Fixture 41
tokenizer
C · 1 functions · 4 lanes · 4 of 4 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
A byte-level lexer driven by an explicit state variable. Character classification produces a dense switch over a small domain, and the accepted token count is written through an output pointer, so both the jump table and the store-through-parameter must survive.
#include <stdint.h>
/* A byte-level lexer driven by an explicit state variable. Character
* classification produces a dense switch over a small domain, and the accepted
* token count is written through an output pointer, so both the jump table and
* the store-through-parameter must survive. */
#define TOK_MAX 16
#define TOK_STATE_BLANK 0
#define TOK_STATE_WORD 1
#define TOK_STATE_NUMBER 2
static int32_t classify(uint8_t byte) {
if (byte >= (uint8_t)'0' && byte <= (uint8_t)'9') {
return TOK_STATE_NUMBER;
}
if ((byte >= (uint8_t)'a' && byte <= (uint8_t)'z') ||
(byte >= (uint8_t)'A' && byte <= (uint8_t)'Z') ||
byte == (uint8_t)'_') {
return TOK_STATE_WORD;
}
return TOK_STATE_BLANK;
}
__attribute__((noinline)) int32_t
tokenize(const uint8_t *text, int32_t length, int32_t *word_count,
int32_t *number_count) {
int32_t state = TOK_STATE_BLANK;
int32_t words = 0;
int32_t numbers = 0;
int32_t index;
if (text == 0 || word_count == 0 || number_count == 0 || length < 0 ||
length > TOK_MAX) {
return -1;
}
for (index = 0; index < length; ++index) {
int32_t next = classify(text[index]);
if (next != state) {
switch (next) {
case TOK_STATE_WORD:
words += 1;
break;
case TOK_STATE_NUMBER:
numbers += 1;
break;
default:
break;
}
state = next;
}
}
*word_count = words;
*number_count = numbers;
return words + numbers;
} Recovered C
Generated by glaurung decompile --style decbench at b47f6b43.
baseline.json records the result after recompiling the C and calling it beside the
original with seeded inputs.
clang -O0
1/1tokenize pass 62 lines
// glaurung: tokenize @ 0x1100
int32_t tokenize(const uint8_t * arg0, int32_t arg1, int32_t * arg2, int32_t * arg3) {
extern int classify(unsigned char);
int state;
int words;
int numbers;
int index;
int next;
int local_4;
int local_40;
int var3;
// x86-64 prologue: save rbp, frame 64 bytes
state = 0;
words = 0;
numbers = 0;
if ((arg0 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if ((arg2 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if ((arg3 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((long)(arg1) < 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
for (index = 0; (index < arg1); index++) {
var3 = classify((unsigned int)((unsigned char)(arg0[index])));
next = var3;
if (((unsigned int)(next) != (unsigned int)(state))) {
local_40 = next;
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(next)) - 1))) == 0)) {
words = ((unsigned int)(words) + 1);
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_40)) - 2))) == 0)) {
numbers = ((unsigned int)(numbers) + 1);
} else {
}
}
state = next;
}
}
*(int *)((long)arg2) = words;
*(int *)((long)arg3) = numbers;
local_4 = ((unsigned int)(words) + numbers);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} clang -O2
1/1tokenize pass 80 lines
// glaurung: tokenize @ 0x1100
int32_t tokenize(const uint8_t * arg0, int32_t arg1, int32_t * arg2, int32_t * arg3) {
int state;
int words;
int numbers;
int next;
int index;
long ret;
long var18;
int var19;
long var33;
long var34;
long var4;
int var41;
long var5;
long var6;
ret = 0xffffffff;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if ((arg0 == 0)) {
return ret;
}
if ((arg2 == 0)) {
return ret;
}
if ((arg3 == 0)) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
var4 = 0;
var5 = 0;
} else {
var6 = (unsigned long)((unsigned int)(arg1));
state = 0;
words = 0;
numbers = 0;
var18 = 0;
do {
var19 = (unsigned int)((unsigned char)(*(char *)(((long)arg0 + var18))));
next = 2;
if (((unsigned long)(10) <= (unsigned long)((unsigned long)((unsigned char)(((unsigned long)((unsigned int)((var19 - 48))) & 255)))))) {
next = 1;
if (((unsigned long)(26) <= (unsigned long)((unsigned long)((unsigned char)(((unsigned long)((unsigned int)((var19 - 97))) & 255)))))) {
next = (unsigned int)((unsigned char)(((((unsigned long)((unsigned char)((var19 & 255))) == 95) | ((unsigned long)((unsigned long)((unsigned char)(((unsigned long)((unsigned int)((var19 - 65))) & 255)))) < (unsigned long)(26))) & 255)));
}
}
var33 = (unsigned long)((unsigned int)(words));
var34 = (unsigned long)((unsigned int)(numbers));
if (((unsigned int)(next) != (unsigned int)(state))) {
if (((unsigned long)((unsigned int)(next)) == 2)) {
var34 = (unsigned long)((unsigned int)((numbers + 1)));
state = 2;
var33 = (unsigned long)((unsigned int)(words));
} else {
state = 0;
var33 = (unsigned long)((unsigned int)(words));
var34 = (unsigned long)((unsigned int)(numbers));
if (((unsigned long)((unsigned int)(next)) == 1)) {
var33 = (unsigned long)((unsigned int)((words + 1)));
state = 1;
var34 = (unsigned long)((unsigned int)(numbers));
}
}
}
index = (var18 + 1);
words = var33;
numbers = var34;
var18 = (unsigned long)((unsigned int)(index));
var4 = var33;
var5 = var34;
} while ((var6 != index));
}
*(int *)(((long)arg2)) = var4;
*(int *)(((long)arg3)) = var5;
var41 = (var5 + var4);
ret = (unsigned long)((unsigned int)(var41));
// x86-64 epilogue: tear down frame
return (unsigned int)(var41);
} gcc -O0
1/1tokenize pass 53 lines
// glaurung: tokenize @ 0x1145
int32_t tokenize(const uint8_t * arg0, int32_t arg1, int32_t * arg2, int32_t * arg3) {
extern int classify(unsigned char);
int state;
int words;
int numbers;
int index;
int next;
int var7;
// x86-64 prologue: save rbp, frame 64 bytes
state = 0;
words = 0;
numbers = 0;
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((arg2 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((arg3 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((long)(arg1) < 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
for (index = 0; (index < arg1); index++) {
var7 = classify((unsigned long)((unsigned int)((unsigned char)(((unsigned int)((unsigned char)(arg0[index])) & 255)))));
next = var7;
if (((unsigned int)(next) != (unsigned int)(state))) {
if (((unsigned long)((unsigned int)(next)) == 1)) {
words = (words + 1);
} else {
if (((unsigned long)((unsigned int)(next)) == 2)) {
numbers = (numbers + 1);
} else {
}
}
state = next;
}
}
*(int *)((long)arg2) = words;
*(int *)((long)arg3) = numbers;
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(numbers)) + (unsigned long)((unsigned int)(words))));
} gcc -O2
1/1tokenize pass 76 lines
// glaurung: tokenize @ 0x1100
int32_t tokenize(const uint8_t * arg0, int32_t arg1, int32_t * arg2, int32_t * arg3) {
int state;
int index;
int next;
int numbers;
int words;
long var0;
long var11;
long var12;
long var13;
long var14;
long var15;
int var17;
long var19;
long var22;
var0 = (unsigned long)((unsigned int)(arg1));
if ((arg0 == 0)) {
return 0xffffffff;
}
if ((arg2 == 0)) {
return 0xffffffff;
}
if ((arg3 == 0)) {
return 0xffffffff;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0xffffffff;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
*(int *)(((long)arg2)) = var0;
*(int *)(((long)arg3)) = 0;
return 0;
}
var11 = 0x3ffffff43ffffff;
var12 = (long)((((long)arg0 + (unsigned long)((unsigned int)((arg1 - 1)))) + 1));
var13 = 0;
var14 = 0;
var15 = (long)arg0;
state = 0;
do {
var17 = (unsigned int)((unsigned char)(*(char *)((var15))));
if (((unsigned long)(57) < (unsigned long)((unsigned long)((unsigned char)((var17 & 255)))))) {
var19 = (unsigned long)((unsigned int)((var17 - 65)));
if (((unsigned long)(57) < (unsigned long)((unsigned long)((unsigned char)((var19 & 255)))))) {
L_115b: ;
var22 = 0;
} else {
if (((((unsigned long)(var11) >> (var19 & 63)) & 1) == 0)) {
goto L_115b;
} else {
var22 = (unsigned long)((unsigned int)(state));
if (((unsigned long)((unsigned int)(state)) != 1)) {
var14 = (unsigned long)((unsigned int)((var14 + 1)));
var22 = 1;
}
}
}
} else {
if (((unsigned long)(47) < (unsigned long)((unsigned long)((unsigned char)((var17 & 255)))))) {
var22 = (unsigned long)((unsigned int)(state));
if (((unsigned long)((unsigned int)(state)) != 2)) {
var13 = (unsigned long)((unsigned int)((var13 + 1)));
var22 = 2;
}
} else {
goto L_115b;
}
}
var15 = (var15 + 1);
state = var22;
} while ((var15 != var12));
*(int *)(((long)arg2)) = var14;
*(int *)(((long)arg3)) = var13;
return (unsigned int)((var14 + var13));
}