From 45431bc2528246f829383abda8c2cd72c57fcb65 Mon Sep 17 00:00:00 2001 From: Jack Palevich Date: Mon, 13 Jul 2009 15:57:26 -0700 Subject: [PATCH] Implement general casts and pointer dereferencing. Prior to this casts and pointer dereferencing were special-cased. --- libacc/acc.cpp | 61 +++++++-------- libacc/tests/data/casts.c | 85 +++++++++++++++++++++ libacc/tests/test.py | 152 +++++++++++++++++++++----------------- 3 files changed, 197 insertions(+), 101 deletions(-) create mode 100644 libacc/tests/data/casts.c diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 219a43690..fb7ec80bc 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -1019,6 +1019,7 @@ class Compiler : public ErrorSink { LOG_API("storeR0(%d);\n", ea); TypeTag tag = pType->tag; switch (tag) { + case TY_POINTER: case TY_INT: case TY_FLOAT: if (ea > -LOCAL && ea < LOCAL) { @@ -2027,6 +2028,7 @@ class Compiler : public ErrorSink { TypeTag tag = pType->tag; switch (tag) { case TY_INT: + case TY_POINTER: gmov(6, ea); /* mov %eax, EA */ break; case TY_FLOAT: @@ -3663,41 +3665,34 @@ class Compiler : public ErrorSink { pGen->genUnaryOp(a); } } else if (t == '(') { - expr(); - skip(')'); - } else if (t == '*') { - /* This is a pointer dereference, but we currently only - * support a pointer dereference if it's immediately - * in front of a cast. So parse the cast right here. - */ - skip('('); - Type* pCast = expectCastTypeDeclaration(mLocalArena); - // We currently only handle 3 types of cast: - // (int*), (char*) , (int (*)()) - if(typeEqual(pCast, mkpIntPtr)) { - t = TOK_INT; - } else if (typeEqual(pCast, mkpCharPtr)) { - t = TOK_CHAR; - } else if (typeEqual(pCast, mkpFloatPtr)) { - t = TOK_FLOAT; - } else if (typeEqual(pCast, mkpDoublePtr)) { - t = TOK_DOUBLE; - } else if (typeEqual(pCast, mkpPtrIntFn)){ - t = 0; + // It's either a cast or an expression + Type* pCast = acceptCastTypeDeclaration(mLocalArena); + if (pCast) { + skip(')'); + unary(false); + pGen->convertR0(pCast); } else { - String buffer; - decodeType(buffer, pCast); - error("Unsupported cast type %s", buffer.getUnwrapped()); - decodeType(buffer, mkpPtrIntFn); - } - skip(')'); - unary(false); - if (accept('=')) { - pGen->pushR0(); expr(); - pGen->storeR0ToTOS(pCast); - } else if (t) { - pGen->loadR0FromR0(pCast); + skip(')'); + } + } else if (t == '*') { + /* This is a pointer dereference. + */ + unary(false); + Type* pR0Type = pGen->getR0Type(); + if (pR0Type->tag != TY_POINTER) { + error("Expected a pointer type."); + } else { + if (pR0Type->pHead->tag == TY_FUNC) { + t = 0; + } + if (accept('=')) { + pGen->pushR0(); + expr(); + pGen->storeR0ToTOS(pR0Type); + } else if (t) { + pGen->loadR0FromR0(pR0Type); + } } // Else we fall through to the function call below, with // t == 0 to trigger an indirect function call. Hack! diff --git a/libacc/tests/data/casts.c b/libacc/tests/data/casts.c new file mode 100644 index 000000000..d3a49b4cf --- /dev/null +++ b/libacc/tests/data/casts.c @@ -0,0 +1,85 @@ +void test1() { + int a = 3; + int* pb = &a; + int c = *pb; + printf("Reading from a pointer: %d %d\n", a, c); + *pb = 4; + printf("Writing to a pointer: %d\n", a); + printf("Testing casts: %d %g %g %d\n", 3, (float) 3, 4.5, (int) 4.5); +} + +void test2() { + int x = 4; + int px = &x; + // int z = * px; // An error, expected a pointer type + int y = * (int*) px; + printf("Testing reading (int*): %d\n", y); +} + +void test3() { + int px = (int) malloc(120); + * (int*) px = 8; + * (int*) (px + 4) = 9; + printf("Testing writing (int*): %d %d\n", * (int*) px, * (int*) (px + 4)); + free((void*) px); +} + +void test4() { + int x = 0x12345678; + int px = &x; + int a = * (char*) px; + int b = * (char*) (px + 1); + int c = * (char*) (px + 2); + int d = * (char*) (px + 3); + printf("Testing reading (char*): 0x%02x 0x%02x 0x%02x 0x%02x\n", a, b, c, d); +} + +void test5() { + int x = 0xFFFFFFFF; + int px = &x; + * (char*) px = 0x21; + * (char*) (px + 1) = 0x43; + * (char*) (px + 2) = 0x65; + * (char*) (px + 3) = 0x87; + printf("Testing writing (char*): 0x%08x\n", x); +} + +int f(int b) { + printf("f(%d)\n", b); + return 7 * b; +} + +void test6() { + int fp = &f; + int x = (*(int(*)()) fp)(10); + printf("Function pointer result: %d\n", x); +} + +void test7() { + int px = (int) malloc(120); + * (float*) px = 8.8f; + * (float*) (px + 4) = 9.9f; + printf("Testing read/write (float*): %g %g\n", * (float*) px, * (float*) (px + 4)); + free((void*) px); +} + +void test8() { + int px = (int) malloc(120); + * (double*) px = 8.8; + * (double*) (px + 8) = 9.9; + printf("Testing read/write (double*): %g %g\n", * (double*) px, * (double*) (px + 8)); + free((void*) px); +} + + +int main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + return 0; +} diff --git a/libacc/tests/test.py b/libacc/tests/test.py index 991c7ded6..702f49df7 100644 --- a/libacc/tests/test.py +++ b/libacc/tests/test.py @@ -77,7 +77,14 @@ def firstDifference(a, b): return i return commonLen -def compareSet(a1,a2,b1,b2): +# a1 and a2 are the expected stdout and stderr. +# b1 and b2 are the actual stdout and stderr. +# Compare the two, sets. Allow any individual line +# to appear in either stdout or stderr. This is because +# the way we obtain output on the ARM combines both +# streams into one sequence. + +def compareOuput(a1,a2,b1,b2): while True: totalLen = len(a1) + len(a2) + len(b1) + len(b2) a1, b1 = matchCommon(a1, b1) @@ -96,6 +103,8 @@ def compareSet(a1,a2,b1,b2): return False def matchCommon(a, b): + """Remove common items from the beginning of a and b, + return just the tails that are different.""" while len(a) > 0 and len(b) > 0 and a[0] == b[0]: a = a[1:] b = b[1:] @@ -105,25 +114,20 @@ def rewritePaths(args): return [rewritePath(x) for x in args] def rewritePath(p): + """Take a path that's correct on the x86 and convert to a path + that's correct on ARM.""" if p.startswith("data/"): p = "/system/bin/accdata/" + p return p class TestACC(unittest.TestCase): - - def compileCheckOld(self, args, stdErrResult, stdOutResult=""): - out, err = compile(args) - compare(out, stdOutResult) - compare(err, stdErrResult) - self.assertEqual(out, stdOutResult) - self.assertEqual(err, stdErrResult) def checkResult(self, out, err, stdErrResult, stdOutResult=""): a1 = out.splitlines() a2 = err.splitlines() b2 = stdErrResult.splitlines() b1 = stdOutResult.splitlines() - self.assertEqual(True, compareSet(a1,a2,b1,b2)) + self.assertEqual(True, compareOuput(a1,a2,b1,b2)) def compileCheck(self, args, stdErrResult, stdOutResult="", targets=['arm', 'x86']): @@ -174,65 +178,77 @@ class TestACC(unittest.TestCase): def testRunFlops(self): self.compileCheck(["-R", "data/flops.c"], - "Executing compiled code:\nresult: 0\n", - "-1.1 = -1.1\n" + - "!1.2 = 0\n" + - "!0 = 1\n" + - "double op double:\n" + - "1 + 2 = 3\n" + - "1 - 2 = -1\n" + - "1 * 2 = 2\n" + - "1 / 2 = 0.5\n" + - "float op float:\n" + - "1 + 2 = 3\n" + - "1 - 2 = -1\n" + - "1 * 2 = 2\n" + - "1 / 2 = 0.5\n" + - "double op float:\n" + - "1 + 2 = 3\n" + - "1 - 2 = -1\n" + - "1 * 2 = 2\n" + - "1 / 2 = 0.5\n" + - "double op int:\n" + - "1 + 2 = 3\n" + - "1 - 2 = -1\n" + - "1 * 2 = 2\n" + - "1 / 2 = 0.5\n" + - "int op double:\n" + - "1 + 2 = 3\n" + - "1 - 2 = -1\n" + - "1 * 2 = 2\n" + - "1 / 2 = 0.5\n" + - "double op double:\n" + - "1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1\n" + - "1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0\n" + - "2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1\n" + - "double op float:\n" + - "1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1\n" + - "1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0\n" + - "2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1\n" + - "float op float:\n" + - "1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1\n" + - "1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0\n" + - "2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1\n" + - "int op double:\n" + - "1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1\n" + - "1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0\n" + - "2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1\n" + - "double op int:\n" + - "1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1\n" + - "1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0\n" + - "2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1\n" + - "branching: 1 0 1\n" + - "testpassi: 1 2 3 4 5 6 7 8\n" + - "testpassf: 1 2 3 4 5 6 7 8\n" + - "testpassd: 1 2 3 4 5 6 7 8\n" + - "testpassidf: 1 2 3\n" - ) - - def oldtestArmRunReturnVal(self): - self.compileCheckArm(["-R", "/system/bin/accdata/data/returnval-ansi.c"], - "Executing compiled code:\nresult: 42\n") + """Executing compiled code: +result: 0""", +"""-1.1 = -1.1 +!1.2 = 0 +!0 = 1 +double op double: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +float op float: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +double op float: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +double op int: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +int op double: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +double op double: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +double op float: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +float op float: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +int op double: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +double op int: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +branching: 1 0 1 +testpassi: 1 2 3 4 5 6 7 8 +testpassf: 1 2 3 4 5 6 7 8 +testpassd: 1 2 3 4 5 6 7 8 +testpassidf: 1 2 3 +""") + def testCasts(self): + self.compileCheck(["-R", "data/casts.c"], + """Executing compiled code: +result: 0""", """Reading from a pointer: 3 3 +Writing to a pointer: 4 +Testing casts: 3 3 4.5 4 +Testing reading (int*): 4 +Testing writing (int*): 8 9 +Testing reading (char*): 0x78 0x56 0x34 0x12 +Testing writing (char*): 0x87654321 +f(10) +Function pointer result: 70 +Testing read/write (float*): 8.8 9.9 +Testing read/write (double*): 8.8 9.9 +""") if __name__ == '__main__': if not outputCanRun():