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(); }