shithub: MicroHs

Download patch

ref: 68fd1e203f625d8aff352fa355603d8d262ac59c
parent: 14f64b3317417795225e2593d5638f367a4c50e2
author: Lennart Augustsson <lennart@augustsson.net>
date: Mon Sep 11 10:10:35 EDT 2023

Improve portability to 32 bits with more typedefs.

--- a/src/runtime/eval.c
+++ b/src/runtime/eval.c
@@ -15,6 +15,20 @@
 #define SANITY   1              /* do some sanity checks */
 #define STACKOVL 1              /* check for stack overflow */
 
+typedef intptr_t value_t;       /* Make value the same size as pointers, since they are in a union */
+#define PRIvalue PRIdPTR
+typedef uintptr_t uvalue_t;     /* Make unsigned value the same size as pointers, since they are in a union */
+#define PRIuvalue PRIuPTR
+typedef uintptr_t heapoffs_t;   /* Heap offsets */
+#define PRIheap PRIuPTR
+typedef uintptr_t tag_t;        /* Room for tag, low order bit indicates AP/not-AP */
+typedef intptr_t stackptr_t;    /* Index into stack */
+/* These types can be changed for 32 bit platforms. */
+typedef uint64_t counter_t;     /* Statistics counter, can be smaller since overflow doesn't matter */
+#define PRIcounter PRIu64
+typedef uint64_t bits_t;        /* One word of bits */
+
+
 #if defined(__MINGW32__)
 #define ffsl __builtin_ffsll
 #endif
@@ -96,8 +110,6 @@
                 T_LAST_TAG,
 };
 
-typedef int64_t value_t;
-
 #if NAIVE
 
 /* Naive node representation with minimal unions */
@@ -128,7 +140,7 @@
 #define HANDLE(p) (p)->u.file
 #define NODE_SIZE sizeof(node)
 #define ALLOC_HEAP(n) do { cells = malloc(n * sizeof(node)); if (!cells) memerr(); memset(cells, 0x55, n * sizeof(node)); } while(0)
-#define LABEL(n) ((uint64_t)((n) - cells))
+#define LABEL(n) ((heapoffs_t)((n) - cells))
 node *cells;                 /* All cells */
 
 #elif UNIONPTR
@@ -136,7 +148,7 @@
 typedef struct node {
   union {
     struct node *uufun;
-    uint64_t uutag;             /* LSB=1 indicates that this is a tag, LSB=0 that this is a T_AP node */
+    tag_t uutag;             /* LSB=1 indicates that this is a tag, LSB=0 that this is a T_AP node */
   } ufun;
   union {
     struct node *uuarg;
@@ -159,7 +171,7 @@
 #define HANDLE(p) (p)->uarg.uufile
 #define NODE_SIZE sizeof(node)
 #define ALLOC_HEAP(n) do { cells = malloc(n * sizeof(node)); memset(cells, 0x55, n * sizeof(node)); } while(0)
-#define LABEL(n) ((uint64_t)((n) - cells))
+#define LABEL(n) ((heapoffs_t)((n) - cells))
 node *cells;                 /* All cells */
 
 #else
@@ -168,14 +180,14 @@
 
 #endif
 
-uint64_t num_reductions = 0;
-uint64_t num_alloc;
-uint64_t num_gc = 0;
+counter_t num_reductions = 0;
+counter_t num_alloc;
+counter_t num_gc = 0;
 double gc_mark_time = 0;
 double run_time = 0;
 
 NODEPTR *stack;
-int64_t stack_ptr = -1;
+stackptr_t stack_ptr = -1;
 #if STACKOVL
 #define PUSH(x) do { if (stack_ptr >= stack_size-1) ERR("stack overflow"); stack[++stack_ptr] = (x); } while(0)
 #else  /* SANITY */
@@ -185,18 +197,18 @@
 #define POP(n) stack_ptr -= (n)
 #define GCCHECK(n) gc_check((n))
 
-uint64_t heap_size = HEAP_CELLS; /* number of heap cells */
-uint64_t heap_start;             /* first location in heap that needs GC */
-int64_t stack_size = STACK_SIZE;
+heapoffs_t heap_size = HEAP_CELLS; /* number of heap cells */
+heapoffs_t heap_start;             /* first location in heap that needs GC */
+stackptr_t stack_size = STACK_SIZE;
 
-uint64_t num_marked;
-uint64_t max_num_marked = 0;
-uint64_t num_free;
+counter_t num_marked;
+counter_t max_num_marked = 0;
+counter_t num_free;
 
-#define BITS_PER_UINT64 64
-uint64_t *free_map;             /* 1 bit per node, 0=free, 1=used */
-uint64_t free_map_nwords;
-uint64_t next_scan_index;
+#define BITS_PER_WORD (sizeof(bits_t) * 8)
+bits_t *free_map;             /* 1 bit per node, 0=free, 1=used */
+heapoffs_t free_map_nwords;
+heapoffs_t next_scan_index;
 
 typedef struct {
   size_t b_size;
@@ -242,30 +254,30 @@
 /* Set FREE bit to 0 */
 static inline void mark_used(NODEPTR n)
 {
-  uint64_t i = LABEL(n);
+  heapoffs_t i = LABEL(n);
   if (i < heap_start)
     return;
 #if SANITY
-  if (i >= free_map_nwords * BITS_PER_UINT64) ERR("mark_used");
+  if (i >= free_map_nwords * BITS_PER_WORD) ERR("mark_used");
 #endif
-  free_map[i / BITS_PER_UINT64] &= ~(1ULL << (i % BITS_PER_UINT64));
+  free_map[i / BITS_PER_WORD] &= ~(1ULL << (i % BITS_PER_WORD));
 }
 
 /* Test if FREE bit is 0 */
 static inline int is_marked_used(NODEPTR n)
 {
-  uint64_t i = LABEL(n);
+  heapoffs_t i = LABEL(n);
   if (i < heap_start)
     return 1;
 #if SANITY
-  if (i >= free_map_nwords * BITS_PER_UINT64) ERR("is_marked_used");;
+  if (i >= free_map_nwords * BITS_PER_WORD) ERR("is_marked_used");;
 #endif
-  return (free_map[i / BITS_PER_UINT64] & (1ULL << (i % BITS_PER_UINT64))) == 0;
+  return (free_map[i / BITS_PER_WORD] & (1ULL << (i % BITS_PER_WORD))) == 0;
 }
 
 static inline void mark_all_free(void)
 {
-  memset(free_map, ~0, free_map_nwords * sizeof(uint64_t));
+  memset(free_map, ~0, free_map_nwords * sizeof(bits_t));
   next_scan_index = heap_start;
 }
 
@@ -290,10 +302,10 @@
     ERR("alloc_node");
 #endif
 
-  uint64_t i = next_scan_index / BITS_PER_UINT64;
+  heapoffs_t i = next_scan_index / BITS_PER_WORD;
   int k;                        /* will contain bit pos + 1 */
   for(;;) {
-    uint64_t word = free_map[i];
+    heapoffs_t word = free_map[i];
     k = ffsl(word);
     if (k)
       break;
@@ -303,7 +315,7 @@
       ERR("alloc_node free_map");
 #endif
   }
-  uint64_t pos = i * BITS_PER_UINT64 + k - 1; /* first free node */
+  heapoffs_t pos = i * BITS_PER_WORD + k - 1; /* first free node */
   NODEPTR n = HEAPREF(pos);
   mark_used(n);
   next_scan_index = pos;
@@ -399,8 +411,8 @@
 init_nodes(void)
 {
   ALLOC_HEAP(heap_size);
-  free_map_nwords = (heap_size + BITS_PER_UINT64 - 1) / BITS_PER_UINT64; /* bytes needed for free map */
-  free_map = malloc(free_map_nwords * sizeof(uint64_t));
+  free_map_nwords = (heap_size + BITS_PER_WORD - 1) / BITS_PER_WORD; /* bytes needed for free map */
+  free_map = malloc(free_map_nwords * sizeof(bits_t));
   if (!free_map)
     memerr();
 
@@ -462,15 +474,10 @@
 #endif
 
   /* Round up heap_start to the next bitword boundary to avoid the permanent nodes. */
-  heap_start = (heap_start + BITS_PER_UINT64 - 1) / BITS_PER_UINT64 * BITS_PER_UINT64;
+  heap_start = (heap_start + BITS_PER_WORD - 1) / BITS_PER_WORD * BITS_PER_WORD;
 
   mark_all_free();
 
-  //for (int64_t i = heap_start; i < heap_size; i++) {
-  //  NODEPTR n = HEAPREF(i);
-  //  MARK(n) = NOTMARKED;
-  //  TAG(n) = FREE;
-  //}
   num_free = heap_size - heap_start;
 }
 
@@ -572,7 +579,7 @@
     fprintf(stderr, "gc mark\n");
   gc_mark_time -= gettime();
   mark_all_free();
-  for (int64_t i = 0; i <= stack_ptr; i++)
+  for (stackptr_t i = 0; i <= stack_ptr; i++)
     mark(&stack[i]);
   t = gettime();
   gc_mark_time += t;
@@ -585,7 +592,7 @@
   if (num_free < heap_size / 50)
     ERR("heap exhausted");
   if (verbose > 1)
-    fprintf(stderr, "gc done, %"PRIu64" free\n", num_free);
+    fprintf(stderr, "gc done, %"PRIcounter" free\n", num_free);
 }
 
 /* Check that there are k nodes available, if not then GC. */
@@ -612,10 +619,10 @@
   }
 }
 
-int64_t
+value_t
 parse_int(BFILE *f)
 {
-  int64_t i = 0;
+  value_t i = 0;
   int c = getb(f);
   for(;;) {
     i = i * 10 + c - '0';
@@ -636,14 +643,14 @@
   return n;
 }
 
-NODEPTR mkInt(int64_t i);
+NODEPTR mkInt(value_t i);
 
 /* Table of labelled nodes for sharing during parsing. */
 struct shared_entry {
-  uint64_t label;
+  heapoffs_t label;
   NODEPTR node;                 /* NIL indicates unused */
 } *shared_table;
-uint64_t shared_table_size;
+heapoffs_t shared_table_size;
 
 /* Look for the label in the table.
  * If it's found, return the node.
@@ -650,7 +657,7 @@
  * If not found, return the first empty entry.
 */
 NODEPTR *
-find_label(uint64_t label)
+find_label(heapoffs_t label)
 {
   int hash = (int)(label % shared_table_size);
   for(int i = hash; ; i++) {
@@ -671,7 +678,7 @@
 {
   NODEPTR r;
   NODEPTR *nodep;
-  int64_t l;
+  heapoffs_t l;
   value_t i;
   value_t neg;
   int c;
@@ -798,7 +805,7 @@
 parse_top(BFILE *f)
 {
   checkversion(f);
-  uint64_t numLabels = parse_int(f);
+  heapoffs_t numLabels = parse_int(f);
   if (!gobble(f, '\n'))
     ERR("size parse");
   gobble(f, '\r');                 /* allow extra CR */
@@ -806,7 +813,7 @@
   shared_table = malloc(shared_table_size * sizeof(struct shared_entry));
   if (!shared_table)
     memerr();
-  for(uint64_t i = 0; i < shared_table_size; i++)
+  for(heapoffs_t i = 0; i < shared_table_size; i++)
     shared_table[i].node = NIL;
   NODEPTR n = parse(f);
   free(shared_table);
@@ -852,7 +859,7 @@
 
 void printrec(FILE *f, NODEPTR n);
 
-uint64_t num_shared;
+counter_t num_shared;
 
 /* Two bits per node: marked, shared
  * 0, 0   -- not visited
@@ -860,22 +867,22 @@
  * 1, 1   -- visited more than once
  * 0, 1   -- printed
  */
-uint64_t *marked_bits;
-uint64_t *shared_bits;
-static inline void set_bit(uint64_t *bits, NODEPTR n)
+bits_t *marked_bits;
+bits_t *shared_bits;
+static inline void set_bit(bits_t *bits, NODEPTR n)
 {
-  uint64_t i = LABEL(n);
-  bits[i / BITS_PER_UINT64] |= (1ULL << (i % BITS_PER_UINT64));
+  heapoffs_t i = LABEL(n);
+  bits[i / BITS_PER_WORD] |= (1ULL << (i % BITS_PER_WORD));
 }
-static inline void clear_bit(uint64_t *bits, NODEPTR n)
+static inline void clear_bit(bits_t *bits, NODEPTR n)
 {
-  uint64_t i = LABEL(n);
-  bits[i / BITS_PER_UINT64] &= ~(1ULL << (i % BITS_PER_UINT64));
+  heapoffs_t i = LABEL(n);
+  bits[i / BITS_PER_WORD] &= ~(1ULL << (i % BITS_PER_WORD));
 }
-static inline uint64_t test_bit(uint64_t *bits, NODEPTR n)
+static inline int test_bit(bits_t *bits, NODEPTR n)
 {
-  uint64_t i = LABEL(n);
-  return bits[i / BITS_PER_UINT64] & (1ULL << (i % BITS_PER_UINT64));
+  heapoffs_t i = LABEL(n);
+  return (bits[i / BITS_PER_WORD] & (1ULL << (i % BITS_PER_WORD))) != 0;
 }
 
 /* Mark all reachable nodes, when a marked node is reached, mark it as shared. */
@@ -919,11 +926,11 @@
     /* The node is shared */
     if (test_bit(marked_bits, n)) {
       /* Not yet printed, so emit a label */
-      fprintf(f, ":%"PRIu64" ", LABEL(n));
+      fprintf(f, ":%"PRIheap" ", LABEL(n));
       clear_bit(marked_bits, n);  /* mark as printed */
     } else {
       /* This node has already been printed, so just use a reference. */
-      fprintf(f, "_%"PRIu64, LABEL(n));
+      fprintf(f, "_%"PRIheap, LABEL(n));
       return;
     }
   }
@@ -937,7 +944,7 @@
     printrec(f, ARG(n));
     fputc(')', f);
     break;
-  case T_INT: fprintf(f, "%"PRIu64, GETVALUE(n)); break;
+  case T_INT: fprintf(f, "%"PRIvalue, GETVALUE(n)); break;
   case T_STR:
     {
       const char *p = STR(n);
@@ -1019,15 +1026,15 @@
 print(FILE *f, NODEPTR n, int header)
 {
   num_shared = 0;
-  marked_bits = calloc(free_map_nwords, sizeof(uint64_t));
+  marked_bits = calloc(free_map_nwords, sizeof(bits_t));
   if (!marked_bits)
     memerr();
-  shared_bits = calloc(free_map_nwords, sizeof(uint64_t));
+  shared_bits = calloc(free_map_nwords, sizeof(bits_t));
   if (!shared_bits)
     memerr();
   find_sharing(n);
   if (header)
-    fprintf(f, "%s%"PRIu64"\n", VERSION, num_shared);
+    fprintf(f, "%s%"PRIcounter"\n", VERSION, num_shared);
   printrec(f, n);
   free(marked_bits);
   free(shared_bits);
@@ -1042,7 +1049,7 @@
 }
 
 NODEPTR
-mkInt(int64_t i)
+mkInt(value_t i)
 {
 #if INTTABLE
   if (LOW_INT <= i && i < HIGH_INT) {
@@ -1202,13 +1209,13 @@
 void
 eval(NODEPTR n)
 {
-  int64_t stk = stack_ptr;
+  stackptr_t stk = stack_ptr;
   NODEPTR x, y, z, w;
   value_t xi, yi;
   value_t r;
   FILE *hdl;
   char *msg;
-  int64_t l;
+  heapoffs_t l;
 
 /* Reset stack pointer and return. */
 #define RET do { stack_ptr = stk; return; } while(0)
@@ -1237,9 +1244,9 @@
 #define SETINT(n,r)   do { SETTAG((n), T_INT); SETVALUE((n), (r)); } while(0)
 #define OPINT2(e)     do { CHECK(2); xi = evalint(ARG(TOP(0))); yi = evalint(ARG(TOP(1))); e; POP(2); n = TOP(-1); } while(0);
 #define ARITHBIN(op)  do { OPINT2(r = xi op yi); SETINT(n, r); RET; } while(0)
-#define ARITHBINU(op) do { OPINT2(r = (int64_t)((uint64_t)xi op (uint64_t)yi)); SETINT(n, r); RET; } while(0)
+#define ARITHBINU(op) do { OPINT2(r = (value_t)((uvalue_t)xi op (uvalue_t)yi)); SETINT(n, r); RET; } while(0)
 #define CMP(op)       do { OPINT2(r = xi op yi); GOIND(r ? comTrue : combFalse); } while(0)
-#define CMPU(op)      do { OPINT2(r = (uint64_t)xi op (uint64_t)yi); GOIND(r ? comTrue : combFalse); } while(0)
+#define CMPU(op)      do { OPINT2(r = (uvalue_t)xi op (uvalue_t)yi); GOIND(r ? comTrue : combFalse); } while(0)
 
   for(;;) {
     num_reductions++;
@@ -1248,7 +1255,7 @@
 #if FASTTAGSCHECK
     if (l < T_IO_BIND) {
       if (l != GETTAG(n)) {
-        printf("%lu %lu\n", l, (uint64_t)(GETTAG(n)));
+        printf("%lu %lu\n", l, (tag_t)(GETTAG(n)));
         ERR("bad tag");
       }
     }
@@ -1339,7 +1346,7 @@
 NODEPTR
 evalio(NODEPTR n)
 {
-  int64_t stk = stack_ptr;
+  stackptr_t stk = stack_ptr;
   NODEPTR f, x;
   int c;
   int hdr;
@@ -1503,10 +1510,10 @@
   }
 }
 
-uint64_t
+heapoffs_t
 memsize(const char *p)
 {
-  uint64_t n = atoi(p);
+  heapoffs_t n = atoi(p);
   while (isdigit(*p))
     p++;
   switch (*p) {
@@ -1577,7 +1584,7 @@
   }
 
   PUSH(prog); gc(); prog = TOP(0); POP(1);
-  uint64_t start_size = num_marked;
+  heapoffs_t start_size = num_marked;
   if (verbose > 2) {
     //pp(stdout, prog);
     print(stdout, prog, 1);
@@ -1595,16 +1602,16 @@
     if (verbose > 1) {
       printf("\nmain returns ");
       pp(stdout, res);
-      printf("node size=%"PRIu64", heap size bytes=%"PRIu64"\n", (uint64_t)NODE_SIZE, heap_size * NODE_SIZE);
+      printf("node size=%"PRIheap", heap size bytes=%"PRIheap"\n", (heapoffs_t)NODE_SIZE, heap_size * NODE_SIZE);
     }
     setlocale(LC_NUMERIC, "");  /* Make %' work on platforms that support it */
-    printf("%"PCOMMA"15"PRIu64" combinator file size\n", (uint64_t)file_size);
-    printf("%"PCOMMA"15"PRIu64" cells at start\n", start_size);
-    printf("%"PCOMMA"15"PRIu64" cells heap size (%"PCOMMA""PRIu64" bytes)\n", heap_size, heap_size * NODE_SIZE);
-    printf("%"PCOMMA"15"PRIu64" cells allocated (%"PCOMMA".1f Mbyte/s)\n", num_alloc, num_alloc * NODE_SIZE / run_time / 1000000);
-    printf("%"PCOMMA"15"PRIu64" GCs\n", num_gc);
-    printf("%"PCOMMA"15"PRIu64" max cells used\n", max_num_marked);
-    printf("%"PCOMMA"15"PRIu64" reductions (%"PCOMMA".1f Mred/s)\n", num_reductions, num_reductions / run_time / 1000000);
+    printf("%"PCOMMA"15"PRIheap" combinator file size\n", (heapoffs_t)file_size);
+    printf("%"PCOMMA"15"PRIheap" cells at start\n", start_size);
+    printf("%"PCOMMA"15"PRIheap" cells heap size (%"PCOMMA""PRIheap" bytes)\n", heap_size, heap_size * NODE_SIZE);
+    printf("%"PCOMMA"15"PRIcounter" cells allocated (%"PCOMMA".1f Mbyte/s)\n", num_alloc, num_alloc * NODE_SIZE / run_time / 1000000);
+    printf("%"PCOMMA"15"PRIcounter" GCs\n", num_gc);
+    printf("%"PCOMMA"15"PRIcounter" max cells used\n", max_num_marked);
+    printf("%"PCOMMA"15"PRIcounter" reductions (%"PCOMMA".1f Mred/s)\n", num_reductions, num_reductions / run_time / 1000000);
     printf("%15.2fs total execution time\n", run_time);
     printf("%15.2fs total gc time\n", gc_mark_time);
 #if GCRED && 0
--