4068b6796a0ba4e5c0235aad14174805d1f69a5d
[projects/chimara/chimara.git] / interpreters / git / peephole.c
1 // $Id: peephole.c,v 1.6 2003/10/13 22:53:04 iain Exp $
2 // Peephole optimiser for git
3
4 #include "git.h"
5
6 static Label sLastOp;
7
8 extern void resetPeepholeOptimiser ()
9 {
10     sLastOp = label_nop;
11 }
12
13 #define REPLACE_SINGLE(lastOp,thisOp,newOp) \
14     case label_ ## thisOp:                  \
15         if (sLastOp == label_ ## lastOp)    \
16         {                                   \
17             op = label_ ## newOp;           \
18             goto replaceNoOperands;         \
19         }                                   \
20         break
21
22 #define CASE_NO_OPERANDS(lastOp,newOp) \
23     case label_ ## lastOp: op = label_ ## newOp; goto replaceNoOperands
24
25 #define CASE_ONE_OPERAND(lastOp,newOp) \
26     case label_ ## lastOp: op = label_ ## newOp; goto replaceOneOperand
27
28 #define REPLACE_STORE(storeOp) \
29     case label_ ## storeOp:                                             \
30         switch(sLastOp)                                                 \
31         {                                                               \
32             CASE_NO_OPERANDS (add_discard,      add_ ## storeOp);       \
33             CASE_NO_OPERANDS (sub_discard,      sub_ ## storeOp);       \
34             CASE_NO_OPERANDS (mul_discard,      mul_ ## storeOp);       \
35             CASE_NO_OPERANDS (div_discard,      div_ ## storeOp);       \
36             CASE_NO_OPERANDS (mod_discard,      mod_ ## storeOp);       \
37             CASE_NO_OPERANDS (neg_discard,      neg_ ## storeOp);       \
38             CASE_NO_OPERANDS (bitand_discard,   bitand_ ## storeOp);    \
39             CASE_NO_OPERANDS (bitor_discard,    bitor_ ## storeOp);     \
40             CASE_NO_OPERANDS (bitxor_discard,   bitxor_ ## storeOp);    \
41             CASE_NO_OPERANDS (bitnot_discard,   bitnot_ ## storeOp);    \
42             CASE_NO_OPERANDS (shiftl_discard,   shiftl_ ## storeOp);    \
43             CASE_NO_OPERANDS (sshiftr_discard,  sshiftr_ ## storeOp);   \
44             CASE_NO_OPERANDS (ushiftr_discard,  ushiftr_ ## storeOp);   \
45             CASE_NO_OPERANDS (copys_discard,    copys_ ## storeOp);     \
46             CASE_NO_OPERANDS (copyb_discard,    copyb_ ## storeOp);     \
47             CASE_NO_OPERANDS (sexs_discard,     sexs_ ## storeOp);      \
48             CASE_NO_OPERANDS (sexb_discard,     sexb_ ## storeOp);      \
49             CASE_NO_OPERANDS (aload_discard,    aload_ ## storeOp);     \
50             CASE_NO_OPERANDS (aloads_discard,   aloads_ ## storeOp);    \
51             CASE_NO_OPERANDS (aloadb_discard,   aloadb_ ## storeOp);    \
52             CASE_NO_OPERANDS (aloadbit_discard, aloadbit_ ## storeOp);  \
53             default: break;                                             \
54         }                                                               \
55         break
56
57 #define REPLACE_L1_L2(mode2)                                    \
58     case label_L2_ ## mode2:                                    \
59         switch(sLastOp)                                         \
60         {                                                       \
61             CASE_ONE_OPERAND (L1_const, L1_const_L2_ ## mode2); \
62             CASE_NO_OPERANDS (L1_stack, L1_stack_L2_ ## mode2); \
63             CASE_ONE_OPERAND (L1_local, L1_local_L2_ ## mode2); \
64             CASE_ONE_OPERAND (L1_addr,  L1_addr_L2_ ## mode2);  \
65             default: break;                                     \
66         }                                                       \
67         break
68
69 #define REPLACE_LOAD_OP(loadOp,reg)                                         \
70     case label_ ## loadOp:                                                  \
71         switch(sLastOp)                                                     \
72         {                                                                   \
73             CASE_ONE_OPERAND (reg ## _const, loadOp ## _ ## reg ## _const); \
74             CASE_NO_OPERANDS (reg ## _stack, loadOp ## _ ## reg ## _stack); \
75             CASE_ONE_OPERAND (reg ## _local, loadOp ## _ ## reg ## _local); \
76             CASE_ONE_OPERAND (reg ## _addr,  loadOp ## _ ## reg ## _addr);  \
77             default: break;                                                 \
78         }                                                                   \
79         break
80
81 extern void emitCode (Label op)
82 {
83     git_uint32 temp;
84
85     if (gPeephole)
86     {
87         switch (op)
88         {
89             REPLACE_SINGLE (args_stack, call_stub_discard, args_stack_call_stub_discard);
90             REPLACE_SINGLE (args_stack, call_stub_addr,    args_stack_call_stub_addr);
91             REPLACE_SINGLE (args_stack, call_stub_local,   args_stack_call_stub_local);
92             REPLACE_SINGLE (args_stack, call_stub_stack,   args_stack_call_stub_stack);
93
94             REPLACE_STORE (S1_stack);
95             REPLACE_STORE (S1_local);
96             REPLACE_STORE (S1_addr);
97
98             REPLACE_L1_L2 (const);
99             REPLACE_L1_L2 (stack);
100             REPLACE_L1_L2 (local);
101             REPLACE_L1_L2 (addr);
102
103             REPLACE_LOAD_OP (return, L1);
104             REPLACE_LOAD_OP (astore, L3);
105             REPLACE_LOAD_OP (astores, L3);
106             REPLACE_LOAD_OP (astoreb, L3);
107             REPLACE_LOAD_OP (astorebit, L3);
108             
109             default: break;
110         }
111     }
112     goto noPeephole;
113
114 replaceOneOperand:
115     // The previous opcode has one operand, so
116     // we have to go back two steps to update it.
117     temp = undoEmit();  // Save the operand.
118     undoEmit();         // Remove the old opcode.
119     emitFinalCode (op); // Emit the new opcode.
120     emitData (temp);    // Emit the operand again.
121     goto done;
122
123 replaceNoOperands:
124     undoEmit();
125     // ... fall through
126 noPeephole:
127     emitFinalCode (op);
128     // ... fall through
129 done:
130     sLastOp = op;
131 }