Merge branch 'master' of ssh://git.stderr.nl/projects/chimara/chimara
[projects/chimara/chimara.git] / interpreters / git / opcodes.c
1 // $Id: opcodes.c,v 1.20 2004/12/22 12:40:07 iain Exp $
2
3 #include "git.h"
4 #include "opcodes.h"
5
6 static void parseModeNibbles (git_uint32* pc, int numModes, int * modeBuffer)
7 {
8     int * mode = modeBuffer;
9
10     while (numModes > 0)
11     {
12         // Load byte.
13         git_uint32 byte = memRead8((*pc)++);
14
15         // Load low nibble.
16         *mode++ = byte & 0x0f;
17         --numModes;
18
19         // Check whether we need to load any more.
20         if (numModes == 0)
21             break;
22
23         // Load high nibble.
24         *mode++ = (byte >> 4) & 0x0f;
25         --numModes;
26     }
27 }
28
29 static void parseLS (git_uint32* pc, Label op)
30 {
31     int modes [2];
32     parseModeNibbles (pc, 2, modes);
33
34     parseLoad (pc, reg_L1, modes [0], size32, NULL);
35     emitCode (op);
36     parseStore (pc, reg_S1, modes [1], size32);
37 }
38 static void parseLLS (git_uint32* pc, Label op)
39 {
40     int modes [3];
41     parseModeNibbles (pc, 3, modes);
42
43     parseLoad (pc, reg_L1, modes [0], size32, NULL);
44     parseLoad (pc, reg_L2, modes [1], size32, NULL);
45     emitCode (op);
46     parseStore (pc, reg_S1, modes [2], size32);
47 }
48 static void parseLLSS (git_uint32* pc, Label op)
49 {
50     int modes [4];
51     parseModeNibbles (pc, 4, modes);
52
53     parseLoad (pc, reg_L1, modes [0], size32, NULL);
54     parseLoad (pc, reg_L2, modes [1], size32, NULL);
55     emitCode (op);
56     parseStore (pc, reg_S1, modes [2], size32);
57     parseStore (pc, reg_S2, modes [3], size32);
58 }
59 static void parseL (git_uint32* pc, Label op)
60 {
61     int modes [1];
62     parseModeNibbles (pc, 1, modes);
63
64     parseLoad (pc, reg_L1, modes [0], size32, NULL);
65     emitCode (op);
66 }
67 static void parseLL (git_uint32* pc, Label op)
68 {
69     int modes [2];
70     parseModeNibbles (pc, 2, modes);
71
72     parseLoad (pc, reg_L1, modes [0], size32, NULL);
73     parseLoad (pc, reg_L2, modes [1], size32, NULL);
74     emitCode (op);
75 }
76 static void parse_finish_branch (git_uint32* pc, Label op, LoadReg reg, int mode)
77 {
78     git_sint32 val;
79     if (parseLoad (pc, reg, mode, size32, &val))
80     {
81         // The branch offset is a constant, so we can
82         // check for the special values 0 and 1 right here.
83         
84         if (val == 0)
85         {
86             emitCode (op - label_jeq_var + label_jeq_return0);
87         }
88         else if (val == 1)
89         {
90             emitCode (op - label_jeq_var + label_jeq_return1);
91         }
92         else
93         {
94             // Calculate the destination address and
95             // emit a constant branch opcode.
96             emitConstBranch (op - label_jeq_var + label_jeq_const, *pc + val - 2);
97         }
98     }
99     else
100     {
101         // The branch offset isn't a constant, so just
102         // emit the normal opcode plus the current PC.
103         
104         emitCode (op);
105         emitData(*pc);
106     }
107 }
108 static void parseLLLL_branch (git_uint32* pc, Label op)
109 {
110     int modes [4];
111     parseModeNibbles (pc, 4, modes);
112
113     parseLoad (pc, reg_L1, modes [0], size32, NULL);
114     parseLoad (pc, reg_L2, modes [1], size32, NULL);
115     parseLoad (pc, reg_L3, modes [2], size32, NULL);
116     parse_finish_branch (pc, op, reg_L4, modes [3]);
117 }
118 static void parseLLL_branch (git_uint32* pc, Label op)
119 {
120     int modes [3];
121     parseModeNibbles (pc, 3, modes);
122
123     parseLoad (pc, reg_L1, modes [0], size32, NULL);
124     parseLoad (pc, reg_L2, modes [1], size32, NULL);
125     parse_finish_branch (pc, op, reg_L3, modes [2]);
126 }
127 static void parseLL_branch (git_uint32* pc, Label op)
128 {
129     int modes [2];
130     parseModeNibbles (pc, 2, modes);
131
132     parseLoad (pc, reg_L1, modes [0], size32, NULL);
133     parse_finish_branch (pc, op, reg_L2, modes [1]);
134 }
135 static void parseL_branch (git_uint32* pc, Label op)
136 {
137     int modes [1];
138     parseModeNibbles (pc, 1, modes);
139
140     parse_finish_branch (pc, op, reg_L1, modes [0]);
141 }
142 static void parseLLL (git_uint32* pc, Label op)
143 {
144     int modes [3];
145     parseModeNibbles (pc, 3, modes);
146
147     parseLoad (pc, reg_L1, modes [0], size32, NULL);
148     parseLoad (pc, reg_L2, modes [1], size32, NULL);
149     parseLoad (pc, reg_L3, modes [2], size32, NULL);
150     emitCode (op);
151 }
152 static void parseS (git_uint32* pc, Label op)
153 {
154     int modes [1];
155     parseModeNibbles (pc, 1, modes);
156
157     emitCode (op);
158     parseStore (pc, reg_S1, modes [0], size32);
159 }
160 static void parseSS (git_uint32* pc, Label op)
161 {
162     int modes [2];
163     parseModeNibbles (pc, 2, modes);
164
165     emitCode (op);
166     parseStore (pc, reg_S1, modes [0], size32);
167     parseStore (pc, reg_S2, modes [1], size32);
168 }
169 static void parseCatch (git_uint32 * pc)
170 {
171     int modes [2];
172     parseModeNibbles (pc, 2, modes);
173
174     parseCatchStub (pc, modes);
175 }
176 void parseInstruction (git_uint32* pc, int * done)
177 {
178     git_uint32 pcStart = *pc;
179     int modes [8];
180     git_uint32 opcode;
181     
182     static int ops = 0;
183     ++ops;
184     
185     // Fetch the opcode.
186     opcode = memRead8((*pc)++);
187
188     // Check for multi-byte opcode.
189     if (opcode & 0x80)
190     {
191         if (opcode & 0x40)
192         {
193             // Four-byte opcode.
194             opcode &= 0x3F;
195             opcode = (opcode << 8) | memRead8((*pc)++);
196             opcode = (opcode << 8) | memRead8((*pc)++);
197             opcode = (opcode << 8) | memRead8((*pc)++);
198         }
199         else
200         {
201             // Two-byte opcode.
202             opcode &= 0x7F;
203             opcode = (opcode << 8) | memRead8((*pc)++);
204         }
205     }
206
207     if (gDebug)
208     {
209         emitCode (label_debug_step);
210         emitData (pcStart);
211         emitData (opcode);
212     }
213     
214     // printf (" opcode=0x%x", opcode);
215     
216     // Now we have an opcode number,
217     // parse the operands and emit code.
218     
219     switch (opcode)
220     {
221         case op_nop: emitCode (label_nop); break;
222
223         // Arithmetic and logic
224
225         case op_add: parseLLS (pc, label_add_discard); break;
226         case op_sub: parseLLS (pc, label_sub_discard); break;        
227         case op_mul: parseLLS (pc, label_mul_discard); break;
228         case op_div: parseLLS (pc, label_div_discard); break;
229         case op_mod: parseLLS (pc, label_mod_discard); break;
230         
231         case op_bitand: parseLLS (pc, label_bitand_discard); break;
232         case op_bitor:  parseLLS (pc, label_bitor_discard);  break;
233         case op_bitxor: parseLLS (pc, label_bitxor_discard); break;
234
235         case op_neg:    parseLS (pc, label_neg_discard);    break;
236         case op_bitnot: parseLS (pc, label_bitnot_discard); break;
237
238         case op_shiftl:  parseLLS (pc, label_shiftl_discard);  break;
239         case op_ushiftr: parseLLS (pc, label_ushiftr_discard); break;
240         case op_sshiftr: parseLLS (pc, label_sshiftr_discard); break;
241
242         // Branches
243
244         case op_jump: parseL_branch (pc, label_jump_var); *done = 1; break;
245         case op_jz:   parseLL_branch (pc, label_jz_var);  break;
246         case op_jnz:  parseLL_branch (pc, label_jnz_var); break;
247         case op_jeq:  parseLLL_branch (pc, label_jeq_var);  break;
248         case op_jne:  parseLLL_branch (pc, label_jne_var);  break;
249         case op_jlt:  parseLLL_branch (pc, label_jlt_var);  break;
250         case op_jgt:  parseLLL_branch (pc, label_jgt_var);  break;
251         case op_jle:  parseLLL_branch (pc, label_jle_var);  break;
252         case op_jge:  parseLLL_branch (pc, label_jge_var);  break;
253         case op_jltu: parseLLL_branch (pc, label_jltu_var); break;
254         case op_jgtu: parseLLL_branch (pc, label_jgtu_var); break;
255         case op_jleu: parseLLL_branch (pc, label_jleu_var); break;
256         case op_jgeu: parseLLL_branch (pc, label_jgeu_var); break;
257         
258         case op_jumpabs: parseL (pc, label_jumpabs); *done = 1; break;
259
260         // Moving data
261
262         case op_copy:
263             parseModeNibbles (pc, 2, modes);
264             parseLoad (pc, reg_L1, modes [0], size32, NULL);
265             parseStore (pc, reg_S1, modes [1], size32);
266             break;
267
268         case op_copys:
269             parseModeNibbles (pc, 2, modes);
270             parseLoad (pc, reg_L1, modes [0], size16, NULL);
271             emitCode (label_copys_discard);
272             parseStore (pc, reg_S1, modes [1], size16);
273             break;
274         
275         case op_copyb:
276             parseModeNibbles (pc, 2, modes);
277             parseLoad (pc, reg_L1, modes [0], size8, NULL);
278             emitCode (label_copyb_discard);
279             parseStore (pc, reg_S1, modes [1], size8);
280             break;
281
282         case op_sexs: parseLS (pc, label_sexs_discard); break;
283         case op_sexb: parseLS (pc, label_sexb_discard); break;
284
285         // Array data
286
287         case op_aload:    parseLLS (pc, label_aload_discard);    break;
288         case op_aloads:   parseLLS (pc, label_aloads_discard);   break;
289         case op_aloadb:   parseLLS (pc, label_aloadb_discard);   break;
290         case op_aloadbit: parseLLS (pc, label_aloadbit_discard); break;
291         
292         case op_astore:    parseLLL (pc, label_astore);    break;
293         case op_astores:   parseLLL (pc, label_astores);   break;
294         case op_astoreb:   parseLLL (pc, label_astoreb);   break;
295         case op_astorebit: parseLLL (pc, label_astorebit); break;
296
297         // The stack
298
299         case op_stkcount: parseS (pc, label_stkcount);  break;
300         case op_stkpeek:  parseLS (pc, label_stkpeek);  break;
301         case op_stkswap:  emitCode (label_stkswap); break;
302         case op_stkcopy:  parseL (pc, label_stkcopy);   break;
303         case op_stkroll:  parseLL (pc, label_stkroll);  break;
304
305         // Functions
306
307         case op_call:
308             parseModeNibbles (pc, 3, modes);        
309             parseLoad (pc, reg_L1, modes [0], size32, NULL);
310             parseLoad (pc, reg_L2, modes [1], size32, NULL);
311             emitCode (label_args_stack);
312             parseCallStub (pc, modes [2]);
313             break;
314
315         case op_callf:
316             parseModeNibbles (pc, 2, modes);
317             parseLoad (pc, reg_L1, modes [0], size32, NULL);
318             emitCode (label_args_0);
319             parseCallStub (pc, modes [1]);
320             break;
321
322         case op_callfi:
323             parseModeNibbles (pc, 3, modes);
324             parseLoad (pc, reg_L1, modes [0], size32, NULL);
325             parseLoad (pc, reg_L2, modes [1], size32, NULL);
326             emitCode (label_args_1);
327             parseCallStub (pc, modes [2]);
328             break;
329
330         case op_callfii:
331             parseModeNibbles (pc, 4, modes);
332             parseLoad (pc, reg_L1, modes [0], size32, NULL);
333             parseLoad (pc, reg_L2, modes [1], size32, NULL);
334             parseLoad (pc, reg_L3, modes [2], size32, NULL);
335             emitCode (label_args_2);
336             parseCallStub (pc, modes [3]);
337             break;
338
339         case op_callfiii:
340             parseModeNibbles (pc, 5, modes);
341             parseLoad (pc, reg_L1, modes [0], size32, NULL);
342             parseLoad (pc, reg_L2, modes [1], size32, NULL);
343             parseLoad (pc, reg_L3, modes [2], size32, NULL);
344             parseLoad (pc, reg_L4, modes [3], size32, NULL);
345             emitCode (label_args_3);
346             parseCallStub (pc, modes [4]);
347             break;
348
349         case op_return:
350             parseL (pc, label_return);
351             *done = 1;
352             break;
353
354         case op_tailcall:
355             parseModeNibbles (pc, 2, modes);        
356             parseLoad (pc, reg_L1, modes [0], size32, NULL);
357             parseLoad (pc, reg_L2, modes [1], size32, NULL);
358             emitCode (label_args_stack);
359             emitCode (label_tailcall);
360             *done = 1;
361             break;
362
363         // Continuations
364
365         case op_catch: parseCatch (pc); break;
366         case op_throw:
367             parseLL (pc, label_throw);
368             *done = 1;
369             break;
370
371         case op_random:  parseLS (pc, label_random); break;
372         case op_setrandom:  parseL (pc, label_setrandom); break;
373
374         case op_getmemsize: parseS (pc, label_getmemsize); break;
375         case op_setmemsize: parseLS (pc, label_setmemsize); break;
376         
377         case op_quit:
378             emitCode (label_quit);
379             *done = 1;
380             break;
381         
382         case op_restart:
383             emitCode (label_restart);
384             *done = 1;
385             break;
386         
387         case op_restore: parseLS (pc, label_restore); break;
388         case op_restoreundo: parseS (pc, label_restoreundo); break;
389         case op_protect: parseLL (pc, label_protect); break;
390         case op_verify: parseS (pc, label_verify); break;
391
392         case op_save:
393             parseModeNibbles (pc, 2, modes);
394             parseLoad (pc, reg_L1, modes [0], size32, NULL);
395             parseSaveStub (pc, modes [1]);
396             break;
397
398         case op_saveundo:
399             parseModeNibbles (pc, 1, modes);
400             parseUndoStub (pc, modes [0]);
401             break;
402
403         case op_getiosys: parseSS (pc, label_getiosys);  break;
404         case op_setiosys: parseLL (pc, label_setiosys);  break;
405
406         case op_getstringtbl: parseS (pc, label_getstringtbl);  break;
407         case op_setstringtbl: parseL (pc, label_setstringtbl);  break;
408
409         case op_streamchar:    parseL (pc, label_streamchar);    emitData(*pc); break;
410         case op_streamnum:     parseL (pc, label_streamnum);     emitData(*pc); break;
411         case op_streamstr:     parseL (pc, label_streamstr);     emitData(*pc); break;
412         case op_streamunichar: parseL (pc, label_streamunichar); emitData(*pc); break;
413  
414         case op_glk: parseLLS (pc, label_glk); break;
415         case op_gestalt: parseLLS (pc, label_gestalt); break;
416
417         case op_binarysearch:
418         case op_linearsearch:
419             parseModeNibbles (pc, 8, modes);
420             parseLoad (pc, reg_L1, modes [0], size32, NULL);
421             parseLoad (pc, reg_L2, modes [1], size32, NULL);
422             parseLoad (pc, reg_L3, modes [2], size32, NULL);
423             parseLoad (pc, reg_L4, modes [3], size32, NULL);
424             parseLoad (pc, reg_L5, modes [4], size32, NULL);
425             parseLoad (pc, reg_L6, modes [5], size32, NULL);
426             parseLoad (pc, reg_L7, modes [6], size32, NULL);
427             emitCode (opcode == op_linearsearch ? label_linearsearch : label_binarysearch);
428             parseStore (pc, reg_S1, modes [7], size32);
429             break;
430
431         case op_linkedsearch:
432             parseModeNibbles (pc, 7, modes);
433             parseLoad (pc, reg_L1, modes [0], size32, NULL);
434             parseLoad (pc, reg_L2, modes [1], size32, NULL);
435             parseLoad (pc, reg_L3, modes [2], size32, NULL);
436             parseLoad (pc, reg_L4, modes [3], size32, NULL);
437             parseLoad (pc, reg_L5, modes [4], size32, NULL);
438             parseLoad (pc, reg_L6, modes [5], size32, NULL);
439             emitCode (label_linkedsearch);
440             parseStore (pc, reg_S1, modes [6], size32);
441             break;
442         
443         case op_debugtrap:
444             parseL (pc, label_debugtrap);
445             break;
446         
447         // Memory management
448             
449         case op_mzero: parseLL (pc, label_mzero); break;
450         case op_mcopy: parseLLL (pc, label_mcopy); break;
451         
452         case op_malloc: parseLS (pc, label_malloc); break;
453         case op_mfree: parseL (pc, label_mfree); break;
454         
455         // Function acceleration
456             
457         case op_accelfunc: parseLL (pc, label_accelfunc); break;
458         case op_accelparam: parseLL (pc, label_accelparam); break;
459
460         // Floating point
461
462         case op_numtof: parseLS (pc, label_numtof); break;
463         case op_ftonumz: parseLS (pc, label_ftonumz); break;
464         case op_ftonumn: parseLS (pc, label_ftonumn); break;
465         case op_ceil: parseLS (pc, label_ceil); break;
466         case op_floor: parseLS (pc, label_floor); break;
467         case op_sqrt: parseLS (pc, label_sqrt); break;
468         case op_exp: parseLS (pc, label_exp); break;
469         case op_log: parseLS (pc, label_log); break;
470
471         case op_fadd: parseLLS (pc, label_fadd_discard); break;
472         case op_fsub: parseLLS (pc, label_fsub_discard); break;
473         case op_fmul: parseLLS (pc, label_fmul_discard); break;
474         case op_fdiv: parseLLS (pc, label_fdiv_discard); break;
475         case op_pow: parseLLS (pc, label_pow); break;
476         case op_atan2: parseLLS (pc, label_atan2); break;
477
478         case op_fmod: parseLLSS (pc, label_fmod); break;
479
480         case op_sin: parseLS (pc, label_sin); break;
481         case op_cos: parseLS (pc, label_cos); break;
482         case op_tan: parseLS (pc, label_tan); break;
483         case op_asin: parseLS (pc, label_asin); break;
484         case op_acos: parseLS (pc, label_acos); break;
485         case op_atan: parseLS (pc, label_atan); break;
486
487         case op_jfeq: parseLLLL_branch (pc, label_jfeq_var); break;
488         case op_jfne: parseLLLL_branch (pc, label_jfne_var); break;
489
490         case op_jflt: parseLLL_branch (pc, label_jflt_var); break;
491         case op_jfle: parseLLL_branch (pc, label_jfle_var); break;
492         case op_jfgt: parseLLL_branch (pc, label_jfgt_var); break;
493         case op_jfge: parseLLL_branch (pc, label_jfge_var); break;
494
495         case op_jisnan: parseLL_branch (pc, label_jisnan_var); break;
496         case op_jisinf: parseLL_branch (pc, label_jisinf_var); break;
497
498         // Special Git opcodes
499         
500         case op_git_setcacheram: parseL (pc, label_git_setcacheram); break;
501         case op_git_prunecache: parseLL (pc, label_git_prunecache); break;
502         
503         default:
504             // Unknown opcode.
505             abortCompilation();
506             break;
507     }
508 }