X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2FSDCCicode.c;h=44dddc1175750e87adfba60a77b369db35302d45;hb=89ced3c908df7524953073632212e98f40566081;hp=32f913aec7f0a10e33a7ac3013399320ebd9f20a;hpb=9a41b4db10ee40ac3a381f4dbbfd3cc2fa9014a6;p=fw%2Fsdcc diff --git a/src/SDCCicode.c b/src/SDCCicode.c index 32f913ae..44dddc11 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) @@ -845,7 +856,14 @@ isOperandVolatile (operand * op, bool chkTemp) if (IS_ITEMP (op) && !chkTemp) return 0; - return IS_VOLATILE(operandType(op)); + opetype = getSpec (optype = operandType (op)); + + if (IS_PTR (optype) && DCL_PTR_VOLATILE (optype)) + return 1; + + if (IS_VOLATILE (opetype)) + return 1; + return 0; } /*-----------------------------------------------------------------*/ @@ -979,7 +997,7 @@ isOperandOnStack (operand * op) /*-----------------------------------------------------------------*/ /* operandLitValue - literal value of an operand */ /*-----------------------------------------------------------------*/ -double +double operandLitValue (operand * op) { assert (isOperandLiteral (op)); @@ -1013,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, @@ -1021,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) @@ -1042,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; @@ -1059,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) < @@ -1126,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) && @@ -1147,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)); @@ -1155,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)); @@ -1163,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 '!': @@ -1187,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 */ @@ -1391,7 +1470,7 @@ operandFromSymbol (symbol * sym) ok && /* farspace check */ !IS_BITVAR (sym->etype) /* not a bit variable */ ) - { + { /* we will use it after all optimizations and before liveRange calculation */ @@ -1514,10 +1593,13 @@ operandFromAst (ast * tree,int lvl) case EX_LINK: return operandFromLink (tree->opval.lnk); - } + break; - assert (0); - /* Just to keep the comiler happy */ + default: + assert (0); + } + + /* Just to keep the compiler happy */ return (operand *) 0; } @@ -1862,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))) @@ -1907,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) && @@ -2051,12 +2133,6 @@ geniCodeAdd (operand * left, operand * right, int lvl) int isarray = 0; LRTYPE; -#if 0 - /* if left is an array then array access */ - if (IS_ARRAY (ltype)) - return geniCodeArray (left, right,lvl); -#endif - /* if the right side is LITERAL zero */ /* return the left side */ if (IS_LITERAL (retype) && right->isLiteral && !floatFromVal (valFromType (retype))) @@ -2118,27 +2194,12 @@ aggrToPtr (sym_link * type, bool force) return type; etype = getSpec (type); - ptype = newLink (); + ptype = newLink (DECLARATOR); ptype->next = type; -#ifdef JWK - /* if the output class is code */ - if ((DCL_TYPE (ptype) = PTR_TYPE (SPEC_OCLS (etype))) == CPOINTER) - DCL_PTR_CONST (ptype) = port->mem.code_ro; - - /* if the variable was declared a constant */ - /* then the pointer points to a constant */ - if (IS_CONSTANT (etype)) - DCL_PTR_CONST (ptype) = 1; - - /* the variable was volatile then pointer to volatile */ - if (IS_VOLATILE (etype)) - DCL_PTR_VOLATILE (ptype) = 1; -#else + /* set the pointer depending on the storage class */ DCL_TYPE (ptype) = PTR_TYPE (SPEC_OCLS (etype)); -#endif - return ptype; } @@ -2151,22 +2212,8 @@ geniCodeArray2Ptr (operand * op) sym_link *optype = operandType (op); sym_link *opetype = getSpec (optype); -#ifdef JWK /* set the pointer depending on the storage class */ - if ((DCL_TYPE (optype) = PTR_TYPE (SPEC_OCLS (opetype))) == CPOINTER) - DCL_PTR_CONST (optype) = port->mem.code_ro; - - /* if the variable was declared a constant */ - /* then the pointer points to a constant */ - if (IS_CONSTANT (opetype)) - DCL_PTR_CONST (optype) = 1; - - /* the variable was volatile then pointer to volatile */ - if (IS_VOLATILE (opetype)) - DCL_PTR_VOLATILE (optype) = 1; -#else DCL_TYPE (optype) = PTR_TYPE (SPEC_OCLS (opetype)); -#endif op->isaddr = 0; return op; @@ -2241,7 +2288,7 @@ geniCodeStruct (operand * left, operand * right, bool islval) retype = getSpec (operandType (IC_RESULT (ic))); SPEC_SCLS (retype) = SPEC_SCLS (etype); SPEC_OCLS (retype) = SPEC_OCLS (etype); - SPEC_VOLATILE (retype) |= SPEC_VOLATILE (etype); + SPEC_VOLATILE (retype) |= SPEC_VOLATILE (etype); /* EEP - I'm doubtful about this */ if (IS_PTR (element->type)) setOperandType (IC_RESULT (ic), aggrToPtr (operandType (IC_RESULT (ic)), TRUE)); @@ -2451,24 +2498,10 @@ geniCodeAddressOf (operand * op) /* return op; */ /* } */ - p = newLink (); - p->class = DECLARATOR; + p = newLink (DECLARATOR); -#ifdef JWK /* set the pointer depending on the storage class */ - if ((DCL_TYPE (p) = PTR_TYPE (SPEC_OCLS (opetype))) == CPOINTER) - DCL_PTR_CONST (p) = port->mem.code_ro; - - /* make sure we preserve the const & volatile */ - if (IS_CONSTANT (opetype)) - DCL_PTR_CONST (p) = 1; - - if (IS_VOLATILE (opetype)) - DCL_PTR_VOLATILE (p) = 1; -#else DCL_TYPE (p) = PTR_TYPE (SPEC_OCLS (opetype)); -#endif - p->next = copyLinkChain (optype); @@ -2538,16 +2571,19 @@ geniCodeDerefPtr (operand * op,int lvl) sym_link *rtype, *retype; sym_link *optype = operandType (op); - /* if this is a pointer then generate the rvalue */ - if (IS_PTR (optype)) + // if this is an array then array access + if (IS_ARRAY (optype)) { + // don't worry, this will be optimized out later + return geniCodeArray (op, operandFromLit (0), lvl); + } + + // just in case someone screws up + wassert (IS_PTR (optype)); + + if (IS_TRUE_SYMOP (op)) { - if (IS_TRUE_SYMOP (op)) - { - op->isaddr = 1; - op = geniCodeRValue (op, TRUE); - } - else - op = geniCodeRValue (op, TRUE); + op->isaddr = 1; + op = geniCodeRValue (op, TRUE); } /* now get rid of the pointer part */ @@ -2560,17 +2596,11 @@ geniCodeDerefPtr (operand * op,int lvl) retype = getSpec (rtype = copyLinkChain (optype->next)); } - /* if this is a pointer then outputclass needs 2b updated */ - if (IS_PTR (optype)) - setOClass (optype, retype); + /* outputclass needs 2b updated */ + setOClass (optype, retype); op->isGptr = IS_GENPTR (optype); - /* if the pointer was declared as a constant */ - /* then we cannot allow assignment to the derefed */ - if (IS_PTR_CONST (optype)) - SPEC_CONST (retype) = 1; - op->isaddr = (IS_PTR (rtype) || IS_STRUCT (rtype) || IS_INT (rtype) || @@ -2646,10 +2676,53 @@ 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); } + /* if one operand is a pointer and the other is a literal generic void pointer, + change the type of the literal generic void pointer to match the other pointer */ + if (IS_GENPTR (ltype) && IS_VOID (ltype->next) && IS_ITEMP (left) + && IS_PTR (rtype) && !IS_GENPTR(rtype)) + { + /* find left's definition */ + ic = (iCode *) setFirstItem (iCodeChain); + while (ic) + { + if (((ic->op == CAST) || (ic->op == '=')) + && isOperandEqual(left, IC_RESULT (ic))) + break; + else + ic = setNextItem (iCodeChain); + } + /* if casting literal to generic pointer, then cast to rtype instead */ + if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic))) + { + left = operandFromValue (valCastLiteral (rtype, operandLitValue (IC_RIGHT (ic)))); + ltype = operandType(left); + } + } + if (IS_GENPTR (rtype) && IS_VOID (rtype->next) && IS_ITEMP (right) + && IS_PTR (ltype) && !IS_GENPTR(ltype)) + { + /* find right's definition */ + ic = (iCode *) setFirstItem (iCodeChain); + while (ic) + { + if (((ic->op == CAST) || (ic->op == '=')) + && isOperandEqual(right, IC_RESULT (ic))) + break; + else + ic = setNextItem (iCodeChain); + } + /* if casting literal to generic pointer, then cast to rtype instead */ + if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic))) + { + right = operandFromValue (valCastLiteral (ltype, operandLitValue (IC_RIGHT (ic)))); + rtype = operandType(right); + } + } + ctype = usualBinaryConversions (&left, &right); ic = newiCode (op, left, right); @@ -3228,7 +3301,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; @@ -3552,16 +3625,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); @@ -3576,9 +3665,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);