Merged the fix-calc-bit-manipulation branch
This commit is contained in:
@@ -13,6 +13,14 @@
|
||||
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h3>CALC engine bitwise operator fixes</h3>
|
||||
|
||||
<p>The bitwise operators in the CALC engine have been modified to work properly
|
||||
with values that have bit 31 (0x80000000) set. This modification involved
|
||||
back-porting some earlier changes from the 3.15 branch, and fixes
|
||||
<a href="https://code.launchpad.net/bugs/1514520">Launchpad bug
|
||||
#1514520</a>.</p>
|
||||
|
||||
<h3>ipAddrToAsciiAsync.: don't try to join the daemon thread</h3>
|
||||
|
||||
<p>On process exit, no longer try to stop the worker thread used by
|
||||
|
||||
@@ -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,8 @@ 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 */
|
||||
epicsUInt32 utop; /* unsigned integer from top of stack */
|
||||
int op;
|
||||
int nargs;
|
||||
|
||||
@@ -55,14 +57,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 +138,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 +263,7 @@ epicsShareFunc long
|
||||
|
||||
case NINT:
|
||||
top = *ptop;
|
||||
*ptop = (double)(long)(top >= 0 ? top + 0.5 : top - 0.5);
|
||||
*ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5);
|
||||
break;
|
||||
|
||||
case RANDOM:
|
||||
@@ -282,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 = (long) *ptop--;
|
||||
*ptop = (long) *ptop | itop;
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop | utop);
|
||||
break;
|
||||
|
||||
case BIT_AND:
|
||||
itop = (long) *ptop--;
|
||||
*ptop = (long) *ptop & itop;
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop & utop);
|
||||
break;
|
||||
|
||||
case BIT_EXCL_OR:
|
||||
itop = (long) *ptop--;
|
||||
*ptop = (long) *ptop ^ itop;
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop);
|
||||
break;
|
||||
|
||||
case BIT_NOT:
|
||||
itop = (long) *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 = (long) *ptop--;
|
||||
*ptop = (long) *ptop >> itop;
|
||||
utop = *ptop--;
|
||||
*ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31);
|
||||
break;
|
||||
|
||||
case LEFT_SHIFT:
|
||||
itop = (long) *ptop--;
|
||||
*ptop = (long) *ptop << itop;
|
||||
utop = *ptop--;
|
||||
*ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31);
|
||||
break;
|
||||
|
||||
case NOT_EQ:
|
||||
@@ -381,7 +394,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 +481,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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// Author: Andrew Johnson
|
||||
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsAlgorithm.h"
|
||||
#include "postfix.h"
|
||||
@@ -38,32 +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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void testArgs(const char *expr, unsigned long einp, unsigned long eout) {
|
||||
@@ -238,8 +266,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(613);
|
||||
|
||||
/* LITERAL_OPERAND elements */
|
||||
testExpr(0);
|
||||
testExpr(1);
|
||||
@@ -883,7 +911,51 @@ 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 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);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; ~a", 0x55555555u);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; 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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user