Add Glulxe and Git. They compile but don't work yet.
[rodin/chimara.git] / interpreters / git / peephole.c
diff --git a/interpreters/git/peephole.c b/interpreters/git/peephole.c
new file mode 100644 (file)
index 0000000..4068b67
--- /dev/null
@@ -0,0 +1,131 @@
+// $Id: peephole.c,v 1.6 2003/10/13 22:53:04 iain Exp $
+// Peephole optimiser for git
+
+#include "git.h"
+
+static Label sLastOp;
+
+extern void resetPeepholeOptimiser ()
+{
+    sLastOp = label_nop;
+}
+
+#define REPLACE_SINGLE(lastOp,thisOp,newOp) \
+    case label_ ## thisOp:                  \
+        if (sLastOp == label_ ## lastOp)    \
+        {                                   \
+            op = label_ ## newOp;           \
+            goto replaceNoOperands;         \
+        }                                   \
+        break
+
+#define CASE_NO_OPERANDS(lastOp,newOp) \
+    case label_ ## lastOp: op = label_ ## newOp; goto replaceNoOperands
+
+#define CASE_ONE_OPERAND(lastOp,newOp) \
+    case label_ ## lastOp: op = label_ ## newOp; goto replaceOneOperand
+
+#define REPLACE_STORE(storeOp) \
+    case label_ ## storeOp:                                             \
+        switch(sLastOp)                                                 \
+        {                                                               \
+            CASE_NO_OPERANDS (add_discard,      add_ ## storeOp);       \
+            CASE_NO_OPERANDS (sub_discard,      sub_ ## storeOp);       \
+            CASE_NO_OPERANDS (mul_discard,      mul_ ## storeOp);       \
+            CASE_NO_OPERANDS (div_discard,      div_ ## storeOp);       \
+            CASE_NO_OPERANDS (mod_discard,      mod_ ## storeOp);       \
+            CASE_NO_OPERANDS (neg_discard,      neg_ ## storeOp);       \
+            CASE_NO_OPERANDS (bitand_discard,   bitand_ ## storeOp);    \
+            CASE_NO_OPERANDS (bitor_discard,    bitor_ ## storeOp);     \
+            CASE_NO_OPERANDS (bitxor_discard,   bitxor_ ## storeOp);    \
+            CASE_NO_OPERANDS (bitnot_discard,   bitnot_ ## storeOp);    \
+            CASE_NO_OPERANDS (shiftl_discard,   shiftl_ ## storeOp);    \
+            CASE_NO_OPERANDS (sshiftr_discard,  sshiftr_ ## storeOp);   \
+            CASE_NO_OPERANDS (ushiftr_discard,  ushiftr_ ## storeOp);   \
+            CASE_NO_OPERANDS (copys_discard,    copys_ ## storeOp);     \
+            CASE_NO_OPERANDS (copyb_discard,    copyb_ ## storeOp);     \
+            CASE_NO_OPERANDS (sexs_discard,     sexs_ ## storeOp);      \
+            CASE_NO_OPERANDS (sexb_discard,     sexb_ ## storeOp);      \
+            CASE_NO_OPERANDS (aload_discard,    aload_ ## storeOp);     \
+            CASE_NO_OPERANDS (aloads_discard,   aloads_ ## storeOp);    \
+            CASE_NO_OPERANDS (aloadb_discard,   aloadb_ ## storeOp);    \
+            CASE_NO_OPERANDS (aloadbit_discard, aloadbit_ ## storeOp);  \
+            default: break;                                             \
+        }                                                               \
+        break
+
+#define REPLACE_L1_L2(mode2)                                    \
+    case label_L2_ ## mode2:                                    \
+        switch(sLastOp)                                         \
+        {                                                       \
+            CASE_ONE_OPERAND (L1_const, L1_const_L2_ ## mode2); \
+            CASE_NO_OPERANDS (L1_stack, L1_stack_L2_ ## mode2); \
+            CASE_ONE_OPERAND (L1_local, L1_local_L2_ ## mode2); \
+            CASE_ONE_OPERAND (L1_addr,  L1_addr_L2_ ## mode2);  \
+            default: break;                                     \
+        }                                                       \
+        break
+
+#define REPLACE_LOAD_OP(loadOp,reg)                                         \
+    case label_ ## loadOp:                                                  \
+        switch(sLastOp)                                                     \
+        {                                                                   \
+            CASE_ONE_OPERAND (reg ## _const, loadOp ## _ ## reg ## _const); \
+            CASE_NO_OPERANDS (reg ## _stack, loadOp ## _ ## reg ## _stack); \
+            CASE_ONE_OPERAND (reg ## _local, loadOp ## _ ## reg ## _local); \
+            CASE_ONE_OPERAND (reg ## _addr,  loadOp ## _ ## reg ## _addr);  \
+            default: break;                                                 \
+        }                                                                   \
+        break
+
+extern void emitCode (Label op)
+{
+    git_uint32 temp;
+
+    if (gPeephole)
+    {
+        switch (op)
+        {
+            REPLACE_SINGLE (args_stack, call_stub_discard, args_stack_call_stub_discard);
+            REPLACE_SINGLE (args_stack, call_stub_addr,    args_stack_call_stub_addr);
+            REPLACE_SINGLE (args_stack, call_stub_local,   args_stack_call_stub_local);
+            REPLACE_SINGLE (args_stack, call_stub_stack,   args_stack_call_stub_stack);
+
+            REPLACE_STORE (S1_stack);
+            REPLACE_STORE (S1_local);
+            REPLACE_STORE (S1_addr);
+
+            REPLACE_L1_L2 (const);
+            REPLACE_L1_L2 (stack);
+            REPLACE_L1_L2 (local);
+            REPLACE_L1_L2 (addr);
+
+            REPLACE_LOAD_OP (return, L1);
+            REPLACE_LOAD_OP (astore, L3);
+            REPLACE_LOAD_OP (astores, L3);
+            REPLACE_LOAD_OP (astoreb, L3);
+            REPLACE_LOAD_OP (astorebit, L3);
+            
+            default: break;
+        }
+    }
+    goto noPeephole;
+
+replaceOneOperand:
+    // The previous opcode has one operand, so
+    // we have to go back two steps to update it.
+    temp = undoEmit();  // Save the operand.
+    undoEmit();         // Remove the old opcode.
+    emitFinalCode (op); // Emit the new opcode.
+    emitData (temp);    // Emit the operand again.
+    goto done;
+
+replaceNoOperands:
+    undoEmit();
+    // ... fall through
+noPeephole:
+    emitFinalCode (op);
+    // ... fall through
+done:
+    sLastOp = op;
+}