Merge change 6658

* changes:
  Finish implementing x86 floating point
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index adc8609..c2dea56 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1213,7 +1213,19 @@
 
         /* l = 0: je, l == 1: jne */
         virtual int gtst(bool l, int t) {
-            o(0x0fc085); /* test %eax, %eax, je/jne xxx */
+            Type* pR0Type = getR0Type();
+            TypeTag tagR0 = pR0Type->tag;
+            bool isFloatR0 = isFloatTag(tagR0);
+            if (isFloatR0) {
+                o(0xeed9); // fldz
+                o(0xe9da); // fucompp
+                o(0xe0df); // fnstsw %ax
+                o(0x9e);   // sahf
+            } else {
+                o(0xc085); // test %eax, %eax
+            }
+            // Use two output statements to generate one instruction.
+            o(0x0f);   // je/jne xxx
             return psym(0x84 + l, t);
         }
 
@@ -1327,8 +1339,6 @@
             }
         }
 
-
-
         virtual void gUnaryCmp(int op, Type* pResultType) {
             if (op != OP_LOGICAL_NOT) {
                 error("Unknown unary cmp %d", op);
@@ -1411,7 +1421,7 @@
                     o(0x241cdd); // fstpl 0(%esp)
                     break;
                 default:
-                    error("pushR0 %d", r0ct);
+                    error("pushR0 unsupported type %d", r0ct);
                     break;
             }
             pushType();
@@ -1444,16 +1454,22 @@
             assert(pPointerType->tag == TY_POINTER);
             switch (pPointerType->pHead->tag) {
                 case TY_INT:
-                    o(0x8b); /* mov (%eax), %eax */
+                    o2(0x008b); /* mov (%eax), %eax */
                     break;
                 case TY_CHAR:
                     o(0xbe0f); /* movsbl (%eax), %eax */
+                    ob(0); /* add zero in code */
+                    break;
+                case TY_FLOAT:
+                    o2(0x00d9); // flds (%eax)
+                    break;
+                case TY_DOUBLE:
+                    o2(0x00dd); // fldl (%eax)
                     break;
                 default:
                     error("loadR0FromR0: unsupported type");
                     break;
             }
-            ob(0); /* add zero in code */
             setR0Type(pPointerType->pHead);
         }
 
@@ -1704,6 +1720,13 @@
             }
         }
 
+        /* Output exactly 2 bytes
+         */
+        void o2(int n) {
+            ob(n & 0xff);
+            ob(0xff & (n >> 8));
+        }
+
         /* psym is used to put an instruction with a data field which is a
          reference to a symbol. It is in fact the same as oad ! */
         int psym(int n, int t) {
@@ -3197,6 +3220,7 @@
             /* push args and invert order */
             a = pGen->beginFunctionCallArguments();
             int l = 0;
+            int argCount = 0;
             while (tok != ')' && tok != EOF) {
                 if (! varArgs && !pArgList) {
                     error ("Unexpected argument.");
@@ -3212,16 +3236,22 @@
                         pTargetType = mkpDouble;
                     }
                 }
-                pGen->convertR0(pTargetType);
-                l += pGen->storeR0ToArg(l);
+                if (pTargetType->tag == TY_VOID) {
+                    error("Can't pass void value for argument %d",
+                          argCount + 1);
+                } else {
+                    pGen->convertR0(pTargetType);
+                    l += pGen->storeR0ToArg(l);
+                }
                 if (accept(',')) {
                     // fine
                 } else if ( tok != ')') {
                     error("Expected ',' or ')'");
                 }
+                argCount += 1;
             }
             if (! varArgs && pArgList) {
-                error ("Expected more argument(s).");
+                error ("Expected more argument(s). Saw %d", argCount);
             }
             pGen->endFunctionCallArguments(a, l);
             skip(')');
@@ -3353,7 +3383,15 @@
             if (accept(TOK_RETURN)) {
                 if (tok != ';') {
                     expr();
-                    pGen->convertR0(pReturnType);
+                    if (pReturnType->tag == TY_VOID) {
+                        error("Must not return a value from a void function");
+                    } else {
+                        pGen->convertR0(pReturnType);
+                    }
+                } else {
+                    if (pReturnType->tag != TY_VOID) {
+                        error("Must specify a value here");
+                    }
                 }
                 rsym = pGen->gjmp(rsym); /* jmp */
             } else if (accept(TOK_BREAK)) {
diff --git a/libacc/tests/data/float.c b/libacc/tests/data/float.c
index b955238..df0de93 100644
--- a/libacc/tests/data/float.c
+++ b/libacc/tests/data/float.c
@@ -32,9 +32,13 @@
     printf("args: %g %g %g %g\n", arg0, arg1, arg2, arg3);
     printf("locals: %g %g %g %g\n", local0, local1, local2, local3);
 
+
+    printf("cast rval: %g %g\n", * (float*) & f1, * (double*) & d1);
+
     * (float*) & f0 = 1.1f;
     * (double*) & d0 = 3.3;
-    printf("pointer tests: %g %g %g %g\n", f0, f1, d0, d1);
+    printf("cast lval: %g %g %g %g\n", f0, f1, d0, d1);
+
 }
 
 int main() {
diff --git a/libacc/tests/data/flops.c b/libacc/tests/data/flops.c
index 347c665..dc36e93 100644
--- a/libacc/tests/data/flops.c
+++ b/libacc/tests/data/flops.c
@@ -106,10 +106,21 @@
     comparisonOpsdi();
 }
 
+int branch(double d) {
+    if (d) {
+        return 1;
+    }
+    return 0;
+}
+
+void testBranching() {
+    printf("branching: %d %d %d\n", branch(-1.0), branch(0.0), branch(1.0));
+}
 
 int main() {
     unaryOps();
     binaryOps();
     comparisonOps();
+    testBranching();
     return 0;
 }