Skip to content

Instantly share code, notes, and snippets.

@bitonic
Created June 20, 2025 20:45
Show Gist options
  • Save bitonic/5ebac6b05a67ef95d8627712d84671c2 to your computer and use it in GitHub Desktop.
Save bitonic/5ebac6b05a67ef95d8627712d84671c2 to your computer and use it in GitHub Desktop.
//go:build amd64
#include "textflag.h"
#define LEHMER_LO AX
#define LEHMER_HI DX
#define LEHMER_M R15
#define MASK R8
#define SLOTS R9
#define KEY DI
#define ENTRY R11
#define NEW_ENTRY SI
#define INDEX R12
#define MIN_TIME R14
#define MIN_TIME_INDEX R10
#define SCRATCH_1 R13
#define SLOT X0
#define SLOT_MATCH X1
#define SLOT_TMP X2
#define LEHMER_SEED \
MOVQ KEY, LEHMER_LO \
MOVQ KEY, LEHMER_HI \
ORQ $1, LEHMER_HI \
MOVQ $0xda942042e4dd58b5, LEHMER_M
#define LEHMER_ROUND \
MOVQ LEHMER_HI, SCRATCH_1 \ // x = hi*m
IMULQ LEHMER_M, SCRATCH_1 \
MULQ LEHMER_M \ // hi, lo = lo*m
ADDQ SCRATCH_1, LEHMER_HI \ // hi += x
// Just for testing
TEXT ·lehmerRound(SB),NOSPLIT,$0-32
MOVQ hi+0(FP), LEHMER_HI
MOVQ lo+8(FP), LEHMER_LO
MOVQ $0xda942042e4dd58b5, LEHMER_M
LEHMER_ROUND
MOVQ LEHMER_HI, retHi+16(FP)
MOVQ LEHMER_LO, retLo+24(FP)
RET
#define GET_ROUND(finished) \
MOVQ LEHMER_HI, INDEX \
ANDQ MASK, INDEX \ // idx = (idx & mask) * 16
SHLQ $4, INDEX \
MOVO 0(SLOTS)(INDEX*1), SLOT \ // slot = slots[idx]
MOVQ SLOT, SCRATCH_1 \
CMPQ SCRATCH_1, KEY \
JEQ finished \ // key is equal, we're done
// func slotsGet5(mask uint64, slots unsafe.Pointer, key uint64) (entry unsafe.Pointer)
TEXT ·slotsGet5(SB),NOSPLIT,$0-32
// Arg loading
MOVQ mask+0(FP), MASK
MOVQ slots+8(FP), SLOTS
MOVQ key+16(FP), KEY
// lehmer64 seeding
LEHMER_SEED
// 5 rounds
LEHMER_ROUND
GET_ROUND(get5Finished)
LEHMER_ROUND
GET_ROUND(get5Finished)
// Nothing found
PXOR SLOT, SLOT
get5Finished:
PEXTRQ $1, SLOT, entry+24(FP)
RET
#define PUT_ROUND(break) \
MOVQ LEHMER_HI, INDEX \
ANDQ MASK, INDEX \ // idx = (idx & mask) * 16
SHLQ $4, INDEX \
MOVO 0(SLOTS)(INDEX*1), SLOT \ // slot = slots[idx]
MOVO SLOT, SLOT_TMP \
PCMPEQQ SLOT_MATCH, SLOT_TMP \ // if the entry is nil, or the key is equal, exit
PTEST SLOT_TMP, SLOT_TMP \
JNE break \
PEXTRQ $1, SLOT, ENTRY \ // less or equal below makes it so that the user can use -1 as time and it'll still work
MOVQ (ENTRY), SCRATCH_1 \ // if time =< min_time {
CMPQ SCRATCH_1, MIN_TIME \ // min_time = time
CMOVQLS SCRATCH_1, MIN_TIME \ // min_time_index = index
CMOVQLS INDEX, MIN_TIME_INDEX \ // }
// func slotsPut5(mask uint64, slots unsafe.Pointer, key uint64, entry unsafe.Pointer)
TEXT ·slotsPut5(SB),NOSPLIT,$0-32
MOVQ mask+0(FP), MASK
MOVQ slots+8(FP), SLOTS
MOVQ key+16(FP), KEY
MOVQ entry+24(FP), NEW_ENTRY
// Prepare thing to compare with
PXOR SLOT_MATCH, SLOT_MATCH // slot_match = (key, nil)
MOVQ KEY, SLOT_MATCH
// Prepare min time
MOVQ $0xffffffffffffffff, MIN_TIME
// lehmer64 seeding
LEHMER_SEED
// 5 rounds
LEHMER_ROUND
PUT_ROUND(put5Found)
LEHMER_ROUND
PUT_ROUND(put5Found)
put5Exit:
CMPL runtime·writeBarrier(SB), $0x0
JEQ put5Write
CALL runtime·gcWriteBarrier2(SB)
MOVQ NEW_ENTRY, (R11)
MOVQ 1(SLOTS)(MIN_TIME_INDEX*1), SCRATCH_1
MOVQ SCRATCH_1, 8(R11)
put5Write:
MOVQ KEY, SLOT // slots[min_time_index] = (key, entry)
PINSRQ $1, NEW_ENTRY, SLOT
MOVO SLOT, 0(SLOTS)(MIN_TIME_INDEX*1)
RET
put5Found:
MOVQ INDEX, MIN_TIME_INDEX
JMP put5Exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment