Fix a bunch of issues with pushing and popping mismatched sizes, which the B
authorDavid Given <dg@cowlark.com>
Sat, 7 Jan 2017 17:47:00 +0000 (18:47 +0100)
committerDavid Given <dg@cowlark.com>
Sat, 7 Jan 2017 17:47:00 +0000 (18:47 +0100)
compiler does a lot; dup 8 for pairs of words is now optimised.

mach/proto/mcg/treebuilder.c

index 5b2a1b9..667562e 100644 (file)
@@ -30,6 +30,18 @@ static void push(struct ir* ir)
     stack[stackptr++] = ir;
 }
 
+/* Returns the size of the top item on the stack. */
+static int peek(int delta)
+{
+    if (stackptr <= delta)
+        return EM_wordsize;
+    else
+    {
+        struct ir* ir = stack[stackptr-1-delta];
+        return ir->size;
+    }
+}
+
 static struct ir* pop(int size)
 {
     if (size < EM_wordsize)
@@ -58,7 +70,6 @@ static struct ir* pop(int size)
         if (size < EM_wordsize)
             ir = convertu(ir, size);
 #endif
-
         if (ir->size != size)
         {
             if ((size == (EM_wordsize*2)) && (ir->size == EM_wordsize))
@@ -875,17 +886,17 @@ static void insn_ivalue(int opcode, arith value)
             struct ir* ptr = pop(EM_pointersize);
             int offset = 0;
 
-            /* FIXME: this is awful; need a better way of dealing with
-             * non-standard EM sizes. */
             if (value > (EM_wordsize*2))
+            {
+                /* We're going to need to do multiple stores; fix the address
+                 * so it'll go into a register and we can do maths on it. */
                 appendir(ptr);
+            }
 
             while (value > 0)
             {
-                int s;
-                if (value > (EM_wordsize*2))
-                    s = EM_wordsize*2;
-                else
+                int s = EM_wordsize*2;
+                if (value < s)
                     s = value;
 
                 push(
@@ -934,24 +945,25 @@ static void insn_ivalue(int opcode, arith value)
             struct ir* ptr = pop(EM_pointersize);
             int offset = 0;
 
-            /* FIXME: this is awful; need a better way of dealing with
-             * non-standard EM sizes. */
-            if (value > (EM_wordsize*2))
+            if (value > peek(0))
+            {
+                /* We're going to need to do multiple stores; fix the address
+                 * so it'll go into a register and we can do maths on it. */
                 appendir(ptr);
+            }
 
             while (value > 0)
             {
-                int s;
-                if (value > (EM_wordsize*2))
-                    s = EM_wordsize*2;
-                else
+                struct ir* v = pop(peek(0));
+                int s = v->size;
+                if (value < s)
                     s = value;
 
                 appendir(
                     store(
                         s,
                         ptr, offset,
-                        pop(s)
+                        v
                     )
                 );
 
@@ -1044,10 +1056,22 @@ static void insn_ivalue(int opcode, arith value)
             
         case op_dup:
         {
-            struct ir* v = pop(value);
-            appendir(v);
-            push(v);
-            push(v);
+            sequence_point();
+            if ((value == (EM_wordsize*2)) && (peek(0) == EM_wordsize) && (peek(1) == EM_wordsize))
+            {
+                struct ir* v1 = pop(EM_wordsize);
+                struct ir* v2 = pop(EM_wordsize);
+                push(v2);
+                push(v1);
+                push(v2);
+                push(v1);
+            }
+            else
+            {
+                struct ir* v = pop(value);
+                push(v);
+                push(v);
+            }
             break;
         }
 
@@ -1077,8 +1101,11 @@ static void insn_ivalue(int opcode, arith value)
                 default:
                     while ((value > 0) && (stackptr > 0))
                     {
-                        struct ir* ir = pop(stack[stackptr-1]->size);
-                        value -= ir->size;
+                        int s = peek(0);
+                        if (s > value)
+                            s = value;
+                        pop(s);
+                        value -= s;
                     }
 
                     if (value != 0)