Skip to content

Instantly share code, notes, and snippets.

@bynect
Created February 15, 2025 01:31
Show Gist options
  • Save bynect/295422de677d7bb38e93d07ce8f5d4a1 to your computer and use it in GitHub Desktop.
Save bynect/295422de677d7bb38e93d07ce8f5d4a1 to your computer and use it in GitHub Desktop.
topbit.c
#include <stdint.h>
#include <string.h>
//static_assert(sizeof(void *) == sizeof(uintptr_t), "Funky libc not allowed");
//static_assert(sizeof(void *) == sizeof(uint64_t), "Only works on amd64");
// We want to represent different values
//
// we have 64-48 => 16 bits at our disposal
// or in the case of 57 addressing
// 64-58 => 6 bits
// we leave the most significant bit
// and use 5 bit (62 to 57)
// Keeping the zeroes configuration for object/pointers
// we can use up to 63 possible tags!
//
// | x | 1 | 1 | 1 | 1 | 1 |
typedef uintptr_t value_t;
typedef enum {
TAG_OBJECT = 0,
TAG_STRING = 1,
TAG_INTEGER = 2,
TAG_FLOAT = 3,
TAG_TINYSTR = 4,
TAG_INVALID = 0x3f,
} value_tag_t;
typedef struct {
// Needs to be zero terminated!
char data[8];
} tinystr_t;
#define TAG_SHIFT (63 - 6)
#define TAG_MASK ((uintptr_t)TAG_INVALID << TAG_SHIFT)
#define VALUE_SIGN_BIT ((uintptr_t)1 << (TAG_SHIFT - 1))
#define VALUE_MS_BIT ((uintptr_t)1 << 63)
#define VALUE_GET_TAG(value) (value_tag_t)(((uintptr_t)(value) & TAG_MASK) >> TAG_SHIFT)
#define VALUE_SET_TAG(value, tag) (value_t)((uintptr_t)(value) | (uintptr_t)tag << TAG_SHIFT)
#define VALUE_UNTAG(value) (value_t)((uintptr_t)(value) & ~TAG_MASK)
#define VALUE_GET_OBJECT(value) (void *)(VALUE_UNTAG(value))
#define VALUE_GET_STRING(value) (char *)(VALUE_UNTAG(value))
#define VALUE_TAG_OBJECT(value) (value_t)(value);
#define VALUE_TAG_STRING(value) (VALUE_SET_TAG(value, TAG_STRING))
value_t value_tag_integer(intptr_t num) {
// We are effectively truncating this 64 bit integer to 58 bit, and the
// sign bit must be handled accordingly!
uintptr_t val = *(uintptr_t *)&num;
val &= ~((uintptr_t)0x7f << (TAG_SHIFT - 1));
// Move the sign bit
if (num < 0)
val |= VALUE_SIGN_BIT;
return VALUE_SET_TAG(val, TAG_INTEGER);
}
intptr_t value_untag_integer(value_t val) {
uintptr_t num = (uintptr_t)val & ~((uintptr_t)0x7f << (TAG_SHIFT - 1));
// If the number is negative, pad with 1's to adjust the two's complement
if ((uintptr_t)val & VALUE_SIGN_BIT)
num |= (uintptr_t)0x7f << (TAG_SHIFT - 1);
return *(intptr_t *)&num;
}
value_t value_tag_float(float num) {
union {
value_t val;
float num;
} pun;
pun.num = num;
return VALUE_SET_TAG(pun.val, TAG_FLOAT);
}
float value_untag_float(value_t val) {
union {
value_t val;
float num;
} pun;
pun.val = val;
return pun.num;
}
value_t value_tag_tinystr(tinystr_t str) {
uintptr_t val = 0;
uint8_t *ptr = (uint8_t *)&val;
memcpy(ptr + 1, str.data, 7);
return VALUE_SET_TAG(val, TAG_TINYSTR);
}
tinystr_t value_untag_tinystr(value_t val) {
tinystr_t str = { 0 };
uint8_t *ptr = (uint8_t *)&val;
memcpy(str.data, ptr + 1, 7);
return str;
}
#include <stdio.h>
void print_value(value_t val) {
switch (VALUE_GET_TAG(val)) {
case TAG_OBJECT:
printf("Object %p\n", VALUE_GET_OBJECT(val));
break;
case TAG_STRING:
printf("String %s\n", VALUE_GET_STRING(val));
break;
case TAG_INTEGER:
printf("Integer %ld\n", value_untag_integer(val));
break;
case TAG_FLOAT:
printf("Float %f\n", value_untag_float(val));
break;
case TAG_TINYSTR:
printf("Tinystr %s\n", value_untag_tinystr(val).data);
break;
default:
printf("Invalid value\n");
}
}
#define VALUE_INT_MAX (((uintptr_t)1 << (TAG_SHIFT - 1)) - 1)
#define VALUE_INT_MIN -((uintptr_t)1 << (TAG_SHIFT - 1))
int main() {
tinystr_t s = { "Hello" };
tinystr_t s2 = { "" };
value_t vs[] = {
value_tag_integer(100169),
value_tag_float(20.49),
value_tag_integer(424242),
VALUE_TAG_STRING("long string works!"),
value_tag_tinystr(s),
value_tag_tinystr(s2),
value_tag_integer(-1000),
value_tag_float(-1.29930e3),
value_tag_integer(VALUE_INT_MIN),
value_tag_integer(VALUE_INT_MAX),
};
printf("MAX %ld\nMIN %ld\n", VALUE_INT_MAX, VALUE_INT_MIN);
for (size_t i = 0; i < sizeof(vs)/sizeof(*vs); i++)
print_value(vs[i]);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment