Skip to content

Instantly share code, notes, and snippets.

@RealNeGate
Last active September 2, 2023 09:21
Show Gist options
  • Save RealNeGate/f15253c9da8f0661a00b84e8be83c57e to your computer and use it in GitHub Desktop.
Save RealNeGate/f15253c9da8f0661a00b84e8be83c57e to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <x86intrin.h>
const char keywords[][16] = {
"alignof",
"auto",
"break",
"case",
"char",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extern",
"float",
"for",
"goto",
"if",
"inline",
"int",
"long",
"register",
"restrict",
"return",
"short",
"signed",
"sizeof",
"static",
"struct",
"switch",
"typedef",
"union",
"unsigned",
"void",
"volatile",
"while",
"_Alignas",
"_Atomic",
"_Bool",
"_Complex",
"_Generic",
"_Imaginary",
"_Noreturn",
"_Static_assert",
"_Thread_local"
};
typedef enum Keyword {
KW_alignof,
KW_auto,
KW_break,
KW_case,
KW_char,
KW_const,
KW_continue,
KW_default,
KW_do,
KW_double,
KW_else,
KW_enum,
KW_extern,
KW_float,
KW_for,
KW_goto,
KW_if,
KW_inline,
KW_int,
KW_long,
KW_register,
KW_restrict,
KW_return,
KW_short,
KW_signed,
KW_sizeof,
KW_static,
KW_struct,
KW_switch,
KW_typedef,
KW_union,
KW_unsigned,
KW_void,
KW_volatile,
KW_while,
KW_Alignas,
KW_Atomic,
KW_Bool,
KW_Complex,
KW_Generic,
KW_Imaginary,
KW_Noreturn,
KW_Static_assert,
KW_Thread_local,
KW_NONE
} Keyword;
static uint32_t fnv1a_len(const void* data, size_t len) {
const unsigned char* ptr = (const unsigned char*)data;
uint32_t hash = 0x811C9DC5;
size_t i = len;
while (i--) {
hash = ((*ptr++) ^ hash) * 0x01000193;
}
return hash;
}
Keyword get_token_as_keyword(const char* restrict str, size_t len) {
// BINARY SEARCH ARRAYS
const static uint32_t keys[64] = {
0x0C547726,0x0DC628CE,0x10D4792F,0x18338D5E,0x1D0E8DBE,0x221EDE24,0x2D6871C0,0x39386E06,
0x3974EFA7,0x48B5725F,0x505E61EF,0x621CD814,0x664FD1D4,0x6AA4A81B,0x6EE13AFD,0x816CB000,
0x85EE37BF,0x9087DDB7,0x923FA396,0x92C2BE20,0x933B5BDE,0x93E05F71,0x94E1036D,0x95E97E5E,
0x9B2538B1,0xA0EB0F08,0xA6C45D85,0xA84C031D,0xACF38390,0xAE76E4A2,0xB1727E44,0xB5712015,
0xBA226BD5,0xBDBF5BF0,0xC2CB5034,0xC2ECDF53,0xC919731F,0xC9648178,0xD290C23B,0xDBDED6F4,
0xE3F06707,0xF5A30FE6,0xFDD57AE5,0xFF2BDAB7,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
};
const static uint8_t values[64] = {
31,34,39,38,43,29,20,16,41,32,42,8,5,35,25,11,22,12,1,27,7,28,33,18,3,9,13,4,14,37,6,24,23,10,17,19,0,2,26,30,40,15,21,36,
};
// HASH STRING
uint32_t n = fnv1a_len(str, len);
// BRANCHLESS BINARY SEARCH
size_t i = 0;
i += (keys[i + 32] <= n) * 32;
i += (keys[i + 16] <= n) * 16;
i += (keys[i + 8] <= n) * 8;
i += (keys[i + 4] <= n) * 4;
i += (keys[i + 2] <= n) * 2;
i += (keys[i + 1] <= n) * 1;
size_t v = values[i];
// VERIFY
__m128i kw128 = _mm_loadu_si128((__m128i*) &keywords[v]);
__m128i str128 = _mm_loadu_si128((__m128i*) str);
// NOTE(NeGate): Fancy x86 strcmp crap :)
int result = _mm_cmpestri(kw128, len,
str128, len,
_SIDD_UBYTE_OPS |
_SIDD_CMP_EQUAL_ANY |
_SIDD_NEGATIVE_POLARITY |
_SIDD_BIT_MASK);
return result ? KW_NONE : v;
}
get_token_as_keyword: # @get_token_as_keyword
mov rax, rsi
test rsi, rsi
je .LBB0_1
lea rcx, [rax - 1]
mov r8d, eax
and r8d, 3
cmp rcx, 3
jae .LBB0_4
mov r9d, -2128831035
mov rsi, rdi
jmp .LBB0_6
.LBB0_1:
mov r9d, -2128831035
xor edx, edx
jmp .LBB0_10
.LBB0_4:
mov rdx, rax
and rdx, -4
mov r9d, -2128831035
mov rsi, rdi
.LBB0_5: # =>This Inner Loop Header: Depth=1
movzx ecx, byte ptr [rsi]
xor ecx, r9d
imul r9d, ecx, 16777619
movzx ecx, byte ptr [rsi + 1]
xor ecx, r9d
imul r9d, ecx, 16777619
movzx ecx, byte ptr [rsi + 2]
xor ecx, r9d
imul r9d, ecx, 16777619
movzx ecx, byte ptr [rsi + 3]
add rsi, 4
xor ecx, r9d
imul r9d, ecx, 16777619
add rdx, -4
jne .LBB0_5
.LBB0_6:
test r8, r8
je .LBB0_9
xor edx, edx
.LBB0_8: # =>This Inner Loop Header: Depth=1
movzx ecx, byte ptr [rsi + rdx]
xor ecx, r9d
imul r9d, ecx, 16777619
inc rdx
cmp r8, rdx
jne .LBB0_8
.LBB0_9:
xor edx, edx
cmp r9d, -1172149291
setae dl
shl rdx, 5
.LBB0_10:
lea rcx, [4*rdx]
or rcx, 64
xor esi, esi
cmp dword ptr [rcx + get_token_as_keyword.keys], r9d
setbe sil
shl rsi, 4
or rsi, rdx
lea rcx, [4*rsi]
or rcx, 32
xor edx, edx
cmp dword ptr [rcx + get_token_as_keyword.keys], r9d
setbe dl
shl rdx, 3
or rdx, rsi
lea rcx, [4*rdx]
or rcx, 16
xor esi, esi
cmp dword ptr [rcx + get_token_as_keyword.keys], r9d
setbe sil
shl rsi, 2
or rsi, rdx
lea rcx, [4*rsi]
or rcx, 8
xor edx, edx
cmp dword ptr [rcx + get_token_as_keyword.keys], r9d
setbe dl
add rdx, rdx
or rdx, rsi
lea rcx, [4*rdx]
or rcx, 4
xor esi, esi
cmp dword ptr [rcx + get_token_as_keyword.keys], r9d
setbe sil
or rsi, rdx
movzx esi, byte ptr [rsi + get_token_as_keyword.values]
mov rcx, rsi
shl rcx, 4
movdqa xmm0, xmmword ptr [rcx + keywords]
mov edx, eax
pcmpestri xmm0, xmmword ptr [rdi], 16
test ecx, ecx
mov eax, 44
cmove eax, esi
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment