modernc.org/ccgo/v3@v3.16.14/lib/testdata/CompCert-3.6/test/c/vmach.c (about)

     1  /* A bytecode interpreter for a simple virtual machine */
     2  
     3  #include <stdio.h>
     4  #include <stdlib.h>
     5  
     6  #define STACKSIZE 256
     7  
     8  enum wordcode_instruct {
     9    WCALL1, WCALL1_pop1, WCONST, WCONST_pop1, WBRANCHIF, WBRANCHIF_pop1,
    10    WCALL3, WRETURN, WBRANCH, WLTINT, WADDINT, WOFFSETINT, WDUP, WGRAB, WSTOP
    11  };
    12  
    13  #define Opcode (instr & 0xFF)
    14  #define Byte1 ((instr >> 8) & 0xFF)
    15  #define Byte2 ((instr >> 16) & 0xFF)
    16  #define Byte3 (instr >> 24)
    17  #define Op1 sp[Byte1]
    18  #define Op2 sp[Byte2]
    19  #define Op3 sp[Byte3]
    20  #define Imm8s ((int)instr >> 24)
    21  #define Imm16u (instr >> 16)
    22  #define Imm16s ((int)instr >> 16)
    23  #define Imm24u (instr >> 8)
    24  #define Imm24s ((int)instr >> 8)
    25  #define Adjust1 (sp += instr & 1)
    26  #define Adjust2 (sp += instr & 3)
    27  #define Adjustbyte1 (sp += Byte1)
    28  #define Adjustbyte2 (sp += Byte2)
    29  #define Adjustbyte3 (sp += Byte3)
    30  #define Extrabyte1(w) (w & 0xFF)
    31  #define Extrabyte2(w) ((w >> 8) & 0xFF)
    32  #define Extrabyte3(w) ((w >> 16) & 0xFF)
    33  #define Extrabyte4(w) (w >> 24)
    34  #define Extraop1(w) sp[Extrabyte1(w)]
    35  #define Extraop2(w) sp[Extrabyte2(w)]
    36  #define Extraop3(w) sp[Extrabyte3(w)]
    37  #define Extraop4(w) sp[Extrabyte4(w)]
    38  #define Push1(x) \
    39    sp-=1, sp[0]=x
    40  #define Push2(x,y) \
    41    sp-=2, sp[1]=x, sp[0]=y
    42  #define Push3(x,y,z) \
    43    sp-=3, sp[2]=x, sp[1]=y, sp[0]=z
    44  #define Push4(x,y,z,t) \
    45    sp-=4, sp[3]=x, sp[2]=y, sp[1]=z, sp[0]=t
    46  #define Push5(x,y,z,t,u) \
    47    sp-=5, sp[4]=x, sp[3]=y, sp[2]=z, sp[1]=t, sp[0]=u
    48  #define Push6(x,y,z,t,u,v) \
    49    sp-=6, sp[5]=x, sp[4]=y, sp[3]=z, sp[2]=t, sp[1]=u, sp[0]=v
    50  #define Push7(x,y,z,t,u,v,w) \
    51    sp-=7, sp[6]=x, sp[5]=y, sp[4]=z, sp[3]=t, sp[2]=u, sp[1]=v, sp[0]=w
    52  
    53  long stack[STACKSIZE];
    54  
    55  long wordcode_interp(unsigned int* code)
    56  {
    57    long * sp;
    58    unsigned int * pc;
    59    unsigned int instr;
    60    int extra_args = 0;
    61  
    62    sp = stack + STACKSIZE;
    63    pc = code;
    64    while (1) {
    65      instr = *pc++;
    66      switch (Opcode) {
    67  
    68      case WCALL1: case WCALL1_pop1: {
    69        long arg = Op1;
    70        Adjust1;
    71        Push3((long)pc, extra_args, arg);
    72        pc += Imm16s;
    73        extra_args = 0;
    74        break;
    75      }
    76      case WCONST: case WCONST_pop1: {
    77        Adjust1;
    78        Push1(Imm24s);
    79        break;
    80      }
    81      case WBRANCHIF: case WBRANCHIF_pop1: {
    82        long arg = Op1;
    83        Adjust1;
    84        if (arg) pc += Imm16s;
    85        break;
    86      }
    87      case WCALL3: {
    88        unsigned int ext = *pc++;
    89        long arg1 = Extraop1(ext);
    90        long arg2 = Extraop2(ext);
    91        long arg3 = Extraop3(ext);
    92        Adjustbyte1;
    93        Push5((long)pc, extra_args, arg3, arg2, arg1);
    94        pc += Imm16s;
    95        extra_args = 2;
    96        break;
    97      }
    98      case WRETURN: {
    99        long res = Op1;
   100        Adjustbyte2;
   101        if (extra_args > 0) {
   102          printf("Over-application.\n");
   103          exit(2);
   104        } else {
   105          extra_args = sp[0];
   106          pc = (unsigned int *) sp[1];
   107          sp += 1;
   108          *sp = res;
   109        }
   110        break;
   111      }
   112      case WBRANCH: {
   113        Adjustbyte1;
   114        pc += Imm16s;
   115        break;
   116      }
   117      case WLTINT: {
   118        long arg1 = Op1, arg2 = Op2;
   119        Adjustbyte3;
   120        Push1(arg1 < arg2);
   121        break;
   122      }
   123      case WADDINT: {
   124        long arg1 = Op1, arg2 = Op2;
   125        Adjustbyte3;
   126        Push1(arg1 + arg2);
   127        break;
   128      }
   129      case WOFFSETINT: {
   130        long arg = Op1;
   131        Adjustbyte2;
   132        Push1(arg + Imm8s);
   133        break;
   134      }
   135      case WDUP: {
   136        long arg = Op1;
   137        Push1(arg);
   138        break;
   139      }
   140      case WGRAB: {
   141        int required = Byte1;
   142        if (extra_args >= required) {
   143          extra_args -= required;
   144        } else {
   145          printf("Partial application.\n");
   146          exit(2);
   147        }
   148        break;
   149      }
   150      case WSTOP: {
   151        long res = Op1;
   152        Adjustbyte2;
   153        return res;
   154        break;
   155      }
   156      }
   157    }
   158  }
   159  
   160  #define I(a,b,c,d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
   161  
   162  unsigned int wordcode_fib[] = {
   163  /* 0 */ I(WCONST, 30, 0, 0),
   164  /* 1 */ I(WCALL1_pop1, 0, 3-1-1, 0),
   165  /* 2 */ I(WSTOP, 0, 1, 0),
   166  /* 3 */ I(WCONST, 2, 0, 0),
   167  /* 4 */ I(WLTINT, 1, 0, 1),
   168  /* 5 */ I(WBRANCHIF_pop1, 0, 12-5-1, 0),
   169  /* 6 */ I(WOFFSETINT, 0, 0, -1),
   170  /* 7 */ I(WCALL1_pop1, 0, 3-7-1, 0),
   171  /* 8 */ I(WOFFSETINT, 1, 0, -2),
   172  /* 9 */ I(WCALL1_pop1, 0, 3-9-1, 0),
   173  /* 10 */ I(WADDINT, 0, 1, 2),
   174  /* 11 */ I(WRETURN, 0, 2, 0),
   175  /* 12 */ I(WCONST, 1, 0, 0),
   176  /* 13 */ I(WRETURN, 0, 2, 0)
   177  };
   178  unsigned int wordcode_tak[] = {
   179  /* 0 */ I(WCONST, 6, 0, 0),
   180  /* 1 */ I(WCONST, 12, 0, 0),
   181  /* 2 */ I(WCONST, 18, 0, 0),
   182  /* 3 */ I(WCALL3, 3, 6-3-2, 0),
   183  /* 4 */ I(0, 1, 2, 0),
   184  /* 5 */ I(WSTOP, 0, 1, 0),
   185  /* 6 */ I(WGRAB, 2, 0, 0),              /* z y x */
   186  /* 7 */ I(WLTINT, 1, 0, 0),             /* z y x (y<x) */
   187  /* 8 */ I(WBRANCHIF_pop1, 0, 11-8-1, 0),
   188  /* 9 */ I(WDUP, 2, 0, 0),
   189  /* 10 */ I(WRETURN, 0, 4, 0),
   190  /* 11 */ I(WOFFSETINT, 0, 0, -1),        /* z y x (x-1) */
   191  /* 12 */ I(WCALL3, 1, 6-12-2, 0),
   192  /* 13 */ I(0, 2, 3, 0),                  /* z y x tx */
   193  /* 14 */ I(WOFFSETINT, 2, 0, -1),        /* z y x tx (y-1) */
   194  /* 15 */ I(WCALL3, 1, 6-15-2, 0),
   195  /* 16 */ I(0, 4, 2, 0),                  /* z y x tx ty */
   196  /* 17 */ I(WOFFSETINT, 4, 0, -1),        /* z y x tx ty (z-1) */
   197  /* 18 */ I(WCALL3, 1, 6-18-2, 0),
   198  /* 19 */ I(0, 3, 4, 0),                  /* z y x tx ty tz */
   199  /* 20 */ I(WCALL3, 3, 6-20-2, 0),
   200  /* 21 */ I(2, 1, 0, 0),                  /* z y x res */
   201  /* 22 */ I(WRETURN, 0, 4, 0),
   202  };
   203  
   204  int main(int argc, char ** argv)
   205  {
   206    printf("fib(30) = %ld\n", wordcode_interp(wordcode_fib));
   207    printf("tak(18, 12, 6) = %ld\n", wordcode_interp(wordcode_tak));
   208  
   209    return 0;
   210  }
   211