Skip to content

Instantly share code, notes, and snippets.

@umgefahren
Created April 28, 2022 17:55
Show Gist options
  • Save umgefahren/fb071e706d1d73c5eb2b0c0f400a727c to your computer and use it in GitHub Desktop.
Save umgefahren/fb071e706d1d73c5eb2b0c0f400a727c to your computer and use it in GitHub Desktop.
Implementation of fast enum in C
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#define ONE 1
// #define PRINT_OUPUT
const uint8_t uint8_one = ONE;
const uint16_t uint16_one = ONE;
const uint32_t uint32_one = ONE;
const uint64_t uint64_one = ONE;
union NumVariantUnion {
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
};
enum NumVariantEnum { u8, u16, u32, u64 };
struct NumVariant {
union NumVariantUnion data;
enum NumVariantEnum type;
};
enum NumInVariantEnum { u8In, u16In, u32In, u64In };
void calcVariant(struct NumVariant input);
void constructVariant(enum NumInVariantEnum input) {
struct NumVariant ret;
switch (input) {
case u8In:
ret.type = u8;
ret.data.u8 = UINT8_MAX;
break;
case u16In:
ret.type = u16;
ret.data.u16 = UINT16_MAX;
break;
case u32In:
ret.type = u32;
ret.data.u32 = UINT32_MAX;
break;
case u64In:
ret.type = u64;
ret.data.u64 = UINT64_MAX;
break;
}
calcVariant(ret);
}
inline void calcVariant(struct NumVariant input) {
switch (input.type) {
case u8: {
uint8_t structData = input.data.u8;
structData -= uint8_one;
#ifdef PRINT_OUPUT
printf("%i\n", structData);
#endif
break;
}
case u16: {
uint16_t structData = input.data.u16;
structData -= uint16_one;
#ifdef PRINT_OUPUT
printf("%i\n", structData);
#endif
break;
}
case u32: {
uint32_t structData = input.data.u32;
structData -= uint32_one;
#ifdef PRINT_OUPUT
printf("%u\n", structData);
#endif
break;
}
case u64: {
uint64_t structData = input.data.u64;
structData -= uint64_one;
#ifdef PRINT_OUPUT
printf("%llu\n", structData);
#endif
break;
}
}
}
void constructVariantASM(enum NumInVariantEnum input) {
uint8_t uint8_variant_val;
uint16_t uint16_variant_val;
uint32_t uint32_variant_val;
uint64_t uint64_variant_val;
struct NumVariant ret;
switch (input) {
case u8In: {
uint8_variant_val = UINT8_MAX;
goto uint8_variant;
ret.type = u8;
ret.data.u8 = UINT8_MAX;
break;
}
case u16In: {
uint16_variant_val = UINT16_MAX;
goto uint16_variant;
ret.type = u16;
ret.data.u16 = UINT16_MAX;
break;
}
case u32In: {
uint32_variant_val = UINT32_MAX;
goto uint32_variant;
ret.type = u32;
ret.data.u32 = UINT32_MAX;
break;
}
case u64In: {
uint64_variant_val = UINT64_MAX;
goto uint64_variant;
ret.type = u64;
ret.data.u64 = UINT64_MAX;
}
}
switch (ret.type) {
case u8: {
uint8_t structData = ret.data.u8;
uint8_variant:
structData = uint8_variant_val;
structData -= uint8_one;
#ifdef PRINT_OUPUT
printf("%i\n", structData);
#endif
break;
}
case u16: {
uint16_t structData = ret.data.u16;
uint16_variant:
structData = uint16_variant_val;
structData -= uint16_one;
#ifdef PRINT_OUPUT
printf("%i\n", structData);
#endif
break;
}
case u32: {
uint32_t structData = ret.data.u32;
uint32_variant:
structData = uint32_variant_val;
structData -= uint32_one;
#ifdef PRINT_OUPUT
printf("%u\n", structData);
#endif
break;
}
case u64: {
uint64_t structData = ret.data.u64;
uint64_variant:
structData = uint64_variant_val;
structData -= uint64_one;
#ifdef PRINT_OUPUT
printf("%llu\n", structData);
#endif
break;
}
}
}
#ifdef PRINT_OUPUT
const uint64_t ITERATIONS = 1;
#else
const uint64_t ITERATIONS = 1E9;
#endif
void DoNotOptimize(enum NumInVariantEnum input) {
asm volatile ("" : : "r,m"(input) : "memory");
}
void benchFunction() {
#pragma nounroll
for (uint64_t i = 0; i < ITERATIONS; i++) {
volatile enum NumInVariantEnum inVariant = u8In;
DoNotOptimize(inVariant);
constructVariant(inVariant);
inVariant = u16In;
DoNotOptimize(inVariant);
constructVariant(inVariant);
inVariant = u32In;
DoNotOptimize(inVariant);
constructVariant(inVariant);
inVariant = u64In;
DoNotOptimize(inVariant);
constructVariant(inVariant);
}
}
void benchASM() {
#pragma nounroll
for (uint64_t i = 0; i < ITERATIONS; i++) {
volatile enum NumInVariantEnum inVariant = u8In;
DoNotOptimize(inVariant);
constructVariantASM(inVariant);
inVariant = u16In;
DoNotOptimize(inVariant);
constructVariantASM(inVariant);
inVariant = u32In;
DoNotOptimize(inVariant);
constructVariantASM(inVariant);
inVariant = u64In;
DoNotOptimize(inVariant);
constructVariantASM(inVariant);
}
}
int main() {
clock_t start, end, time;
start = clock();
benchFunction();
end = clock();
time = end - start;
double time_taken = ((double)time) / CLOCKS_PER_SEC;
printf("Pure took %f seconds\n", time_taken);
start = clock();
benchASM();
end = clock();
time = end - start;
time_taken = ((double)time) / CLOCKS_PER_SEC;
printf("ASM took %f seconds\n", time_taken);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment