operand *geniCodeRValue (operand *, bool);
operand *geniCodeDerefPtr (operand *,int);
int isLvaluereq(int lvl);
+void setOClass (sym_link * ptr, sym_link * spec);
#define PRINTFUNC(x) void x (FILE *of, iCode *ic, char *s)
/* forward definition of ic print functions */
/* 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)
/*-----------------------------------------------------------------*/
/* operandLitValue - literal value of an operand */
/*-----------------------------------------------------------------*/
-double
+double
operandLitValue (operand * op)
{
assert (isOperandLiteral (op));
}
/*-----------------------------------------------------------------*/
-/* operandOperation - perforoms operations on operands */
+/* operandOperation - performs operations on operands */
/*-----------------------------------------------------------------*/
operand *
operandOperation (operand * left, operand * right,
operandLitValue (right)));
break;
case '*':
+ /*
retval = operandFromValue (valCastLiteral (type,
operandLitValue (left) *
operandLitValue (right)));
- if (!options.lessPedantic &&
- !IS_FLOAT (OP_VALUE(retval)->type) &&
- !SPEC_LONG (OP_VALUE(retval)->type))
- ; /* TODO: werror (W_INT_OVL) */
+ 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 (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 (l != (TYPE_WORD) l)
+ werror (W_INT_OVL);
+ }
+ }
+ else
+ /* all others go here: */
+ retval = operandFromValue (valCastLiteral (type,
+ operandLitValue (left) *
+ operandLitValue (right)));
break;
case '/':
if ((TYPE_UDWORD) operandLitValue (right) == 0)
retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) <<
(TYPE_UDWORD) operandLitValue (right));
break;
- case RIGHT_OP: {
+ 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))
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) <
break;
case UNARYMINUS:
- retval = operandFromLit (-1 * operandLitValue (left));
+ retval = operandFromValue (valCastLiteral (type,
+ -1 * operandLitValue (left)));
break;
case '~':
/*-----------------------------------------------------------------*/
/* 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 */
ok && /* farspace check */
!IS_BITVAR (sym->etype) /* not a bit variable */
)
- {
+ {
/* we will use it after all optimizations
and before liveRange calculation */
if (IS_INTEGRAL(optype)) {
// maybe this is NULL, than it's ok.
if (!(IS_LITERAL(optype) && (SPEC_CVAL(optype).v_ulong ==0))) {
- if (!TARGET_IS_Z80 && !TARGET_IS_GBZ80 && IS_GENPTR(type)) {
+ if (port->s.gptr_size > port->s.fptr_size && IS_GENPTR(type)) {
// no way to set the storage
if (IS_LITERAL(optype)) {
werror(E_LITERAL_GENERIC);
}
}
} else { // from a pointer to a pointer
- if (!TARGET_IS_Z80 && !TARGET_IS_GBZ80) {
+ if (port->s.gptr_size > port->s.fptr_size /*!TARGET_IS_Z80 && !TARGET_IS_GBZ80*/) {
// if not a pointer to a function
if (!(IS_CODEPTR(type) && IS_FUNC(type->next) && IS_FUNC(optype))) {
if (implicit) { // if not to generic, they have to match
/* 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)))
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) &&
sym_link *etype;
sym_link *ptype;
-
if (IS_PTR (type) && !force)
return type;
ptype->next = type;
- /* 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;
-
+ /* set the pointer depending on the storage class */
+ DCL_TYPE (ptype) = PTR_TYPE (SPEC_OCLS (etype));
return ptype;
}
sym_link *opetype = getSpec (optype);
/* 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;
+ DCL_TYPE (optype) = PTR_TYPE (SPEC_OCLS (opetype));
op->isaddr = 0;
return op;
SPEC_SCLS (retype) = SPEC_SCLS (etype);
SPEC_OCLS (retype) = SPEC_OCLS (etype);
SPEC_VOLATILE (retype) |= SPEC_VOLATILE (etype);
-
+ SPEC_CONST (retype) |= SPEC_CONST (etype);
+
if (IS_PTR (element->type))
setOperandType (IC_RESULT (ic), aggrToPtr (operandType (IC_RESULT (ic)), TRUE));
-
+
IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (element->type));
-
ADDTOCHAIN (ic);
return (islval ? IC_RESULT (ic) : geniCodeRValue (IC_RESULT (ic), TRUE));
}
p = newLink (DECLARATOR);
/* 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;
+ DCL_TYPE (p) = PTR_TYPE (SPEC_OCLS (opetype));
p->next = copyLinkChain (optype);
else
{
retype = getSpec (rtype = copyLinkChain (optype->next));
+ /* outputclass needs 2b updated */
+ 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) ||
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);
return left;
}
+/*-----------------------------------------------------------------*/
+/* geniCodeDummyRead - generate code for dummy read */
+/*-----------------------------------------------------------------*/
+static void
+geniCodeDummyRead (operand * op)
+{
+ iCode *ic;
+ sym_link *type = operandType (op);
+
+ if (!IS_VOLATILE(type))
+ return;
+
+ ic = newiCode (DUMMY_READ_VOLATILE, NULL, op);
+ ADDTOCHAIN (ic);
+
+ ic->nosupdate = 1;
+}
+
/*-----------------------------------------------------------------*/
/* geniCodeSEParms - generate code for side effecting fcalls */
/*-----------------------------------------------------------------*/
operand *boundary;
symbol *falseLabel;
set *labels = NULL;
+ int needRangeCheck = !optimize.noJTabBoundary
+ || tree->values.switchVals.swDefault;
if (!tree || !caseVals)
return 0;
/* if the number of case statements <= 2 then */
/* it is not economical to create the jump table */
/* since two compares are needed for boundary conditions */
- if ((!optimize.noJTabBoundary && cnt <= 2) || max > (255 / 3))
+ if ((needRangeCheck && cnt <= 2) || max > (255 / 3))
return 0;
if (tree->values.switchVals.swDefault)
/* so we can create a jumptable */
/* first we rule out the boundary conditions */
/* if only optimization says so */
- if (!optimize.noJTabBoundary)
+ if (needRangeCheck)
{
sym_link *cetype = getSpec (operandType (cond));
/* no need to check the lower bound if
if (min)
{
cond = geniCodeSubtract (cond, operandFromLit (min));
- setOperandType (cond, UCHARTYPE);
+ if (!IS_LITERAL(getSpec(operandType(cond))))
+ setOperandType (cond, UCHARTYPE);
}
/* now create the jumptable */
/*-----------------------------------------------------------------*/
/* geniCodeSwitch - changes a switch to a if statement */
/*-----------------------------------------------------------------*/
-void
+void
geniCodeSwitch (ast * tree,int lvl)
{
iCode *ic;
operand *cond = geniCodeRValue (ast2iCode (tree->left,lvl+1), FALSE);
value *caseVals = tree->values.switchVals.swVals;
symbol *trueLabel, *falseLabel;
+
+ /* If the condition is a literal, then just jump to the */
+ /* appropriate case label. */
+ if (IS_LITERAL(getSpec(operandType(cond))))
+ {
+ int switchVal, caseVal;
+
+ switchVal = (int) floatFromVal (cond->operand.valOperand);
+ while (caseVals)
+ {
+ caseVal = (int) floatFromVal (caseVals);
+ if (caseVal == switchVal)
+ {
+ SNPRINTF (buffer, sizeof(buffer), "_case_%d_%d",
+ tree->values.switchVals.swNum, caseVal);
+ trueLabel = newiTempLabel (buffer);
+ geniCodeGoto (trueLabel);
+ goto jumpTable;
+ }
+ caseVals = caseVals->next;
+ }
+ goto defaultOrBreak;
+ }
/* if we can make this a jump table */
if (geniCodeJumpTable (cond, caseVals, tree))
}
-
+defaultOrBreak:
/* if default is present then goto break else break */
if (tree->values.switchVals.swDefault)
{
(tree->opval.op == NULLOP ||
tree->opval.op == BLOCK))
{
- ast2iCode (tree->left,lvl+1);
- ast2iCode (tree->right,lvl+1);
+ if (tree->left && tree->left->type == EX_VALUE)
+ geniCodeDummyRead (ast2iCode (tree->left,lvl+1));
+ else
+ ast2iCode (tree->left,lvl+1);
+ if (tree->right && tree->right->type == EX_VALUE)
+ geniCodeDummyRead (ast2iCode (tree->right,lvl+1));
+ else
+ ast2iCode (tree->right,lvl+1);
return NULL;
}
#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);
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);