Bug fixes
[rodin/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 parseL (git_uint32* pc, Label op)
49 {
50     int modes [1];
51     parseModeNibbles (pc, 1, modes);
52
53     parseLoad (pc, reg_L1, modes [0], size32, NULL);
54     emitCode (op);
55 }
56 static void parseLL (git_uint32* pc, Label op)
57 {
58     int modes [2];
59     parseModeNibbles (pc, 2, modes);
60
61     parseLoad (pc, reg_L1, modes [0], size32, NULL);
62     parseLoad (pc, reg_L2, modes [1], size32, NULL);
63     emitCode (op);
64 }
65 static void parse_finish_branch (git_uint32* pc, Label op, LoadReg reg, int mode)
66 {
67     git_sint32 val;
68     if (parseLoad (pc, reg, mode, size32, &val))
69     {
70         // The branch offset is a constant, so we can
71         // check for the special values 0 and 1 right here.
72         
73         if (val == 0)
74         {
75             emitCode (op - label_jeq_var + label_jeq_return0);
76         }
77         else if (val == 1)
78         {
79             emitCode (op - label_jeq_var + label_jeq_return1);
80         }
81         else
82         {
83             // Calculate the destination address and
84             // emit a constant branch opcode.
85             emitConstBranch (op - label_jeq_var + label_jeq_const, *pc + val - 2);
86         }
87     }
88     else
89     {
90         // The branch offset isn't a constant, so just
91         // emit the normal opcode plus the current PC.
92         
93         emitCode (op);
94         emitData(*pc);
95     }
96 }
97 static void parseLLL_branch (git_uint32* pc, Label op)
98 {
99     int modes [3];
100     parseModeNibbles (pc, 3, modes);
101
102     parseLoad (pc, reg_L1, modes [0], size32, NULL);
103     parseLoad (pc, reg_L2, modes [1], size32, NULL);
104     parse_finish_branch (pc, op, reg_L3, modes [2]);
105 }
106 static void parseLL_branch (git_uint32* pc, Label op)
107 {
108     int modes [2];
109     parseModeNibbles (pc, 2, modes);
110
111     parseLoad (pc, reg_L1, modes [0], size32, NULL);
112     parse_finish_branch (pc, op, reg_L2, modes [1]);
113 }
114 static void parseL_branch (git_uint32* pc, Label op)
115 {
116     int modes [1];
117     parseModeNibbles (pc, 1, modes);
118
119     parse_finish_branch (pc, op, reg_L1, modes [0]);
120 }
121 static void parseLLL (git_uint32* pc, Label op)
122 {
123     int modes [3];
124     parseModeNibbles (pc, 3, modes);
125
126     parseLoad (pc, reg_L1, modes [0], size32, NULL);
127     parseLoad (pc, reg_L2, modes [1], size32, NULL);
128     parseLoad (pc, reg_L3, modes [2], size32, NULL);
129     emitCode (op);
130 }
131 static void parseS (git_uint32* pc, Label op)
132 {
133     int modes [1];
134     parseModeNibbles (pc, 1, modes);
135
136     emitCode (op);
137     parseStore (pc, reg_S1, modes [0], size32);
138 }
139 static void parseSS (git_uint32* pc, Label op)
140 {
141     int modes [2];
142     parseModeNibbles (pc, 2, modes);
143
144     emitCode (op);
145     parseStore (pc, reg_S1, modes [0], size32);
146     parseStore (pc, reg_S2, modes [1], size32);
147 }
148 static void parseCatch (git_uint32 * pc)
149 {
150     Block stubCode;
151     int modes [2];
152     parseModeNibbles (pc, 2, modes);
153
154     parseCatchStub (pc, modes[0]);
155
156     // This is a little nasty. The last thing emitted by
157     // parseCatchStub() is the current value of the PC,
158     // which is where execution will resume when and if
159     // the stub is used; but execution should resume
160     // after the branch we're about to do, so we'll need
161     // to fix up that emitted value.
162
163     stubCode = peekAtEmittedStuff (1);
164
165     parseLoad (pc, reg_L1, modes[1], size32, NULL);
166     emitCode (label_jump_var);
167     emitData(*pc);
168
169     // Fix up the end of the stub, as described above.
170     *stubCode = *pc;
171 }
172 void parseInstruction (git_uint32* pc, int * done)
173 {
174     git_uint32 pcStart = *pc;
175     int modes [8];
176     git_uint32 opcode;
177     
178     static int ops = 0;
179     ++ops;
180     
181     // Fetch the opcode.
182     opcode = memRead8((*pc)++);
183
184     // Check for multi-byte opcode.
185     if (opcode & 0x80)
186     {
187         if (opcode & 0x40)
188         {
189             // Four-byte opcode.
190             opcode &= 0x3F;
191             opcode = (opcode << 8) | memRead8((*pc)++);
192             opcode = (opcode << 8) | memRead8((*pc)++);
193             opcode = (opcode << 8) | memRead8((*pc)++);
194         }
195         else
196         {
197             // Two-byte opcode.
198             opcode &= 0x7F;
199             opcode = (opcode << 8) | memRead8((*pc)++);
200         }
201     }
202
203     if (gDebug)
204     {
205         emitCode (label_debug_step);
206         emitData (pcStart);
207         emitData (opcode);
208     }
209     
210     // printf (" opcode=0x%x", opcode);
211     
212     // Now we have an opcode number,
213     // parse the operands and emit code.
214     
215     switch (opcode)
216     {
217         case op_nop: emitCode (label_nop); break;
218
219         // Arithmetic and logic
220
221         case op_add: parseLLS (pc, label_add_discard); break;
222         case op_sub: parseLLS (pc, label_sub_discard); break;        
223         case op_mul: parseLLS (pc, label_mul_discard); break;
224         case op_div: parseLLS (pc, label_div_discard); break;
225         case op_mod: parseLLS (pc, label_mod_discard); break;
226         
227         case op_bitand: parseLLS (pc, label_bitand_discard); break;
228         case op_bitor:  parseLLS (pc, label_bitor_discard);  break;
229         case op_bitxor: parseLLS (pc, label_bitxor_discard); break;
230
231         case op_neg:    parseLS (pc, label_neg_discard);    break;
232         case op_bitnot: parseLS (pc, label_bitnot_discard); break;
233
234         case op_shiftl:  parseLLS (pc, label_shiftl_discard);  break;
235         case op_ushiftr: parseLLS (pc, label_ushiftr_discard); break;
236         case op_sshiftr: parseLLS (pc, label_sshiftr_discard); break;
237
238         // Branches
239
240         case op_jump: parseL_branch (pc, label_jump_var); *done = 1; break;
241         case op_jz:   parseLL_branch (pc, label_jz_var);  break;
242         case op_jnz:  parseLL_branch (pc, label_jnz_var); break;
243         case op_jeq:  parseLLL_branch (pc, label_jeq_var);  break;
244         case op_jne:  parseLLL_branch (pc, label_jne_var);  break;
245         case op_jlt:  parseLLL_branch (pc, label_jlt_var);  break;
246         case op_jgt:  parseLLL_branch (pc, label_jgt_var);  break;
247         case op_jle:  parseLLL_branch (pc, label_jle_var);  break;
248         case op_jge:  parseLLL_branch (pc, label_jge_var);  break;
249         case op_jltu: parseLLL_branch (pc, label_jltu_var); break;
250         case op_jgtu: parseLLL_branch (pc, label_jgtu_var); break;
251         case op_jleu: parseLLL_branch (pc, label_jleu_var); break;
252         case op_jgeu: parseLLL_branch (pc, label_jgeu_var); break;
253         
254         case op_jumpabs: parseL (pc, label_jumpabs); *done = 1; break;
255
256         // Moving data
257
258         case op_copy:
259             parseModeNibbles (pc, 2, modes);
260             parseLoad (pc, reg_L1, modes [0], size32, NULL);
261             parseStore (pc, reg_S1, modes [1], size32);
262             break;
263
264         case op_copys:
265             parseModeNibbles (pc, 2, modes);
266             parseLoad (pc, reg_L1, modes [0], size16, NULL);
267             emitCode (label_copys_discard);
268             parseStore (pc, reg_S1, modes [1], size16);
269             break;
270         
271         case op_copyb:
272             parseModeNibbles (pc, 2, modes);
273             parseLoad (pc, reg_L1, modes [0], size8, NULL);
274             emitCode (label_copyb_discard);
275             parseStore (pc, reg_S1, modes [1], size8);
276             break;
277
278         case op_sexs: parseLS (pc, label_sexs_discard); break;
279         case op_sexb: parseLS (pc, label_sexb_discard); break;
280
281         // Array data
282
283         case op_aload:    parseLLS (pc, label_aload_discard);    break;
284         case op_aloads:   parseLLS (pc, label_aloads_discard);   break;
285         case op_aloadb:   parseLLS (pc, label_aloadb_discard);   break;
286         case op_aloadbit: parseLLS (pc, label_aloadbit_discard); break;
287         
288         case op_astore:    parseLLL (pc, label_astore);    break;
289         case op_astores:   parseLLL (pc, label_astores);   break;
290         case op_astoreb:   parseLLL (pc, label_astoreb);   break;
291         case op_astorebit: parseLLL (pc, label_astorebit); break;
292
293         // The stack
294
295         case op_stkcount: parseS (pc, label_stkcount);  break;
296         case op_stkpeek:  parseLS (pc, label_stkpeek);  break;
297         case op_stkswap:  emitCode (label_stkswap); break;
298         case op_stkcopy:  parseL (pc, label_stkcopy);   break;
299         case op_stkroll:  parseLL (pc, label_stkroll);  break;
300
301         // Functions
302
303         case op_call:
304             parseModeNibbles (pc, 3, modes);        
305             parseLoad (pc, reg_L1, modes [0], size32, NULL);
306             parseLoad (pc, reg_L2, modes [1], size32, NULL);
307             emitCode (label_args_stack);
308             parseCallStub (pc, modes [2]);
309             break;
310
311         case op_callf:
312             parseModeNibbles (pc, 2, modes);
313             parseLoad (pc, reg_L1, modes [0], size32, NULL);
314             emitCode (label_args_0);
315             parseCallStub (pc, modes [1]);
316             break;
317
318         case op_callfi:
319             parseModeNibbles (pc, 3, modes);
320             parseLoad (pc, reg_L1, modes [0], size32, NULL);
321             parseLoad (pc, reg_L2, modes [1], size32, NULL);
322             emitCode (label_args_1);
323             parseCallStub (pc, modes [2]);
324             break;
325
326         case op_callfii:
327             parseModeNibbles (pc, 4, modes);
328             parseLoad (pc, reg_L1, modes [0], size32, NULL);
329             parseLoad (pc, reg_L2, modes [1], size32, NULL);
330             parseLoad (pc, reg_L3, modes [2], size32, NULL);
331             emitCode (label_args_2);
332             parseCallStub (pc, modes [3]);
333             break;
334
335         case op_callfiii:
336             parseModeNibbles (pc, 5, modes);
337             parseLoad (pc, reg_L1, modes [0], size32, NULL);
338             parseLoad (pc, reg_L2, modes [1], size32, NULL);
339             parseLoad (pc, reg_L3, modes [2], size32, NULL);
340             parseLoad (pc, reg_L4, modes [3], size32, NULL);
341             emitCode (label_args_3);
342             parseCallStub (pc, modes [4]);
343             break;
344
345         case op_return:
346             parseL (pc, label_return);
347             *done = 1;
348             break;
349
350         case op_tailcall:
351             parseModeNibbles (pc, 2, modes);        
352             parseLoad (pc, reg_L1, modes [0], size32, NULL);
353             parseLoad (pc, reg_L2, modes [1], size32, NULL);
354             emitCode (label_args_stack);
355             emitCode (label_tailcall);
356             *done = 1;
357             break;
358
359         // Continuations
360
361         case op_catch: parseCatch (pc); break;
362             case op_throw:
363             parseLL (pc, label_throw);
364             *done = 1;
365             break;
366
367         case op_random:  parseLS (pc, label_random); break;
368         case op_setrandom:  parseL (pc, label_setrandom); break;
369
370         case op_getmemsize: parseS (pc, label_getmemsize); break;
371         case op_setmemsize: parseLS (pc, label_setmemsize); break;
372         
373         case op_quit:
374             emitCode (label_quit);
375             *done = 1;
376             break;
377         
378         case op_restart:
379             emitCode (label_restart);
380             *done = 1;
381             break;
382         
383         case op_restore: parseLS (pc, label_restore); break;
384         case op_restoreundo: parseS (pc, label_restoreundo); break;
385         case op_protect: parseLL (pc, label_protect); break;
386         case op_verify: parseS (pc, label_verify); break;
387
388         case op_save:
389             parseModeNibbles (pc, 2, modes);
390             parseLoad (pc, reg_L1, modes [0], size32, NULL);
391             parseSaveStub (pc, modes [1]);
392             break;
393
394         case op_saveundo:
395             parseModeNibbles (pc, 1, modes);
396             parseUndoStub (pc, modes [0]);
397             break;
398
399         case op_getiosys: parseSS (pc, label_getiosys);  break;
400         case op_setiosys: parseLL (pc, label_setiosys);  break;
401
402         case op_getstringtbl: parseS (pc, label_getstringtbl);  break;
403         case op_setstringtbl: parseL (pc, label_setstringtbl);  break;
404
405         case op_streamchar:    parseL (pc, label_streamchar);    emitData(*pc); break;
406         case op_streamnum:     parseL (pc, label_streamnum);     emitData(*pc); break;
407         case op_streamstr:     parseL (pc, label_streamstr);     emitData(*pc); break;
408         case op_streamunichar: parseL (pc, label_streamunichar); emitData(*pc); break;
409  
410         case op_glk: parseLLS (pc, label_glk); break;
411         case op_gestalt: parseLLS (pc, label_gestalt); break;
412
413         case op_binarysearch:
414         case op_linearsearch:
415             parseModeNibbles (pc, 8, modes);
416             parseLoad (pc, reg_L1, modes [0], size32, NULL);
417             parseLoad (pc, reg_L2, modes [1], size32, NULL);
418             parseLoad (pc, reg_L3, modes [2], size32, NULL);
419             parseLoad (pc, reg_L4, modes [3], size32, NULL);
420             parseLoad (pc, reg_L5, modes [4], size32, NULL);
421             parseLoad (pc, reg_L6, modes [5], size32, NULL);
422             parseLoad (pc, reg_L7, modes [6], size32, NULL);
423             emitCode (opcode == op_linearsearch ? label_linearsearch : label_binarysearch);
424             parseStore (pc, reg_S1, modes [7], size32);
425             break;
426
427         case op_linkedsearch:
428             parseModeNibbles (pc, 7, modes);
429             parseLoad (pc, reg_L1, modes [0], size32, NULL);
430             parseLoad (pc, reg_L2, modes [1], size32, NULL);
431             parseLoad (pc, reg_L3, modes [2], size32, NULL);
432             parseLoad (pc, reg_L4, modes [3], size32, NULL);
433             parseLoad (pc, reg_L5, modes [4], size32, NULL);
434             parseLoad (pc, reg_L6, modes [5], size32, NULL);
435             emitCode (label_linkedsearch);
436             parseStore (pc, reg_S1, modes [6], size32);
437             break;
438         
439         case op_debugtrap:
440             parseL (pc, label_debugtrap);
441             break;
442         
443         // Memory management
444             
445         case op_mzero: parseLL (pc, label_mzero); break;
446         case op_mcopy: parseLLL (pc, label_mcopy); break;
447         
448         case op_malloc: parseLS (pc, label_malloc); break;
449         case op_mfree: parseL (pc, label_mfree); break;
450         
451         // Function acceleration
452             
453         case op_accelfunc: parseLL (pc, label_accelfunc); break;
454         case op_accelparam: parseLL (pc, label_accelparam); break;
455        
456         // Special Git opcodes
457         
458         case op_git_setcacheram: parseL (pc, label_git_setcacheram); break;
459         case op_git_prunecache: parseLL (pc, label_git_prunecache); break;
460         
461         default:
462             // Unknown opcode.
463             abortCompilation();
464             break;
465     }
466 }