Merge branch 'master' of ssh://git.stderr.nl/projects/chimara/chimara
[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             CASE_NO_OPERANDS (fadd_discard,     fadd_ ## storeOp);      \
54             CASE_NO_OPERANDS (fsub_discard,     fsub_ ## storeOp);      \
55             CASE_NO_OPERANDS (fmul_discard,     fmul_ ## storeOp);      \
56             CASE_NO_OPERANDS (fdiv_discard,     fdiv_ ## storeOp);      \
57             default: break;                                             \
58         }                                                               \
59         break
60
61 #define REPLACE_L1_L2(mode2)                                    \
62     case label_L2_ ## mode2:                                    \
63         switch(sLastOp)                                         \
64         {                                                       \
65             CASE_ONE_OPERAND (L1_const, L1_const_L2_ ## mode2); \
66             CASE_NO_OPERANDS (L1_stack, L1_stack_L2_ ## mode2); \
67             CASE_ONE_OPERAND (L1_local, L1_local_L2_ ## mode2); \
68             CASE_ONE_OPERAND (L1_addr,  L1_addr_L2_ ## mode2);  \
69             default: break;                                     \
70         }                                                       \
71         break
72
73 #define REPLACE_LOAD_OP(loadOp,reg)                                         \
74     case label_ ## loadOp:                                                  \
75         switch(sLastOp)                                                     \
76         {                                                                   \
77             CASE_ONE_OPERAND (reg ## _const, loadOp ## _ ## reg ## _const); \
78             CASE_NO_OPERANDS (reg ## _stack, loadOp ## _ ## reg ## _stack); \
79             CASE_ONE_OPERAND (reg ## _local, loadOp ## _ ## reg ## _local); \
80             CASE_ONE_OPERAND (reg ## _addr,  loadOp ## _ ## reg ## _addr);  \
81             default: break;                                                 \
82         }                                                                   \
83         break
84
85 extern void emitCode (Label op)
86 {
87     git_uint32 temp;
88
89     if (gPeephole)
90     {
91         switch (op)
92         {
93             REPLACE_SINGLE (args_stack, call_stub_discard, args_stack_call_stub_discard);
94             REPLACE_SINGLE (args_stack, call_stub_addr,    args_stack_call_stub_addr);
95             REPLACE_SINGLE (args_stack, call_stub_local,   args_stack_call_stub_local);
96             REPLACE_SINGLE (args_stack, call_stub_stack,   args_stack_call_stub_stack);
97
98             REPLACE_STORE (S1_stack);
99             REPLACE_STORE (S1_local);
100             REPLACE_STORE (S1_addr);
101
102             REPLACE_L1_L2 (const);
103             REPLACE_L1_L2 (stack);
104             REPLACE_L1_L2 (local);
105             REPLACE_L1_L2 (addr);
106
107             REPLACE_LOAD_OP (return, L1);
108             REPLACE_LOAD_OP (astore, L3);
109             REPLACE_LOAD_OP (astores, L3);
110             REPLACE_LOAD_OP (astoreb, L3);
111             REPLACE_LOAD_OP (astorebit, L3);
112             
113             default: break;
114         }
115     }
116     goto noPeephole;
117
118 replaceOneOperand:
119     // The previous opcode has one operand, so
120     // we have to go back two steps to update it.
121     temp = undoEmit();  // Save the operand.
122     undoEmit();         // Remove the old opcode.
123     emitFinalCode (op); // Emit the new opcode.
124     emitData (temp);    // Emit the operand again.
125     goto done;
126
127 replaceNoOperands:
128     undoEmit();
129     // ... fall through
130 noPeephole:
131     emitFinalCode (op);
132     // ... fall through
133 done:
134     sLastOp = op;
135 }