src/host/buildvm_fold.c - luajit-2.0-src

Global variables defined

Functions defined

Source code

  1. /*
  2. ** LuaJIT VM builder: IR folding hash table generator.
  3. ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
  4. */

  5. #include "buildvm.h"
  6. #include "lj_obj.h"
  7. #include "lj_ir.h"

  8. /* Context for the folding hash table generator. */
  9. static int lineno;
  10. static int funcidx;
  11. static uint32_t foldkeys[BUILD_MAX_FOLD];
  12. static uint32_t nkeys;

  13. /* Try to fill the hash table with keys using the hash parameters. */
  14. static int tryhash(uint32_t *htab, uint32_t sz, uint32_t r, int dorol)
  15. {
  16.   uint32_t i;
  17.   if (dorol && ((r & 31) == 0 || (r>>5) == 0))
  18.     return 0/* Avoid zero rotates. */
  19.   memset(htab, 0xff, (sz+1)*sizeof(uint32_t));
  20.   for (i = 0; i < nkeys; i++) {
  21.     uint32_t key = foldkeys[i];
  22.     uint32_t k = key & 0xffffff;
  23.     uint32_t h = (dorol ? lj_rol(lj_rol(k, r>>5) - k, r&31) :
  24.                           (((k << (r>>5)) - k) << (r&31))) % sz;
  25.     if (htab[h] != 0xffffffff) {  /* Collision on primary slot. */
  26.       if (htab[h+1] != 0xffffffff) {  /* Collision on secondary slot. */
  27.         /* Try to move the colliding key, if possible. */
  28.         if (h < sz-1 && htab[h+2] == 0xffffffff) {
  29.           uint32_t k2 = htab[h+1] & 0xffffff;
  30.           uint32_t h2 = (dorol ? lj_rol(lj_rol(k2, r>>5) - k2, r&31) :
  31.                                  (((k2 << (r>>5)) - k2) << (r&31))) % sz;
  32.           if (h2 != h+1) return 0/* Cannot resolve collision. */
  33.           htab[h+2] = htab[h+1];  /* Move colliding key to secondary slot. */
  34.         } else {
  35.           return 0/* Collision. */
  36.         }
  37.       }
  38.       htab[h+1] = key;
  39.     } else {
  40.       htab[h] = key;
  41.     }
  42.   }
  43.   return 1/* Success, all keys could be stored. */
  44. }

  45. /* Print the generated hash table. */
  46. static void printhash(BuildCtx *ctx, uint32_t *htab, uint32_t sz)
  47. {
  48.   uint32_t i;
  49.   fprintf(ctx->fp, "static const uint32_t fold_hash[%d] = {\n0x%08x",
  50.           sz+1, htab[0]);
  51.   for (i = 1; i < sz+1; i++)
  52.     fprintf(ctx->fp, ",\n0x%08x", htab[i]);
  53.   fprintf(ctx->fp, "\n};\n\n");
  54. }

  55. /* Exhaustive search for the shortest semi-perfect hash table. */
  56. static void makehash(BuildCtx *ctx)
  57. {
  58.   uint32_t htab[BUILD_MAX_FOLD*2+1];
  59.   uint32_t sz, r;
  60.   /* Search for the smallest hash table with an odd size. */
  61.   for (sz = (nkeys|1); sz < BUILD_MAX_FOLD*2; sz += 2) {
  62.     /* First try all shift hash combinations. */
  63.     for (r = 0; r < 32*32; r++) {
  64.       if (tryhash(htab, sz, r, 0)) {
  65.         printhash(ctx, htab, sz);
  66.         fprintf(ctx->fp,
  67.                 "#define fold_hashkey(k)\t(((((k)<<%u)-(k))<<%u)%%%u)\n\n",
  68.                 r>>5, r&31, sz);
  69.         return;
  70.       }
  71.     }
  72.     /* Then try all rotate hash combinations. */
  73.     for (r = 0; r < 32*32; r++) {
  74.       if (tryhash(htab, sz, r, 1)) {
  75.         printhash(ctx, htab, sz);
  76.         fprintf(ctx->fp,
  77.           "#define fold_hashkey(k)\t(lj_rol(lj_rol((k),%u)-(k),%u)%%%u)\n\n",
  78.                 r>>5, r&31, sz);
  79.         return;
  80.       }
  81.     }
  82.   }
  83.   fprintf(stderr, "Error: search for perfect hash failed\n");
  84.   exit(1);
  85. }

  86. /* Parse one token of a fold rule. */
  87. static uint32_t nexttoken(char **pp, int allowlit, int allowany)
  88. {
  89.   char *p = *pp;
  90.   if (p) {
  91.     uint32_t i;
  92.     char *q = strchr(p, ' ');
  93.     if (q) *q++ = '\0';
  94.     *pp = q;
  95.     if (allowlit && !strncmp(p, "IRFPM_", 6)) {
  96.       for (i = 0; irfpm_names[i]; i++)
  97.         if (!strcmp(irfpm_names[i], p+6))
  98.           return i;
  99.     } else if (allowlit && !strncmp(p, "IRFL_", 5)) {
  100.       for (i = 0; irfield_names[i]; i++)
  101.         if (!strcmp(irfield_names[i], p+5))
  102.           return i;
  103.     } else if (allowlit && !strncmp(p, "IRCALL_", 7)) {
  104.       for (i = 0; ircall_names[i]; i++)
  105.         if (!strcmp(ircall_names[i], p+7))
  106.           return i;
  107.     } else if (allowlit && !strncmp(p, "IRCONV_", 7)) {
  108.       for (i = 0; irt_names[i]; i++) {
  109.         const char *r = strchr(p+7, '_');
  110.         if (r && !strncmp(irt_names[i], p+7, r-(p+7))) {
  111.           uint32_t j;
  112.           for (j = 0; irt_names[j]; j++)
  113.             if (!strcmp(irt_names[j], r+1))
  114.               return (i << 5) + j;
  115.         }
  116.       }
  117.     } else if (allowlit && *p >= '0' && *p <= '9') {
  118.       for (i = 0; *p >= '0' && *p <= '9'; p++)
  119.         i = i*10 + (*p - '0');
  120.       if (*p == '\0')
  121.         return i;
  122.     } else if (allowany && !strcmp("any", p)) {
  123.       return allowany;
  124.     } else {
  125.       for (i = 0; ir_names[i]; i++)
  126.         if (!strcmp(ir_names[i], p))
  127.           return i;
  128.     }
  129.     fprintf(stderr, "Error: bad fold definition token \"%s\" at line %d\n", p, lineno);
  130.     exit(1);
  131.   }
  132.   return 0;
  133. }

  134. /* Parse a fold rule. */
  135. static void foldrule(char *p)
  136. {
  137.   uint32_t op = nexttoken(&p, 0, 0);
  138.   uint32_t left = nexttoken(&p, 0, 0x7f);
  139.   uint32_t right = nexttoken(&p, 1, 0x3ff);
  140.   uint32_t key = (funcidx << 24) | (op << 17) | (left << 10) | right;
  141.   uint32_t i;
  142.   if (nkeys >= BUILD_MAX_FOLD) {
  143.     fprintf(stderr, "Error: too many fold rules, increase BUILD_MAX_FOLD.\n");
  144.     exit(1);
  145.   }
  146.   /* Simple insertion sort to detect duplicates. */
  147.   for (i = nkeys; i > 0; i--) {
  148.     if ((foldkeys[i-1]&0xffffff) < (key & 0xffffff))
  149.       break;
  150.     if ((foldkeys[i-1]&0xffffff) == (key & 0xffffff)) {
  151.       fprintf(stderr, "Error: duplicate fold definition at line %d\n", lineno);
  152.       exit(1);
  153.     }
  154.     foldkeys[i] = foldkeys[i-1];
  155.   }
  156.   foldkeys[i] = key;
  157.   nkeys++;
  158. }

  159. /* Emit C source code for IR folding hash table. */
  160. void emit_fold(BuildCtx *ctx)
  161. {
  162.   char buf[256];  /* We don't care about analyzing lines longer than that. */
  163.   const char *fname = ctx->args[0];
  164.   FILE *fp;

  165.   if (fname == NULL) {
  166.     fprintf(stderr, "Error: missing input filename\n");
  167.     exit(1);
  168.   }

  169.   if (fname[0] == '-' && fname[1] == '\0') {
  170.     fp = stdin;
  171.   } else {
  172.     fp = fopen(fname, "r");
  173.     if (!fp) {
  174.       fprintf(stderr, "Error: cannot open input file '%s': %s\n",
  175.               fname, strerror(errno));
  176.       exit(1);
  177.     }
  178.   }

  179.   fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
  180.   fprintf(ctx->fp, "static const FoldFunc fold_func[] = {\n");

  181.   lineno = 0;
  182.   funcidx = 0;
  183.   nkeys = 0;
  184.   while (fgets(buf, sizeof(buf), fp) != NULL) {
  185.     lineno++;
  186.     /* The prefix must be at the start of a line, otherwise it's ignored. */
  187.     if (!strncmp(buf, FOLDDEF_PREFIX, sizeof(FOLDDEF_PREFIX)-1)) {
  188.       char *p = buf+sizeof(FOLDDEF_PREFIX)-1;
  189.       char *q = strchr(p, ')');
  190.       if (p[0] == '(' && q) {
  191.         p++;
  192.         *q = '\0';
  193.         foldrule(p);
  194.       } else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) {
  195.         p += 2;
  196.         *q = '\0';
  197.         if (funcidx)
  198.           fprintf(ctx->fp, ",\n");
  199.         if (p[-2] == 'X')
  200.           fprintf(ctx->fp, %s", p);
  201.         else
  202.           fprintf(ctx->fp, "  fold_%s", p);
  203.         funcidx++;
  204.       } else {
  205.         buf[strlen(buf)-1] = '\0';
  206.         fprintf(stderr, "Error: unknown fold definition tag %s%s at line %d\n",
  207.                 FOLDDEF_PREFIX, p, lineno);
  208.         exit(1);
  209.       }
  210.     }
  211.   }
  212.   fclose(fp);
  213.   fprintf(ctx->fp, "\n};\n\n");

  214.   makehash(ctx);
  215. }