this repo has no description

Support chibicc

This requires moving constants out of globals and into defines. To make
this more flexible---we've changed back and forth a couple of times
now---define the constants in Python and print them into the runtime.

authored by bernsteinbear.com and committed by

Max Bernstein 53f162ee 98e49a20

+45 -38
+38 -5
compiler.py
··· 367 367 main_fn.code.append(f"return {result};") 368 368 369 369 f = io.StringIO() 370 + constants = [ 371 + ("uword", "kKiB", 1024), 372 + ("uword", "kMiB", "kKiB * kKiB"), 373 + ("uword", "kGiB", "kKiB * kKiB * kKiB"), 374 + ("uword", "kPageSize", "4 * kKiB"), 375 + ("uword", "kSmallIntTagBits", 1), 376 + ("uword", "kPrimaryTagBits", 3), 377 + ("uword", "kImmediateTagBits", 5), 378 + ("uword", "kSmallIntTagMask", "(1 << kSmallIntTagBits) - 1"), 379 + ("uword", "kPrimaryTagMask", "(1 << kPrimaryTagBits) - 1"), 380 + ("uword", "kImmediateTagMask", "(1 << kImmediateTagBits) - 1"), 381 + ("uword", "kWordSize", "sizeof(word)"), 382 + ("uword", "kMaxSmallStringLength", "kWordSize - 1"), 383 + ("uword", "kBitsPerByte", 8), 384 + # Up to the five least significant bits are used to tag the object's layout. 385 + # The three low bits make up a primary tag, used to differentiate gc_obj 386 + # from immediate objects. All even tags map to SmallInt, which is 387 + # optimized by checking only the lowest bit for parity. 388 + ("uword", "kSmallIntTag", 0), # 0b****0 389 + ("uword", "kHeapObjectTag", 1), # 0b**001 390 + ("uword", "kEmptyListTag", 5), # 0b00101 391 + ("uword", "kHoleTag", 7), # 0b00111 392 + ("uword", "kSmallStringTag", 13), # 0b01101 393 + ("uword", "kBitsPerPointer", "kBitsPerByte * kWordSize"), 394 + ("word", "kSmallIntBits", "kBitsPerPointer - kSmallIntTagBits"), 395 + ("word", "kSmallIntMinValue", "-(((word)1) << (kSmallIntBits - 1))"), 396 + ("word", "kSmallIntMaxValue", "(((word)1) << (kSmallIntBits - 1)) - 1"), 397 + ] 398 + for type_, name, value in constants: 399 + print(f"#define {name} ({type_})({value})", file=f) 370 400 # The runtime is in the same directory as this file 371 401 dirname = os.path.dirname(__file__) 372 402 with open(os.path.join(dirname, "runtime.c"), "r") as runtime: 373 403 print(runtime.read(), file=f) 374 404 print("#define OBJECT_HANDLE(name, exp) GC_HANDLE(struct object*, name, exp)", file=f) 375 - # Declare all functions 376 - print("const char* record_keys[] = {", file=f) 377 - for key in compiler.record_keys: 378 - print(f'"{key}",', file=f) 379 - print("};", file=f) 380 405 if compiler.record_keys: 406 + print("const char* record_keys[] = {", file=f) 407 + for key in compiler.record_keys: 408 + print(f'"{key}",', file=f) 409 + print("};", file=f) 381 410 print("enum {", file=f) 382 411 for key, idx in compiler.record_keys.items(): 383 412 print(f"Record_{key} = {idx},", file=f) 384 413 print("};", file=f) 414 + else: 415 + # Pacify the C compiler 416 + print("const char* record_keys[] = { NULL };", file=f) 385 417 if compiler.variant_tags: 386 418 print("const char* variant_names[] = {", file=f) 387 419 for key in compiler.variant_tags: ··· 394 426 else: 395 427 # Pacify the C compiler 396 428 print("const char* variant_names[] = { NULL };", file=f) 429 + # Declare all functions 397 430 for function in compiler.functions: 398 431 print(function.decl() + ";", file=f) 399 432 for function in compiler.functions:
+1
compiler_tests.py
··· 69 69 def test_match_int(self) -> None: 70 70 self.assertEqual(self._run("f 3 . f = | 1 -> 2 | 3 -> 4"), "4\n") 71 71 72 + @unittest.skipIf("tcc" in os.environ.get("CC", ""), "TODO(max): Fix; TCC emits crashy code") 72 73 def test_match_list(self) -> None: 73 74 self.assertEqual(self._run("f [4, 5] . f = | [1, 2] -> 3 | [4, 5] -> 6"), "6\n") 74 75
+6 -33
runtime.c
··· 24 24 uintptr_t payload[0]; 25 25 }; 26 26 27 - const uword kKiB = 1024; 28 - const uword kMiB = kKiB * kKiB; 29 - const uword kGiB = kKiB * kKiB * kKiB; 30 - 31 - const uword kPageSize = 4 * kKiB; 32 - 33 27 // The low bit of the pointer is 1 if it's a heap object and 0 if it's an 34 28 // immediate integer 35 - struct object {}; 36 - 37 - // Up to the five least significant bits are used to tag the object's layout. 38 - // The three low bits make up a primary tag, used to differentiate gc_obj 39 - // from immediate objects. All even tags map to SmallInt, which is 40 - // optimized by checking only the lowest bit for parity. 41 - static const uword kSmallIntTagBits = 1; 42 - static const uword kPrimaryTagBits = 3; 43 - static const uword kImmediateTagBits = 5; 44 - static const uword kSmallIntTagMask = (1 << kSmallIntTagBits) - 1; 45 - static const uword kPrimaryTagMask = (1 << kPrimaryTagBits) - 1; 46 - static const uword kImmediateTagMask = (1 << kImmediateTagBits) - 1; 47 - 48 - static const uword kWordSize = sizeof(word); 49 - static const uword kMaxSmallStringLength = kWordSize - 1; 50 - static const uword kBitsPerByte = 8; 51 - 52 - static const uword kSmallIntTag = 0; // 0b****0 53 - static const uword kHeapObjectTag = 1; // 0b**001 54 - static const uword kEmptyListTag = 5; // 0b00101 55 - static const uword kHoleTag = 7; // 0b00111 56 - static const uword kSmallStringTag = 13; // 0b01101 29 + struct object; 57 30 58 31 bool is_small_int(struct object* obj) { 59 32 return (((uword)obj) & kSmallIntTagMask) == kSmallIntTag; ··· 229 202 #endif 230 203 } 231 204 205 + #if defined(__builtin_expect) 232 206 #define LIKELY(x) __builtin_expect(!!(x), 1) 233 207 #define UNLIKELY(x) __builtin_expect(!!(x), 0) 208 + #else 209 + #define LIKELY(x) x 210 + #define UNLIKELY(x) x 211 + #endif 234 212 #define ALLOCATOR __attribute__((__malloc__)) 235 213 236 214 static NEVER_INLINE ALLOCATOR struct object* allocate_slow_path( ··· 375 353 } 376 354 return heap_object_size(obj); 377 355 } 378 - 379 - static const uword kBitsPerPointer = kBitsPerByte * kWordSize; 380 - static const word kSmallIntBits = kBitsPerPointer - kSmallIntTagBits; 381 - static const word kSmallIntMinValue = -(((word)1) << (kSmallIntBits - 1)); 382 - static const word kSmallIntMaxValue = (((word)1) << (kSmallIntBits - 1)) - 1; 383 356 384 357 bool smallint_is_valid(word value) { 385 358 return (value >= kSmallIntMinValue) && (value <= kSmallIntMaxValue);