X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2FSDCCicode.c;h=36a4837e9c89a5b7b2c4b0eb77fea7bfaebada77;hb=26daa5ec1aff94ebbe55715797ea92c0332b51b7;hp=cc65ac066028318a58201eaa772154e872c304c3;hpb=96ff919c3470720e4bf26c7d278c753a97eeef09;p=fw%2Fsdcc diff --git a/src/SDCCicode.c b/src/SDCCicode.c index cc65ac06..36a4837e 100644 --- a/src/SDCCicode.c +++ b/src/SDCCicode.c @@ -67,6 +67,7 @@ PRINTFUNC (picIfx); PRINTFUNC (picJumpTable); PRINTFUNC (picInline); PRINTFUNC (picReceive); +PRINTFUNC (picDummyRead); iCodeTable codeTable[] = { @@ -113,12 +114,14 @@ iCodeTable codeTable[] = {RECEIVE, "recv", picReceive, NULL}, {SEND, "send", picGenericOne, NULL}, {ARRAYINIT, "arrayInit", picGenericOne, NULL}, + {DUMMY_READ_VOLATILE, "dummy = (volatile)", picDummyRead, NULL} }; /*-----------------------------------------------------------------*/ /* checkConstantRange: check a constant against the type */ /*-----------------------------------------------------------------*/ + /* pedantic=0: allmost anything is allowed as long as the absolute value is within the bit range of the type, and -1 is treated as 0xf..f for unsigned types (e.g. in assign) @@ -126,7 +129,7 @@ iCodeTable codeTable[] = pedantic>1: "char c=200" is not allowed (evaluates to -56) */ -void checkConstantRange(sym_link *ltype, value *val, char *msg, +void checkConstantRange(sym_link *ltype, value *val, char *msg, int pedantic) { double max; int warnings=0; @@ -216,7 +219,7 @@ printOperand (operand * op, FILE * file) if (SPEC_NOUN (opetype) == V_FLOAT) fprintf (file, "%g {", SPEC_CVAL (opetype).v_float); else - fprintf (file, "0x%x {", (int) floatFromVal (op->operand.valOperand)); + fprintf (file, "0x%x {", (unsigned) floatFromVal (op->operand.valOperand)); printTypeChain (operandType (op), file); fprintf (file, "}"); break; @@ -461,10 +464,18 @@ PRINTFUNC (picReceive) fprintf (of, "\n"); } +PRINTFUNC (picDummyRead) +{ + fprintf (of, "\t"); + fprintf (of, "%s ", s); + printOperand (IC_RIGHT (ic), of); + fprintf (of, "\n"); +} + /*-----------------------------------------------------------------*/ /* piCode - prints one iCode */ /*-----------------------------------------------------------------*/ -int +int piCode (void *item, FILE * of) { iCode *ic = item; @@ -488,7 +499,7 @@ void PICC(iCode *ic) /*-----------------------------------------------------------------*/ /* printiCChain - prints intermediate code for humans */ /*-----------------------------------------------------------------*/ -void +void printiCChain (iCode * icChain, FILE * of) { iCode *loop; @@ -722,7 +733,7 @@ copyiCode (iCode * ic) iCodeTable * getTableEntry (int oper) { - int i; + unsigned i; for (i = 0; i < (sizeof (codeTable) / sizeof (iCodeTable)); i++) if (oper == codeTable[i].icode) @@ -986,7 +997,7 @@ isOperandOnStack (operand * op) /*-----------------------------------------------------------------*/ /* operandLitValue - literal value of an operand */ /*-----------------------------------------------------------------*/ -double +double operandLitValue (operand * op) { assert (isOperandLiteral (op)); @@ -1020,7 +1031,7 @@ iCode *getBuiltinParms (iCode *ic, int *pcount, operand **parms) } /*-----------------------------------------------------------------*/ -/* operandOperation - perforoms operations on operands */ +/* operandOperation - performs operations on operands */ /*-----------------------------------------------------------------*/ operand * operandOperation (operand * left, operand * right, @@ -1028,12 +1039,12 @@ operandOperation (operand * left, operand * right, { sym_link *let , *ret=NULL; operand *retval = (operand *) 0; - + assert (isOperandLiteral (left)); let = getSpec(operandType(left)); if (right) { assert (isOperandLiteral (right)); - ret = getSpec(operandType(left)); + ret = getSpec(operandType(right)); } switch (op) @@ -1049,12 +1060,63 @@ operandOperation (operand * left, operand * right, operandLitValue (right))); break; case '*': + /* retval = operandFromValue (valCastLiteral (type, operandLitValue (left) * operandLitValue (right))); + This could be all we've to do, but with gcc we've to take care about + overflows. Two examples: + ULONG_MAX * ULONG_MAX doesn't fit into a double, some of the least + significant bits are lost (52 in fraction, 63 bits would be + necessary to keep full precision). + If the resulting double value is greater than ULONG_MAX (resp. + USHRT_MAX, ...), then 0 will be assigned to v_ulong (resp. u_uint, ...)! + */ + + /* if it is not a specifier then we can assume that */ + /* it will be an unsigned long */ + if (IS_INT (type) || + !IS_SPEC (type)) + { + /* long is handled here, because it can overflow with double */ + if (SPEC_LONG (type) || + !IS_SPEC (type)) + /* signed and unsigned mul are the same, as long as the precision + of the result isn't bigger than the precision of the operands. */ + retval = operandFromValue (valCastLiteral (type, + (TYPE_UDWORD) operandLitValue (left) * + (TYPE_UDWORD) operandLitValue (right))); + else if (SPEC_USIGN (type)) /* unsigned int */ + { + /* unsigned int is handled here in order to detect overflow */ + TYPE_UDWORD ul = (TYPE_UWORD) operandLitValue (left) * + (TYPE_UWORD) operandLitValue (right); + + retval = operandFromValue (valCastLiteral (type, (TYPE_UWORD) ul)); + if (!options.lessPedantic && + ul != (TYPE_UWORD) ul) + werror (W_INT_OVL); + } + else /* signed int */ + { + /* signed int is handled here in order to detect overflow */ + TYPE_DWORD l = (TYPE_WORD) operandLitValue (left) * + (TYPE_WORD) operandLitValue (right); + + retval = operandFromValue (valCastLiteral (type, (TYPE_WORD) l)); + if (!options.lessPedantic && + l != (TYPE_WORD) l) + werror (W_INT_OVL); + } + } + else + /* all others go here: */ + retval = operandFromValue (valCastLiteral (type, + operandLitValue (left) * + operandLitValue (right))); break; case '/': - if ((unsigned long) operandLitValue (right) == 0) + if ((TYPE_UDWORD) operandLitValue (right) == 0) { werror (E_DIVIDE_BY_ZERO); retval = right; @@ -1066,51 +1128,57 @@ operandOperation (operand * left, operand * right, operandLitValue (right))); break; case '%': - if ((unsigned long) operandLitValue (right) == 0) { + if ((TYPE_UDWORD) operandLitValue (right) == 0) { werror (E_DIVIDE_BY_ZERO); retval = right; } - else - retval = operandFromLit ((SPEC_USIGN(let) ? - (unsigned long) operandLitValue (left) : - (long) operandLitValue (left)) % - (SPEC_USIGN(ret) ? - (unsigned long) operandLitValue (right) : - (long) operandLitValue (right))); - + else + { + if (SPEC_USIGN(let) || SPEC_USIGN(ret)) + /* one of the operands is unsigned */ + retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) % + (TYPE_UDWORD) operandLitValue (right)); + else + /* both operands are signed */ + retval = operandFromLit ((TYPE_DWORD) operandLitValue (left) % + (TYPE_DWORD) operandLitValue (right)); + } break; case LEFT_OP: - retval = operandFromLit ((SPEC_USIGN(let) ? - (unsigned long) operandLitValue (left) : - (long) operandLitValue (left)) << - (SPEC_USIGN(ret) ? - (unsigned long) operandLitValue (right) : - (long) operandLitValue (right))); + /* The number of left shifts is always unsigned. Signed doesn't make + sense here. Shifting by a negative number is impossible. */ + retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) << + (TYPE_UDWORD) operandLitValue (right)); break; - case RIGHT_OP: { - double lval = operandLitValue(left), rval = operandLitValue(right); - double res=0; - switch ((SPEC_USIGN(let) ? 2 : 0) + (SPEC_USIGN(ret) ? 1 : 0)) - { - case 0: // left=unsigned right=unsigned - res=(unsigned long)lval >> (unsigned long)rval; - break; - case 1: // left=unsigned right=signed - res=(unsigned long)lval >> (signed long)rval; - break; - case 2: // left=signed right=unsigned - res=(signed long)lval >> (unsigned long)rval; - break; - case 3: // left=signed right=signed - res=(signed long)lval >> (signed long)rval; - break; - } - retval = operandFromLit (res); + case RIGHT_OP: + /* The number of right shifts is always unsigned. Signed doesn't make + sense here. Shifting by a negative number is impossible. */ + if (SPEC_USIGN(let)) + /* unsigned: logic shift right */ + retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) >> + (TYPE_UDWORD) operandLitValue (right)); + else + /* signed: arithmetic shift right */ + retval = operandFromLit ((TYPE_DWORD ) operandLitValue (left) >> + (TYPE_UDWORD) operandLitValue (right)); break; - } case EQ_OP: - retval = operandFromLit (operandLitValue (left) == - operandLitValue (right)); + /* this op doesn't care about signedness */ + { + TYPE_UDWORD l, r; + + l = (TYPE_UDWORD) operandLitValue (left); + if (SPEC_NOUN(OP_VALUE(left)->type) == V_CHAR) + l &= 0xff; + else if (!SPEC_LONG (OP_VALUE(left)->type)) + l &= 0xffff; + r = (TYPE_UDWORD) operandLitValue (right); + if (SPEC_NOUN(OP_VALUE(right)->type) == V_CHAR) + r &= 0xff; + else if (!SPEC_LONG (OP_VALUE(right)->type)) + r &= 0xffff; + retval = operandFromLit (l == r); + } break; case '<': retval = operandFromLit (operandLitValue (left) < @@ -1133,16 +1201,19 @@ operandOperation (operand * left, operand * right, operandLitValue (right)); break; case BITWISEAND: - retval = operandFromLit ((long)operandLitValue(left) & - (long)operandLitValue(right)); + retval = operandFromValue (valCastLiteral (type, + (TYPE_UDWORD)operandLitValue(left) & + (TYPE_UDWORD)operandLitValue(right))); break; case '|': - retval = operandFromLit ((long)operandLitValue (left) | - (long)operandLitValue (right)); + retval = operandFromValue (valCastLiteral (type, + (TYPE_UDWORD)operandLitValue(left) | + (TYPE_UDWORD)operandLitValue(right))); break; case '^': - retval = operandFromLit ((long)operandLitValue (left) ^ - (long)operandLitValue (right)); + retval = operandFromValue (valCastLiteral (type, + (TYPE_UDWORD)operandLitValue(left) ^ + (TYPE_UDWORD)operandLitValue(right))); break; case AND_OP: retval = operandFromLit (operandLitValue (left) && @@ -1154,7 +1225,7 @@ operandOperation (operand * left, operand * right, break; case RRC: { - long i = (long) operandLitValue (left); + TYPE_UDWORD i = (TYPE_UDWORD) operandLitValue (left); retval = operandFromLit ((i >> (getSize (operandType (left)) * 8 - 1)) | (i << 1)); @@ -1162,7 +1233,7 @@ operandOperation (operand * left, operand * right, break; case RLC: { - long i = (long) operandLitValue (left); + TYPE_UDWORD i = (TYPE_UDWORD) operandLitValue (left); retval = operandFromLit ((i << (getSize (operandType (left)) * 8 - 1)) | (i >> 1)); @@ -1170,11 +1241,12 @@ operandOperation (operand * left, operand * right, break; case UNARYMINUS: - retval = operandFromLit (-1 * operandLitValue (left)); + retval = operandFromValue (valCastLiteral (type, + -1 * operandLitValue (left))); break; case '~': - retval = operandFromLit (~((long) operandLitValue (left))); + retval = operandFromLit (~((TYPE_UDWORD) operandLitValue (left))); break; case '!': @@ -1194,7 +1266,7 @@ operandOperation (operand * left, operand * right, /*-----------------------------------------------------------------*/ /* isOperandEqual - compares two operand & return 1 if they r = */ /*-----------------------------------------------------------------*/ -int +int isOperandEqual (operand * left, operand * right) { /* if the pointers are equal then they are equal */ @@ -1872,11 +1944,11 @@ geniCodeMultiply (operand * left, operand * right,int resultIsInt) /* if the right is a literal & power of 2 */ /* then make it a left shift */ - /* code generated for 1 byte * 1 byte literal = 2 bytes result is more - efficient in most cases than 2 bytes result = 2 bytes << literal + /* code generated for 1 byte * 1 byte literal = 2 bytes result is more + efficient in most cases than 2 bytes result = 2 bytes << literal if port has 1 byte muldiv */ if (p2 && !IS_FLOAT (letype) && - !((resultIsInt) && (getSize (resType) != getSize (ltype)) && + !((resultIsInt) && (getSize (resType) != getSize (ltype)) && (port->support.muldiv == 1))) { if ((resultIsInt) && (getSize (resType) != getSize (ltype))) @@ -1917,8 +1989,8 @@ geniCodeDivision (operand * left, operand * right) resType = usualBinaryConversions (&left, &right); - /* if the right is a literal & power of 2 - and left is unsigned then make it a + /* if the right is a literal & power of 2 + and left is unsigned then make it a right shift */ if (IS_LITERAL (retype) && !IS_FLOAT (letype) && @@ -2638,7 +2710,7 @@ geniCodeLogic (operand * left, operand * right, int op) check if the literal value is within bounds */ if (IS_INTEGRAL (ltype) && IS_VALOP (right) && IS_LITERAL (rtype)) { - checkConstantRange(ltype, + checkConstantRange(ltype, OP_VALUE(right), "compare operation", 1); } @@ -3220,7 +3292,7 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree) /*-----------------------------------------------------------------*/ /* geniCodeSwitch - changes a switch to a if statement */ /*-----------------------------------------------------------------*/ -void +void geniCodeSwitch (ast * tree,int lvl) { iCode *ic; @@ -3544,16 +3616,32 @@ ast2iCode (ast * tree,int lvl) case RIGHT_OP: return geniCodeRightShift (geniCodeRValue (left, FALSE), geniCodeRValue (right, FALSE)); - case CAST: + case CAST: +#if 0 // this indeed needs a second thought + { + operand *op; + + // let's keep this simple: get the rvalue we need + op=geniCodeRValue (right, FALSE); + // now cast it to whatever we want + op=geniCodeCast (operandType(left), op, FALSE); + // if this is going to be used as an lvalue, make it so + if (tree->lvalue) { + op->isaddr=1; + } + return op; + } +#else // bug #604575, is it a bug ???? return geniCodeCast (operandType (left), geniCodeRValue (right, FALSE), FALSE); +#endif case '~': - case '!': case RRC: case RLC: return geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op); + case '!': case GETHBIT: { operand *op = geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op); @@ -3568,9 +3656,21 @@ ast2iCode (ast * tree,int lvl) case NE_OP: case AND_OP: case OR_OP: + /* different compilers (even different gccs) evaluate + the two calls in a different order. to get the same + result on all machines we've to specify a clear sequence. return geniCodeLogic (geniCodeRValue (left, FALSE), - geniCodeRValue (right, FALSE), - tree->opval.op); + geniCodeRValue (right, FALSE), + tree->opval.op); + */ + { + operand *leftOp, *rightOp; + + rightOp = geniCodeRValue (right, FALSE); + leftOp = geniCodeRValue (left , FALSE); + + return geniCodeLogic (leftOp, rightOp, tree->opval.op); + } case '?': return geniCodeConditional (tree,lvl);