From 9eedf0581e05033e82c5c4cdeaf3fdfa324a8256 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 18 Feb 2016 14:44:43 +0100 Subject: [PATCH 1/5] libCom/calc: Use epics(U)Int32 for all integer calculations Adapted backport of 3.15 revision 12308 --- src/libCom/calc/calcPerform.c | 43 ++++++++++++++++++----------------- src/libCom/calc/postfix.c | 27 ++++++++++++---------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 6de3f9dc6..0e8fcd5e9 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -21,6 +21,7 @@ #include "osiUnistd.h" #include "dbDefs.h" #include "epicsMath.h" +#include "epicsTypes.h" #include "errlog.h" #include "postfix.h" #include "postfixPvt.h" @@ -43,7 +44,7 @@ epicsShareFunc long double stack[CALCPERFORM_STACK+1]; /* zero'th entry not used */ double *ptop; /* stack pointer */ double top; /* value from top of stack */ - int itop; /* integer from top of stack */ + epicsInt32 itop; /* integer from top of stack */ int op; int nargs; @@ -55,14 +56,14 @@ epicsShareFunc long switch (op){ case LITERAL_DOUBLE: - memcpy((void *)++ptop, pinst, sizeof(double)); + memcpy(++ptop, pinst, sizeof(double)); pinst += sizeof(double); break; case LITERAL_INT: - memcpy(&itop, pinst, sizeof(int)); + memcpy(&itop, pinst, sizeof(epicsInt32)); *++ptop = itop; - pinst += sizeof(int); + pinst += sizeof(epicsInt32); break; case FETCH_VAL: @@ -136,11 +137,11 @@ epicsShareFunc long break; case MODULO: - itop = (long) *ptop--; + itop = (epicsInt32) *ptop--; if (itop) - *ptop = (long) *ptop % itop; + *ptop = (epicsInt32) *ptop % itop; else - *ptop = epicsNAN; /* NaN */ + *ptop = epicsNAN; break; case POWER: @@ -261,7 +262,7 @@ epicsShareFunc long case NINT: top = *ptop; - *ptop = (double)(long)(top >= 0 ? top + 0.5 : top - 0.5); + *ptop = (double)(epicsInt32)(top >= 0 ? top + 0.5 : top - 0.5); break; case RANDOM: @@ -283,33 +284,33 @@ epicsShareFunc long break; case BIT_OR: - itop = (long) *ptop--; - *ptop = (long) *ptop | itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop | itop; break; case BIT_AND: - itop = (long) *ptop--; - *ptop = (long) *ptop & itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop & itop; break; case BIT_EXCL_OR: - itop = (long) *ptop--; - *ptop = (long) *ptop ^ itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop ^ itop; break; case BIT_NOT: - itop = (long) *ptop; + itop = (epicsInt32) *ptop; *ptop = ~itop; break; case RIGHT_SHIFT: - itop = (long) *ptop--; - *ptop = (long) *ptop >> itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop >> itop; break; case LEFT_SHIFT: - itop = (long) *ptop--; - *ptop = (long) *ptop << itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop << itop; break; case NOT_EQ: @@ -381,7 +382,7 @@ calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores) pinst += sizeof(double); break; case LITERAL_INT: - pinst += sizeof(int); + pinst += sizeof(epicsInt32); break; case MIN: case MAX: @@ -468,7 +469,7 @@ static int cond_search(const char **ppinst, int match) pinst += sizeof(double); break; case LITERAL_INT: - pinst += sizeof(int); + pinst += sizeof(epicsInt32); break; case MIN: case MAX: diff --git a/src/libCom/calc/postfix.c b/src/libCom/calc/postfix.c index ca25bea42..4ad57f910 100644 --- a/src/libCom/calc/postfix.c +++ b/src/libCom/calc/postfix.c @@ -22,6 +22,7 @@ #include "dbDefs.h" #include "epicsStdlib.h" #include "epicsString.h" +#include "epicsTypes.h" #include "postfix.h" #include "postfixPvt.h" #include "shareLib.h" @@ -216,7 +217,7 @@ epicsShareFunc long char * const pdest = pout; char *pnext; double lit_d; - int lit_i; + epicsInt32 lit_i; if (psrc == NULL || *psrc == '\0' || pout == NULL || perror == NULL) { @@ -249,27 +250,29 @@ epicsShareFunc long goto bad; } psrc = pnext; - lit_i = (int) lit_d; + lit_i = (epicsInt32) lit_d; if (lit_d != (double) lit_i) { *pout++ = pel->code; - memcpy(pout, (void *)&lit_d, sizeof(double)); + memcpy(pout, &lit_d, sizeof(double)); pout += sizeof(double); } else { *pout++ = LITERAL_INT; - memcpy(pout, (void *)&lit_i, sizeof(int)); - pout += sizeof(int); + memcpy(pout, &lit_i, sizeof(epicsInt32)); + pout += sizeof(epicsInt32); } } else { - lit_i = strtoul(psrc, &pnext, 0); + epicsUInt32 lit_ui; + + lit_ui = (epicsUInt32) strtoul(psrc, &pnext, 0); if (pnext == psrc) { *perror = CALC_ERR_BAD_LITERAL; goto bad; } psrc = pnext; *pout++ = LITERAL_INT; - memcpy(pout, (void *)&lit_i, sizeof(int)); - pout += sizeof(int); + memcpy(pout, &lit_ui, sizeof(epicsUInt32)); + pout += sizeof(epicsUInt32); } operand_needed = FALSE; @@ -594,18 +597,18 @@ epicsShareFunc void }; char op; double lit_d; - int lit_i; + epicsInt32 lit_i; while ((op = *pinst) != END_EXPRESSION) { switch (op) { case LITERAL_DOUBLE: - memcpy((void *)&lit_d, ++pinst, sizeof(double)); + memcpy(&lit_d, ++pinst, sizeof(double)); printf("\tDouble %g\n", lit_d); pinst += sizeof(double); break; case LITERAL_INT: - memcpy((void *)&lit_i, ++pinst, sizeof(int)); - printf("\tInteger %d\n", lit_i); + memcpy(&lit_i, ++pinst, sizeof(epicsInt32)); + printf("\tInteger %d (0x%x)\n", lit_i, lit_i); pinst += sizeof(int); break; case MIN: From 4241b4e6cbf0f38d1b0e8ac9e82802eec3f88b12 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 18 Feb 2016 15:17:52 +0100 Subject: [PATCH 2/5] libCom/test: add calc tests for bit31 operators (lp:1514520) --- src/libCom/test/epicsCalcTest.cpp | 88 +++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index 3fee4923b..5b17694f9 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -8,6 +8,7 @@ // Author: Andrew Johnson #include "epicsUnitTest.h" +#include "epicsTypes.h" #include "epicsMath.h" #include "epicsAlgorithm.h" #include "postfix.h" @@ -38,30 +39,59 @@ void testCalc(const char *expr, double expected) { /* Evaluate expression, test against expected result */ bool pass = false; double args[CALCPERFORM_NARGS] = { - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 }; char rpn[MAX_POSTFIX_SIZE]; short err; double result = 0.0; result /= result; /* Start as NaN */ - + if (postfix(expr, rpn, &err)) { - testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr); + testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr); } else - if (calcPerform(args, &result, rpn) && finite(result)) { - testDiag("calcPerform: error evaluating '%s'", expr); - } - + if (calcPerform(args, &result, rpn) && finite(result)) { + testDiag("calcPerform: error evaluating '%s'", expr); + } + if (finite(expected) && finite(result)) { - pass = fabs(expected - result) < 1e-8; + pass = fabs(expected - result) < 1e-8; } else if (isnan(expected)) { - pass = (bool) isnan(result); + pass = (bool) isnan(result); } else { - pass = (result == expected); + pass = (result == expected); } if (!testOk(pass, "%s", expr)) { - testDiag("Expected result is %g, actually got %g", expected, result); - calcExprDump(rpn); + testDiag("Expected result is %g, actually got %g", expected, result); + calcExprDump(rpn); + } + return; +} + +void testUInt32Calc(const char *expr, epicsUInt32 expected) { + /* Evaluate expression, test against expected result */ + bool pass = false; + double args[CALCPERFORM_NARGS] = { + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 + }; + char rpn[MAX_POSTFIX_SIZE]; + short err; + epicsUInt32 uresult; + double result = 0.0; + result /= result; /* Start as NaN */ + + if (postfix(expr, rpn, &err)) { + testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr); + } else + if (calcPerform(args, &result, rpn) && finite(result)) { + testDiag("calcPerform: error evaluating '%s'", expr); + } + + uresult = (epicsUInt32) result; + pass = (uresult == expected); + if (!testOk(pass, "%s", expr)) { + testDiag("Expected result is 0x%x (%u), actually got 0x%x (%u)", + expected, expected, uresult, uresult); + calcExprDump(rpn); } return; } @@ -238,8 +268,8 @@ MAIN(epicsCalcTest) const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0, g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0; - testPlan(577); - + testPlan(598); + /* LITERAL_OPERAND elements */ testExpr(0); testExpr(1); @@ -883,7 +913,35 @@ MAIN(epicsCalcTest) testBadExpr("1?", CALC_ERR_CONDITIONAL); testBadExpr("1?1", CALC_ERR_CONDITIONAL); testBadExpr(":1", CALC_ERR_SYNTAX); - + + // Bit manipulations wrt bit 31 (bug lp:1514520) + // using integer literals + testUInt32Calc("0xaaaaaaaa AND 0xffff0000", 0xaaaa0000u); + testUInt32Calc("0xaaaaaaaa OR 0xffff0000", 0xffffaaaau); + testUInt32Calc("0xaaaaaaaa XOR 0xffff0000", 0x5555aaaau); + testUInt32Calc("~0xaaaaaaaa", 0x55555555u); + testUInt32Calc("~~0xaaaaaaaa", 0xaaaaaaaau); + testUInt32Calc("0xaaaaaaaa >> 8", 0xffaaaaaau); + testUInt32Calc("0xaaaaaaaa << 8", 0xaaaaaa00u); + // using integer literals, assigned to operands + testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a AND b", 0xaaaa0000u); + testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a OR b", 0xffffaaaau); + testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a XOR b", 0x5555aaaau); + testUInt32Calc("a:=0xaaaaaaaa; ~a", 0x55555555u); + testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau); + testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau); + testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u); + // using double operands (what the calc record does) + // 0xaaaaaaaa = 2863311530.0 + // 0xffff0000 = 4294901760.0 + testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a AND b", 0xaaaa0000u); + testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a OR b", 0xffffaaaau); + testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a XOR b", 0x5555aaaau); + testUInt32Calc("a:=2863311530.0; ~a", 0x55555555u); + testUInt32Calc("a:=2863311530.0; ~~a", 0xaaaaaaaau); + testUInt32Calc("a:=2863311530.0; a >> 8", 0xffaaaaaau); + testUInt32Calc("a:=2863311530.0; a << 8", 0xaaaaaa00u); + return testDone(); } From 599e6635fbd970af8cb80b92622da8b5c1758532 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 18 Feb 2016 15:19:01 +0100 Subject: [PATCH 3/5] libCom/calc: fix bit31 bit manipulations --- src/libCom/calc/calcPerform.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 0e8fcd5e9..76c0e1623 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -284,33 +284,33 @@ epicsShareFunc long break; case BIT_OR: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop | itop; + itop = (epicsUInt32) *ptop--; + *ptop = (epicsInt32) ((epicsUInt32)*ptop | itop); break; case BIT_AND: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop & itop; + itop = (epicsUInt32) *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop & itop); break; case BIT_EXCL_OR: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop ^ itop; + itop = (epicsUInt32) *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop ^ itop); break; case BIT_NOT: - itop = (epicsInt32) *ptop; + itop = (epicsUInt32) *ptop; *ptop = ~itop; break; case RIGHT_SHIFT: itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop >> itop; + *ptop = (epicsInt32) (epicsUInt32) *ptop >> itop; break; case LEFT_SHIFT: itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop << itop; + *ptop = (epicsInt32) ((epicsUInt32) *ptop << itop); break; case NOT_EQ: From 89e6fdbca058a8c88b1f56512fb6f695841b3e1e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 19 Feb 2016 15:57:44 -0600 Subject: [PATCH 4/5] Fixed conversion overflows in tests Minor tidying-up, added comments about casting for bitwise operations. --- src/libCom/calc/calcPerform.c | 38 ++++++++++++++++++++----------- src/libCom/calc/postfix.c | 6 ++--- src/libCom/test/epicsCalcTest.cpp | 22 ++++++++---------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 76c0e1623..2221f169f 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -45,6 +45,7 @@ epicsShareFunc long double *ptop; /* stack pointer */ double top; /* value from top of stack */ epicsInt32 itop; /* integer from top of stack */ + epicsUInt32 utop; /* unsigned integer from top of stack */ int op; int nargs; @@ -262,7 +263,7 @@ epicsShareFunc long case NINT: top = *ptop; - *ptop = (double)(epicsInt32)(top >= 0 ? top + 0.5 : top - 0.5); + *ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5); break; case RANDOM: @@ -283,34 +284,45 @@ epicsShareFunc long *ptop = ! *ptop; break; + /* For bitwise operations on values with bit 31 set, double values + * must first be cast to unsigned to correctly set that bit; the + * double value must be negative in that case. The result must be + * cast to a signed integer before converting to the double result. + */ + case BIT_OR: - itop = (epicsUInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32)*ptop | itop); + utop = *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop | utop); break; case BIT_AND: - itop = (epicsUInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32) *ptop & itop); + utop = *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop & utop); break; case BIT_EXCL_OR: - itop = (epicsUInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32) *ptop ^ itop); + utop = *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop); break; case BIT_NOT: - itop = (epicsUInt32) *ptop; - *ptop = ~itop; + utop = *ptop; + *ptop = (epicsInt32) ~utop; break; + /* The shift operators use signed integers, so a right-shift will + * extend the sign bit into the left-hand end of the value. The + * double-casting through unsigned here is important, see above. + */ + case RIGHT_SHIFT: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) (epicsUInt32) *ptop >> itop; + utop = *ptop--; + *ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31); break; case LEFT_SHIFT: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32) *ptop << itop); + utop = *ptop--; + *ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31); break; case NOT_EQ: diff --git a/src/libCom/calc/postfix.c b/src/libCom/calc/postfix.c index 4ad57f910..d64d00d85 100644 --- a/src/libCom/calc/postfix.c +++ b/src/libCom/calc/postfix.c @@ -602,13 +602,13 @@ epicsShareFunc void while ((op = *pinst) != END_EXPRESSION) { switch (op) { case LITERAL_DOUBLE: - memcpy(&lit_d, ++pinst, sizeof(double)); + memcpy(&lit_d, ++pinst, sizeof(double)); printf("\tDouble %g\n", lit_d); pinst += sizeof(double); break; case LITERAL_INT: - memcpy(&lit_i, ++pinst, sizeof(epicsInt32)); - printf("\tInteger %d (0x%x)\n", lit_i, lit_i); + memcpy(&lit_i, ++pinst, sizeof(epicsInt32)); + printf("\tInteger %d (0x%x)\n", lit_i, lit_i); pinst += sizeof(int); break; case MIN: diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index 5b17694f9..b5199ac15 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -64,7 +64,6 @@ void testCalc(const char *expr, double expected) { testDiag("Expected result is %g, actually got %g", expected, result); calcExprDump(rpn); } - return; } void testUInt32Calc(const char *expr, epicsUInt32 expected) { @@ -93,7 +92,6 @@ void testUInt32Calc(const char *expr, epicsUInt32 expected) { expected, expected, uresult, uresult); calcExprDump(rpn); } - return; } void testArgs(const char *expr, unsigned long einp, unsigned long eout) { @@ -931,16 +929,16 @@ MAIN(epicsCalcTest) testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u); - // using double operands (what the calc record does) - // 0xaaaaaaaa = 2863311530.0 - // 0xffff0000 = 4294901760.0 - testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a AND b", 0xaaaa0000u); - testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a OR b", 0xffffaaaau); - testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a XOR b", 0x5555aaaau); - testUInt32Calc("a:=2863311530.0; ~a", 0x55555555u); - testUInt32Calc("a:=2863311530.0; ~~a", 0xaaaaaaaau); - testUInt32Calc("a:=2863311530.0; a >> 8", 0xffaaaaaau); - testUInt32Calc("a:=2863311530.0; a << 8", 0xaaaaaa00u); + // using double operands (add 0.1 to force as double) + // 0xaaaaaaaa = -1431655766 + // 0xffff0000 = -65536 + testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a AND b", 0xaaaa0000u); + testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a OR b", 0xffffaaaau); + testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a XOR b", 0x5555aaaau); + testUInt32Calc("a:=-1431655766.1; ~a", 0x55555555u); + testUInt32Calc("a:=-1431655766.1; ~~a", 0xaaaaaaaau); + testUInt32Calc("a:=-1431655766.1; a >> 8", 0xffaaaaaau); + testUInt32Calc("a:=-1431655766.1; a << 8", 0xaaaaaa00u); return testDone(); } From b45622ac5e3a230d3d1ee55526bb2bd71bf75361 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 23 Feb 2016 12:42:00 -0600 Subject: [PATCH 5/5] Test each bitwise cast individually for overflow --- src/libCom/test/epicsCalcTest.cpp | 40 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index b5199ac15..ae129c449 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -266,7 +266,7 @@ MAIN(epicsCalcTest) const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0, g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0; - testPlan(598); + testPlan(613); /* LITERAL_OPERAND elements */ testExpr(0); @@ -921,7 +921,7 @@ MAIN(epicsCalcTest) testUInt32Calc("~~0xaaaaaaaa", 0xaaaaaaaau); testUInt32Calc("0xaaaaaaaa >> 8", 0xffaaaaaau); testUInt32Calc("0xaaaaaaaa << 8", 0xaaaaaa00u); - // using integer literals, assigned to operands + // using integer literals assigned to variables testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a AND b", 0xaaaa0000u); testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a OR b", 0xffffaaaau); testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a XOR b", 0x5555aaaau); @@ -929,16 +929,32 @@ MAIN(epicsCalcTest) testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u); - // using double operands (add 0.1 to force as double) - // 0xaaaaaaaa = -1431655766 - // 0xffff0000 = -65536 - testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a AND b", 0xaaaa0000u); - testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a OR b", 0xffffaaaau); - testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a XOR b", 0x5555aaaau); - testUInt32Calc("a:=-1431655766.1; ~a", 0x55555555u); - testUInt32Calc("a:=-1431655766.1; ~~a", 0xaaaaaaaau); - testUInt32Calc("a:=-1431655766.1; a >> 8", 0xffaaaaaau); - testUInt32Calc("a:=-1431655766.1; a << 8", 0xaaaaaa00u); + + // Test proper conversion of double values (+ 0.1 enforces double literal) + // when used as inputs to the bitwise operations. + // 0xaaaaaaaa = -1431655766 or 2863311530u + testUInt32Calc("-1431655766.1 OR 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 OR 0", 0xaaaaaaaau); + testUInt32Calc("0 OR -1431655766.1", 0xaaaaaaaau); + testUInt32Calc("0 OR 2863311530.1", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 XOR 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 XOR 0", 0xaaaaaaaau); + testUInt32Calc("0 XOR -1431655766.1", 0xaaaaaaaau); + testUInt32Calc("0 XOR 2863311530.1", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 AND 0xffffffff", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 AND 0xffffffff", 0xaaaaaaaau); + testUInt32Calc("0xffffffff AND -1431655766.1", 0xaaaaaaaau); + testUInt32Calc("0xffffffff AND 2863311530.1", 0xaaaaaaaau); + testUInt32Calc("~ -1431655766.1", 0x55555555u); + testUInt32Calc("~ 2863311530.1", 0x55555555u); + testUInt32Calc("-1431655766.1 >> 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 >> 0", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 >> 0.1", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 >> 0.1", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 << 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 << 0", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 << 0.1", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 << 0.1", 0xaaaaaaaau); return testDone(); }