Code generator cleanup

Factor ARM integer binary operation setup code into a function.

Don't pass redundant pType information into loadR0FromR0, storeR0ToTOS,
gcmp, gUnaryCmp, li

Separate inc/dec from variable loading. Generates worse code, but now
we handle pointer inc/dec and char inc/dec.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index e097608..bf48490 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -282,6 +282,11 @@
             }
         }
 
+        /* Give the code generator some utility types so it can
+         * use its own types as needed for the results of some
+         * operations like gcmp.
+         */
+
         void setTypes(Type* pInt) {
             mkpInt = pInt;
         }
@@ -312,7 +317,7 @@
                                   int localVariableSize) = 0;
 
         /* load immediate value to R0 */
-        virtual void li(int i, Type* pType) = 0;
+        virtual void li(int i) = 0;
 
         /* Load floating point value from global address. */
         virtual void loadFloat(int address, Type* pType) = 0;
@@ -333,7 +338,7 @@
          * Pops TOS.
          * op specifies the comparison.
          */
-        virtual void gcmp(int op, Type* pResultType) = 0;
+        virtual void gcmp(int op) = 0;
 
         /* Perform the arithmetic op specified by op. TOS is the
          * left argument, R0 is the right argument.
@@ -344,7 +349,7 @@
         /* Compare 0 against R0, and store the boolean result in R0.
          * op specifies the comparison.
          */
-        virtual void gUnaryCmp(int op, Type* pResultType) = 0;
+        virtual void gUnaryCmp(int op) = 0;
 
         /* Perform the arithmetic op specified by op. 0 is the
          * left argument, R0 is the right argument.
@@ -355,16 +360,18 @@
          */
         virtual void pushR0() = 0;
 
+        /* Pop R0 from the stack.
+         */
+        virtual void popR0() = 0;
+
         /* Store R0 to the address stored in TOS.
          * The TOS is popped.
-         * pPointerType is the type of the pointer (of the input R0).
          */
-        virtual void storeR0ToTOS(Type* pPointerType) = 0;
+        virtual void storeR0ToTOS() = 0;
 
         /* Load R0 from the address stored in R0.
-         * pPointerType is the type of the pointer (of the input R0).
          */
-        virtual void loadR0FromR0(Type* pPointerType) = 0;
+        virtual void loadR0FromR0() = 0;
 
         /* Load the absolute address of a variable to R0.
          * If ea <= LOCAL, then this is a local variable, or an
@@ -384,11 +391,8 @@
          * If ea <= LOCAL, then this is a local variable, or an
          * argument, addressed relative to FP.
          * else it is an absolute global address.
-         * If isIncDec is true, then the stored variable's value
-         * should be post-incremented or post-decremented, based
-         * on the value of op.
          */
-        virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
+        virtual void loadR0(int ea, Type* pType) = 0;
 
         /**
          * Convert R0 to the given type.
@@ -636,9 +640,9 @@
         }
 
         /* load immediate value */
-        virtual void li(int t, Type* pType) {
+        virtual void li(int t) {
             liReg(t, 0);
-            setR0Type(pType);
+            setR0Type(mkpInt);
         }
 
         virtual void loadFloat(int address, Type* pType) {
@@ -685,14 +689,13 @@
             return o4(branch | encodeAddress(t));
         }
 
-        virtual void gcmp(int op, Type* pResultType) {
+        virtual void gcmp(int op) {
             Type* pR0Type = getR0Type();
             Type* pTOSType = getTOSType();
             TypeTag tagR0 = collapseType(pR0Type->tag);
             TypeTag tagTOS = collapseType(pTOSType->tag);
             if (tagR0 == TY_INT && tagTOS == TY_INT) {
-                o4(0xE8BD0002);  // ldmfd   sp!,{r1}
-                mStackUse -= 4;
+                setupIntPtrArgs();
                 o4(0xE1510000); // cmp r1, r1
                 switch(op) {
                 case OP_EQUALS:
@@ -723,7 +726,6 @@
                     error("Unknown comparison op %d", op);
                     break;
                 }
-                popType();
             } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
                 setupDoubleArgs();
                 switch(op) {
@@ -775,7 +777,7 @@
                         break;
                 }
             }
-            setR0Type(pResultType);
+            setR0Type(mkpInt);
         }
 
         virtual void genOp(int op) {
@@ -786,6 +788,7 @@
             bool isFloatR0 = isFloatTag(tagR0);
             bool isFloatTOS = isFloatTag(tagTOS);
             if (!isFloatR0 && !isFloatTOS) {
+                setupIntPtrArgs();
                 bool isPtrR0 = tagR0 == TY_POINTER;
                 bool isPtrTOS = tagTOS == TY_POINTER;
                 if (isPtrR0 || isPtrTOS) {
@@ -796,14 +799,12 @@
                         if (! typeEqual(pR0Type, pTOSType)) {
                             error("Incompatible pointer types for subtraction.");
                         }
-                        o4(0xE8BD0002); // ldmfd   sp!,{r1}
                         o4(0xE0410000); // sub     r0,r1,r0
-                        popType();
                         setR0Type(mkpInt);
                         int size = sizeOf(pR0Type->pHead);
                         if (size != 1) {
                             pushR0();
-                            li(size, mkpInt);
+                            li(size);
                             // TODO: Optimize for power-of-two.
                             genOp(OP_DIV);
                         }
@@ -812,7 +813,6 @@
                             error("Unsupported pointer-scalar operation %d", op);
                         }
                         Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
-                        o4(0xE8BD0002); // ldmfd   sp!,{r1}
                         int size = sizeOf(pPtrType->pHead);
                         if (size != 1) {
                             // TODO: Optimize for power-of-two.
@@ -831,12 +831,9 @@
                             o4(0xE0410000); // sub     r0,r1,r0
                             break;
                         }
-                        popType();
                         setR0Type(pPtrType);
                     }
                 } else {
-                    o4(0xE8BD0002); // ldmfd   sp!,{r1}
-                mStackUse -= 4;
                     switch(op) {
                         case OP_MUL:
                         o4(0x0E0000091); // mul     r0,r1,r0
@@ -875,7 +872,6 @@
                         error("Unimplemented op %d\n", op);
                         break;
                     }
-                    popType();
                 }
             } else {
                 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
@@ -922,7 +918,7 @@
             }
         }
 
-        virtual void gUnaryCmp(int op, Type* pResultType) {
+        virtual void gUnaryCmp(int op) {
             if (op != OP_LOGICAL_NOT) {
                 error("Unknown unary cmp %d", op);
             } else {
@@ -946,7 +942,7 @@
                         break;
                 }
             }
-            setR0Type(pResultType);
+            setR0Type(mkpInt);
         }
 
         virtual void genUnaryOp(int op) {
@@ -1005,7 +1001,28 @@
             LOG_STACK("pushR0: %d\n", mStackUse);
         }
 
-        virtual void storeR0ToTOS(Type* pPointerType) {
+        virtual void popR0() {
+            Type* pTOSType = getTOSType();
+            switch (collapseType(pTOSType->tag)){
+                case TY_INT:
+                case TY_FLOAT:
+                    o4(0xE8BD0001);  // ldmfd   sp!,{r0}
+                    mStackUse -= 4;
+                    break;
+                case TY_DOUBLE:
+                    o4(0xE8BD0003);  // ldmfd   sp!,{r0, r1}  // Restore R0
+                        mStackUse -= 8;
+                    break;
+                default:
+                    error("Can't pop this type.");
+                    break;
+            }
+            popType();
+            LOG_STACK("popR0: %d\n", mStackUse);
+        }
+
+        virtual void storeR0ToTOS() {
+            Type* pPointerType = getTOSType();
             assert(pPointerType->tag == TY_POINTER);
             o4(0xE8BD0004);  // ldmfd   sp!,{r2}
             popType();
@@ -1027,7 +1044,8 @@
             }
         }
 
-        virtual void loadR0FromR0(Type* pPointerType) {
+        virtual void loadR0FromR0() {
+            Type* pPointerType = getR0Type();
             assert(pPointerType->tag == TY_POINTER);
             switch (pPointerType->pHead->tag) {
                 case TY_INT:
@@ -1149,7 +1167,7 @@
             }
         }
 
-        virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
+        virtual void loadR0(int ea, Type* pType) {
             TypeTag tag = pType->tag;
             switch (tag) {
                 case TY_CHAR:
@@ -1170,10 +1188,6 @@
                         o4(ea);         // .L1:   .word ea
                         o4(0xE5D20000); // .L99:  ldrb r0, [r2]
                     }
-
-                    if (isIncDec) {
-                        error("inc/dec not implemented for char.");
-                    }
                     break;
                 case TY_POINTER:
                 case TY_INT:
@@ -1195,37 +1209,6 @@
                         o4(ea);         // .L1:   .word ea
                         o4(0xE5920000); // .L99:  ldr r0, [r2]
                     }
-
-                    if (isIncDec) {
-                        if (tag == TY_INT) {
-                            switch (op) {
-                            case OP_INCREMENT:
-                                o4(0xE2801001); // add r1, r0, #1
-                                break;
-                            case OP_DECREMENT:
-                                o4(0xE2401001); // sub r1, r0, #1
-                                break;
-                            default:
-                                error("unknown opcode: %d", op);
-                            }
-                            if (ea < LOCAL) {
-                                // Local, fp relative
-                                // Don't need range check, was already checked above
-                                if (ea < 0) {
-                                    o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
-                                } else {
-                                    o4(0xE58B1000 | (0xfff & ea));    // str r1, [fp,#ea]
-                                }
-                            } else{
-                                // Global, absolute
-                                // r2 is already set up from before.
-                                o4(0xE5821000); // str r1, [r2]
-                           }
-                        }
-                        else {
-                            error("inc/dec not implemented for float.");
-                        }
-                    }
                     break;
                 case TY_DOUBLE:
                     if ((ea & 0x7) != 0) {
@@ -1563,6 +1546,12 @@
             return reg;
         }
 
+        void setupIntPtrArgs() {
+            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
+            mStackUse -= 4;
+            popType();
+        }
+
         /* Pop TOS to R1
          * Make sure both R0 and TOS are floats. (Could be ints)
          * We know that at least one of R0 and TOS is already a float
@@ -1837,9 +1826,9 @@
         }
 
         /* load immediate value */
-        virtual void li(int i, Type* pType) {
+        virtual void li(int i) {
             oad(0xb8, i); /* mov $xx, %eax */
-            setR0Type(pType);
+            setR0Type(mkpInt);
         }
 
         virtual void loadFloat(int address, Type* pType) {
@@ -1879,7 +1868,7 @@
             return psym(0x84 + l, t);
         }
 
-        virtual void gcmp(int op, Type* pResultType) {
+        virtual void gcmp(int op) {
             Type* pR0Type = getR0Type();
             Type* pTOSType = getTOSType();
             TypeTag tagR0 = pR0Type->tag;
@@ -1890,7 +1879,7 @@
                 int t = decodeOp(op);
                 o(0x59); /* pop %ecx */
                 o(0xc139); /* cmp %eax,%ecx */
-                li(0, NULL);
+                li(0);
                 o(0x0f); /* setxx %al */
                 o(t + 0x90);
                 o(0xc0);
@@ -1945,7 +1934,7 @@
                 }
                 o(0xc0b60f); // movzbl %al, %eax
             }
-            setR0Type(pResultType);
+            setR0Type(mkpInt);
         }
 
         virtual void genOp(int op) {
@@ -1973,7 +1962,7 @@
                         int size = sizeOf(pR0Type->pHead);
                         if (size != 1) {
                             pushR0();
-                            li(size, mkpInt);
+                            li(size);
                             // TODO: Optimize for power-of-two.
                             genOp(OP_DIV);
                         }
@@ -2028,7 +2017,7 @@
             }
         }
 
-        virtual void gUnaryCmp(int op, Type* pResultType) {
+        virtual void gUnaryCmp(int op) {
             if (op != OP_LOGICAL_NOT) {
                 error("Unknown unary cmp %d", op);
             } else {
@@ -2039,7 +2028,7 @@
                             oad(0xb9, 0); /* movl $0, %ecx */
                             int t = decodeOp(op);
                             o(0xc139); /* cmp %eax,%ecx */
-                            li(0, NULL);
+                            li(0);
                             o(0x0f); /* setxx %al */
                             o(t + 0x90);
                             o(0xc0);
@@ -2062,7 +2051,7 @@
                         break;
                 }
             }
-            setR0Type(pResultType);
+            setR0Type(mkpInt);
         }
 
         virtual void genUnaryOp(int op) {
@@ -2116,7 +2105,31 @@
             pushType();
         }
 
-        virtual void storeR0ToTOS(Type* pPointerType) {
+        virtual void popR0() {
+            Type* pR0Type = getR0Type();
+            TypeTag r0ct = collapseType(pR0Type->tag);
+            switch(r0ct) {
+                case TY_INT:
+                    o(0x58); /* popl %eax */
+                    break;
+                case TY_FLOAT:
+                    o(0x2404d9); // flds (%esp)
+                    o(0x58); /* popl %eax */
+                    break;
+                case TY_DOUBLE:
+                    o(0x2404dd); // fldl (%esp)
+                    o(0x58); /* popl %eax */
+                    o(0x58); /* popl %eax */
+                    break;
+                default:
+                    error("pushR0 unsupported type %d", r0ct);
+                    break;
+            }
+            popType();
+        }
+
+        virtual void storeR0ToTOS() {
+            Type* pPointerType = getTOSType();
             assert(pPointerType->tag == TY_POINTER);
             Type* pTargetType = pPointerType->pHead;
             convertR0(pTargetType);
@@ -2141,7 +2154,8 @@
             }
         }
 
-        virtual void loadR0FromR0(Type* pPointerType) {
+        virtual void loadR0FromR0() {
+            Type* pPointerType = getR0Type();
             assert(pPointerType->tag == TY_POINTER);
             switch (pPointerType->pHead->tag) {
                 case TY_INT:
@@ -2204,7 +2218,7 @@
             }
         }
 
-        virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
+        virtual void loadR0(int ea, Type* pType) {
             TypeTag tag = pType->tag;
             switch (tag) {
                 case TY_CHAR:
@@ -2213,22 +2227,10 @@
                     } else {
                         oad(0x85BE0F, ea); // movsbl  ea(%ebp),%eax
                     }
-                    if (isIncDec) {
-                        error("inc/dec not implemented for char.");
-                    }
                     break;
                 case TY_INT:
                 case TY_POINTER:
-                    if (tag == TY_CHAR) {
-                    } else {
-                        gmov(8, ea); /* mov EA, %eax */
-                    }
-                    if (isIncDec) {
-                        /* Implement post-increment or post decrement.
-                         */
-                        gmov(0, ea); /* 83 ADD */
-                        o(decodeOp(op));
-                    }
+                    gmov(8, ea); /* mov EA, %eax */
                     break;
                 case TY_FLOAT:
                     if (ea < -LOCAL || ea > LOCAL) {
@@ -2236,9 +2238,6 @@
                     } else {
                         oad(0x85d9, ea); // flds ea(%ebp)
                     }
-                    if (isIncDec) {
-                        error("inc/dec not implemented for float.");
-                    }
                     break;
                 case TY_DOUBLE:
                     if (ea < -LOCAL || ea > LOCAL) {
@@ -2246,9 +2245,6 @@
                     } else {
                         oad(0x85dd, ea); // fldl ea(%ebp)
                     }
-                    if (isIncDec) {
-                        error("inc/dec not implemented for double.");
-                    }
                     break;
                 default:
                     error("Unable to load type %d", tag);
@@ -2535,9 +2531,9 @@
         }
 
         /* load immediate value */
-        virtual void li(int t, Type* pType) {
+        virtual void li(int t) {
             fprintf(stderr, "li(%d)\n", t);
-            mpBase->li(t, pType);
+            mpBase->li(t);
         }
 
         virtual void loadFloat(int address, Type* pType) {
@@ -2558,9 +2554,9 @@
             return result;
         }
 
-        virtual void gcmp(int op, Type* pResultType) {
-            fprintf(stderr, "gcmp(%d, pResultType)\n", op);
-            mpBase->gcmp(op, pResultType);
+        virtual void gcmp(int op) {
+            fprintf(stderr, "gcmp(%d)\n", op);
+            mpBase->gcmp(op);
         }
 
         virtual void genOp(int op) {
@@ -2569,9 +2565,9 @@
         }
 
 
-        virtual void gUnaryCmp(int op, Type* pResultType) {
-            fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
-            mpBase->gUnaryCmp(op, pResultType);
+        virtual void gUnaryCmp(int op) {
+            fprintf(stderr, "gUnaryCmp(%d)\n", op);
+            mpBase->gUnaryCmp(op);
         }
 
         virtual void genUnaryOp(int op) {
@@ -2584,14 +2580,19 @@
             mpBase->pushR0();
         }
 
-        virtual void storeR0ToTOS(Type* pPointerType) {
-            fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
-            mpBase->storeR0ToTOS(pPointerType);
+        virtual void popR0() {
+            fprintf(stderr, "popR0()\n");
+            mpBase->popR0();
         }
 
-        virtual void loadR0FromR0(Type* pPointerType) {
-            fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
-            mpBase->loadR0FromR0(pPointerType);
+        virtual void storeR0ToTOS() {
+            fprintf(stderr, "storeR0ToTOS()\n");
+            mpBase->storeR0ToTOS();
+        }
+
+        virtual void loadR0FromR0() {
+            fprintf(stderr, "loadR0FromR0()\n");
+            mpBase->loadR0FromR0();
         }
 
         virtual void leaR0(int ea, Type* pPointerType) {
@@ -2604,9 +2605,9 @@
             mpBase->storeR0(ea, pType);
         }
 
-        virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
-            fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
-            mpBase->loadR0(ea, isIncDec, op, pType);
+        virtual void loadR0(int ea, Type* pType) {
+            fprintf(stderr, "loadR0(%d, pType)\n", ea);
+            mpBase->loadR0(ea, pType);
         }
 
         virtual void convertR0(Type* pType){
@@ -3814,7 +3815,7 @@
 
     bool acceptStringLiteral() {
         if (tok == '"') {
-            pGen->li((int) glo, mkpCharPtr);
+            pGen->leaR0((int) glo, mkpCharPtr);
             // This while loop merges multiple adjacent string constants.
             while (tok == '"') {
                 while (ch != '"' && ch != EOF) {
@@ -3869,7 +3870,7 @@
             t = tok;
             next();
             if (t == TOK_NUM) {
-                pGen->li(a, mkpInt);
+                pGen->li(a);
             } else if (t == TOK_NUM_FLOAT) {
                 // Align to 4-byte boundary
                 glo = (char*) (((intptr_t) glo + 3) & -4);
@@ -3886,7 +3887,7 @@
                 /* -, +, !, ~ */
                 unary(false);
                 if (t == '!')
-                    pGen->gUnaryCmp(a, mkpInt);
+                    pGen->gUnaryCmp(a);
                 else if (t == '+') {
                     // ignore unary plus.
                 } else {
@@ -3917,9 +3918,9 @@
                     if (accept('=')) {
                         pGen->pushR0();
                         expr();
-                        pGen->storeR0ToTOS(pR0Type);
+                        pGen->storeR0ToTOS();
                     } else if (t) {
-                        pGen->loadR0FromR0(pR0Type);
+                        pGen->loadR0FromR0();
                     }
                 }
                 // Else we fall through to the function call below, with
@@ -3965,8 +3966,14 @@
                             error("Undeclared variable %s\n", nameof(t));
                         }
                     }
-                    pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
+                    // load a variable
+                    pGen->loadR0(n, pVI->pType);
                     if (tokl == 11) {
+                        // post inc / post dec
+                        pGen->pushR0();
+                        impInc(tokc);
+                        pGen->storeR0(n, pVI->pType);
+                        pGen->popR0();
                         next();
                     }
                 }
@@ -4037,6 +4044,28 @@
         }
     }
 
+    /* Increment / decrement R0 */
+
+    void impInc(int op) {
+        Type* pType = pGen->getR0Type();
+        int lit = 1;
+        if (op == OP_DECREMENT) {
+            lit = -1;
+        }
+        switch (pType->tag) {
+            case TY_INT:
+            case TY_CHAR:
+            case TY_POINTER:
+                pGen->pushR0();
+                pGen->li(lit);
+                pGen->genOp(OP_PLUS);
+                break;
+            default:
+                error("++/-- illegal for this type.");
+                break;
+        }
+    }
+
     /* Recursive descent parser for binary operations.
      */
     void binaryOp(int level) {
@@ -4061,10 +4090,10 @@
                     if (pGen->getR0Type() == NULL) {
                         // We failed to parse a right-hand argument.
                         // Push a dummy value so we don't fail
-                        pGen->li(0, mkpInt);
+                        pGen->li(0);
                     }
                     if ((level == 4) | (level == 5)) {
-                        pGen->gcmp(t, mkpInt);
+                        pGen->gcmp(t);
                     } else {
                         pGen->genOp(t);
                     }
@@ -4073,10 +4102,10 @@
             /* && and || output code generation */
             if (a && level > 8) {
                 a = pGen->gtst(t == OP_LOGICAL_OR, a);
-                pGen->li(t != OP_LOGICAL_OR, mkpInt);
+                pGen->li(t != OP_LOGICAL_OR);
                 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
                 pGen->gsym(a);
-                pGen->li(t == OP_LOGICAL_OR, mkpInt);
+                pGen->li(t == OP_LOGICAL_OR);
             }
         }
     }