/*-----------------------------------------------------------------*/
/* forward definition of some functions */
-operand *geniCodeAssign (operand *, operand *, int);
+operand *geniCodeAssign (operand *, operand *, int, int);
static operand *geniCodeArray (operand *, operand *,int);
static operand *geniCodeArray2Ptr (operand *);
operand *geniCodeRValue (operand *, bool);
{ARRAYINIT, "arrayInit", picGenericOne, NULL},
{DUMMY_READ_VOLATILE, "dummy = (volatile)", picDummyRead, NULL},
{CRITICAL, "critical_start", picCritical, NULL},
- {ENDCRITICAL, "critical_end", picEndCritical, NULL}
+ {ENDCRITICAL, "critical_end", picEndCritical, NULL},
+ {SWAP, "swap", picGenericOne, NULL}
};
/*-----------------------------------------------------------------*/
case SYMBOL:
#define REGA 1
#ifdef REGA
- fprintf (file, "%s [k%d lr%d:%d so:%d]{ ia%d re%d rm%d nos%d ru%d dp%d}", /*{ar%d rm%d ru%d p%d a%d u%d i%d au%d k%d ks%d}" , */
+ fprintf (file, "%s [k%d lr%d:%d so:%d]{ ia%d a2p%d re%d rm%d nos%d ru%d dp%d}", /*{ar%d rm%d ru%d p%d a%d u%d i%d au%d k%d ks%d}" , */
(OP_SYMBOL (op)->rname[0] ? OP_SYMBOL (op)->rname : OP_SYMBOL (op)->name),
op->key,
OP_LIVEFROM (op), OP_LIVETO (op),
OP_SYMBOL (op)->stack,
- op->isaddr, OP_SYMBOL (op)->isreqv,
+ op->isaddr, op->aggr2ptr, OP_SYMBOL (op)->isreqv,
OP_SYMBOL (op)->remat,OP_SYMBOL(op)->noSpilLoc,
OP_SYMBOL(op)->ruonly,OP_SYMBOL(op)->dptr
);
break;
case '~':
- retval = operandFromLit (~((TYPE_UDWORD) operandLitValue (left)));
+ retval = operandFromValue (valCastLiteral (type,
+ ~((TYPE_UDWORD)
+ operandLitValue (left))));
break;
case '!':
ok = 0;
if (!IS_AGGREGATE (sym->type) && /* not an aggregate */
- !IS_FUNC (sym->type) && /* not a function */
- !sym->_isparm && /* not a parameter */
- sym->level && /* is a local variable */
- !sym->addrtaken && /* whose address has not been taken */
- !sym->reqv && /* does not already have a reg equivalence */
+ !IS_FUNC (sym->type) && /* not a function */
+ !sym->_isparm && /* not a parameter */
+ IS_AUTO (sym) && /* is a local auto variable */
+ !sym->addrtaken && /* whose address has not been taken */
+ !sym->reqv && /* does not already have a reg equivalence */
!IS_VOLATILE (sym->etype) && /* not declared as volatile */
- !IS_STATIC (sym->etype) && /* and not declared static */
- !sym->islbl && /* not a label */
- ok && /* farspace check */
- !IS_BITVAR (sym->etype) /* not a bit variable */
+ !sym->islbl && /* not a label */
+ ok && /* farspace check */
+ !IS_BITVAR (sym->etype) /* not a bit variable */
)
{
}
}
} else { // from a pointer to a pointer
- if (port->s.gptr_size > port->s.fptr_size /*!TARGET_IS_Z80 && !TARGET_IS_GBZ80*/) {
+ if (IS_GENPTR(type) && IS_VOID(type->next))
+ { // cast to void* is always allowed
+ }
+ else if (IS_GENPTR(optype) && IS_VOID(optype->next))
+ { // cast from void* is always allowed
+ }
+ else 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
}
/*-----------------------------------------------------------------*/
-/* aggrToPtr - changes an aggregate to pointer to an aggregate */
+/* aggrToPtr - changes an "aggregate" to a "pointer to aggregate" */
/*-----------------------------------------------------------------*/
sym_link *
aggrToPtr (sym_link * type, bool force)
return ptype;
}
+/*------------------------------------------------------------------*/
+/* aggrToPtrDclType - like aggrToPtr, but returns only the DCL_TYPE */
+/*------------------------------------------------------------------*/
+int
+aggrToPtrDclType (sym_link * type, bool force)
+{
+ if (IS_PTR (type) && !force)
+ return DCL_TYPE (type);
+
+ /* return the pointer depending on the storage class */
+ return PTR_TYPE (SPEC_OCLS (getSpec (type)));
+}
+
/*-----------------------------------------------------------------*/
/* geniCodeArray2Ptr - array to pointer */
/*-----------------------------------------------------------------*/
!IS_PTR (ltype->next))
? ltype : ltype->next), 0);
- IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (ltype->next));
+ if (!IS_AGGREGATE (ltype->next))
+ {
+ IC_RESULT (ic)->isaddr = 1;
+ IC_RESULT (ic)->aggr2ptr = 1;
+ }
ADDTOCHAIN (ic);
return IC_RESULT (ic);
right->operand.symOperand);
wassert(IS_SYMOP(right));
-
+
/* add the offset */
ic = newiCode ('+', left, operandFromLit (element->offset));
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);
if (IS_ITEMP (rv))
OP_SYMBOL(rv)->noSpilLoc = 1;
- geniCodeAssign (rOp, rv, 0);
+ geniCodeAssign (rOp, rv, 0, 0);
size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
+ if (size == 0)
+ werror(W_SIZEOF_VOID);
if (IS_FLOAT (rvtype))
ic = newiCode ('+', rv, operandFromValue (constFloatVal ("1.0")));
else
IC_RESULT (ic) = result = newiTempOperand (rvtype, 0);
ADDTOCHAIN (ic);
- geniCodeAssign (op, result, 0);
+ geniCodeAssign (op, result, 0, 0);
return rOp;
return op;
}
-
size = (IS_PTR (roptype) ? getSize (roptype->next) : 1);
+ if (size == 0)
+ werror(W_SIZEOF_VOID);
if (IS_FLOAT (roptype))
ic = newiCode ('+', rop, operandFromValue (constFloatVal ("1.0")));
else
IC_RESULT (ic) = result = newiTempOperand (roptype, 0);
ADDTOCHAIN (ic);
- (void) geniCodeAssign (op, result, 0);
- if (lvalue || IS_TRUE_SYMOP (op))
+ (void) geniCodeAssign (op, result, 0, 0);
+ if (lvalue || IS_TRUE_SYMOP (op) || IS_BITVAR (optype))
return op;
else
return result;
if (IS_ITEMP (rv))
OP_SYMBOL(rv)->noSpilLoc = 1;
- geniCodeAssign (rOp, rv, 0);
+ geniCodeAssign (rOp, rv, 0, 0);
size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
+ if (size == 0)
+ werror(W_SIZEOF_VOID);
if (IS_FLOAT (rvtype))
ic = newiCode ('-', rv, operandFromValue (constFloatVal ("1.0")));
else
IC_RESULT (ic) = result = newiTempOperand (rvtype, 0);
ADDTOCHAIN (ic);
- geniCodeAssign (op, result, 0);
+ geniCodeAssign (op, result, 0, 0);
return rOp;
return op;
}
-
size = (IS_PTR (roptype) ? getSize (roptype->next) : 1);
+ if (size == 0)
+ werror(W_SIZEOF_VOID);
if (IS_FLOAT (roptype))
ic = newiCode ('-', rop, operandFromValue (constFloatVal ("1.0")));
else
IC_RESULT (ic) = result = newiTempOperand (roptype, 0);
ADDTOCHAIN (ic);
- (void) geniCodeAssign (op, result, 0);
- if (lvalue || IS_TRUE_SYMOP (op))
+ (void) geniCodeAssign (op, result, 0, 0);
+ if (lvalue || IS_TRUE_SYMOP (op) || IS_BITVAR (optype))
return op;
else
return result;
/*-----------------------------------------------------------------*/
/* geniCodeLogic- logic code */
/*-----------------------------------------------------------------*/
-operand *
+static operand *
geniCodeLogic (operand * left, operand * right, int op)
{
iCode *ic;
op != NE_OP &&
op != AND_OP &&
op != OR_OP)
- ic->supportRtn = 1;
+ ic->supportRtn = 1;
ADDTOCHAIN (ic);
return IC_RESULT (ic);
}
+/*-----------------------------------------------------------------*/
+/* geniCodeLogicAndOr - && || operations */
+/*-----------------------------------------------------------------*/
+static operand *
+geniCodeLogicAndOr (ast *tree, int lvl)
+{
+ iCode *ic;
+ symbol *falseLabel = newiTempLabel (NULL);
+ symbol *trueLabel = newiTempLabel (NULL);
+ symbol *exitLabel = newiTempLabel (NULL);
+ operand *op, *result, *condition;
+
+ /* AND_OP and OR_OP are no longer generated because of bug-905492.
+ They can be reenabled by executing the following block. If you find
+ a decent optimization you could start right here:
+ */
+#if 0
+ if (0)
+ {
+ operand *leftOp, *rightOp;
+
+ leftOp = geniCodeRValue (ast2iCode (tree->left , lvl + 1), FALSE);
+ rightOp = geniCodeRValue (ast2iCode (tree->right, lvl + 1), FALSE);
+
+ return geniCodeLogic (leftOp, rightOp, tree->opval.op);
+ }
+#endif
+
+ /* generate two IFX for the '&&' or '||' op */
+
+ /* evaluate left operand */
+ condition = ast2iCode (tree->left, lvl + 1);
+ op = geniCodeRValue (condition, FALSE);
+
+ /* test left operand */
+ if (tree->opval.op == AND_OP)
+ ic = newiCodeCondition (op, NULL, falseLabel);
+ else /* OR_OP */
+ ic = newiCodeCondition (op, trueLabel, NULL);
+ ADDTOCHAIN (ic);
+
+ /* evaluate right operand */
+ condition = ast2iCode (tree->right, lvl + 1);
+ op = geniCodeRValue (condition, FALSE);
+
+ /* test right operand */
+ ic = newiCodeCondition (op, trueLabel, NULL);
+ ADDTOCHAIN (ic);
+
+ /* store 0 or 1 in result */
+ result = newiTempOperand (newCharLink(), 1);
+
+ geniCodeLabel (falseLabel);
+ geniCodeAssign (result, operandFromLit (0), 0, 0);
+ /* generate an unconditional goto */
+ geniCodeGoto (exitLabel);
+
+ geniCodeLabel (trueLabel);
+ geniCodeAssign (result, operandFromLit (1), 0, 0);
+
+ geniCodeLabel (exitLabel);
+
+ return result;
+}
+
/*-----------------------------------------------------------------*/
/* geniCodeUnary - for a a generic unary operation */
/*-----------------------------------------------------------------*/
/* move the value to a new Operand */
result = newiTempOperand (tree->right->ftype, 0);
- geniCodeAssign (result, geniCodeRValue (true, FALSE), 0);
+ geniCodeAssign (result, geniCodeRValue (true, FALSE), 0, 0);
/* generate an unconditional goto */
geniCodeGoto (exitLabel);
geniCodeLabel (falseLabel);
false = ast2iCode (tree->right->right,lvl+1);
- geniCodeAssign (result, geniCodeRValue (false, FALSE), 0);
+ geniCodeAssign (result, geniCodeRValue (false, FALSE), 0, 0);
/* create the exit label */
geniCodeLabel (exitLabel);
/* geniCodeAssign - generate code for assignment */
/*-----------------------------------------------------------------*/
operand *
-geniCodeAssign (operand * left, operand * right, int nosupdate)
+geniCodeAssign (operand * left, operand * right, int nosupdate, int strictLval)
{
iCode *ic;
sym_link *ltype = operandType (left);
sym_link *rtype = operandType (right);
- if (!left->isaddr && !IS_ITEMP (left))
+ if (!left->isaddr && (!IS_ITEMP (left) || strictLval))
{
werror (E_LVALUE_REQUIRED, "assignment");
return left;
operand *top = operandFromSymbol (argVals->sym);
/* clear useDef and other bitVectors */
OP_USES(top)=OP_DEFS(top)=OP_SYMBOL(top)->clashes = NULL;
- geniCodeAssign (top, pval, 1);
+ geniCodeAssign (top, pval, 1, 0);
}
else
{
/* create a proc icode */
ic = newiCode (FUNCTION, func, NULL);
lineno=ic->lineno = OP_SYMBOL (func)->lineDef;
+ ic->tree = tree;
ADDTOCHAIN (ic);
/* now generate the end proc */
ic = newiCode (ENDFUNCTION, func, NULL);
+ ic->tree = tree;
ADDTOCHAIN (ic);
return;
}
int
geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
{
- int min = 0, max = 0, t, cnt = 0;
+ int min, max, cnt = 1;
+ int i, t;
value *vch;
iCode *ic;
operand *boundary;
set *labels = NULL;
int needRangeCheck = !optimize.noJTabBoundary
|| tree->values.switchVals.swDefault;
+ sym_link *cetype = getSpec (operandType (cond));
+ int sizeofMinCost, sizeofMaxCost;
+ int sizeofMatchJump, sizeofJumpTable;
+ int sizeIndex;
if (!tree || !caseVals)
return 0;
/* the criteria for creating a jump table is */
/* all integer numbers between the maximum & minimum must */
/* be present , the maximum value should not exceed 255 */
- min = max = (int) floatFromVal (vch = caseVals);
- SNPRINTF (buffer, sizeof(buffer),
- "_case_%d_%d",
- tree->values.switchVals.swNum,
- min);
- addSet (&labels, newiTempLabel (buffer));
-
- /* if there is only one case value then no need */
- if (!(vch = vch->next))
- return 0;
+ /* If not all integer numbers are present the algorithm */
+ /* inserts jumps to the default label for the missing numbers */
+ /* and decides later whether it is worth it */
+ min = (int) floatFromVal (vch = caseVals);
- while (vch)
+ while (vch->next)
{
- if (((t = (int) floatFromVal (vch)) - max) != 1)
- return 0;
- SNPRINTF (buffer, sizeof(buffer),
- "_case_%d_%d",
- tree->values.switchVals.swNum,
- t);
- addSet (&labels, newiTempLabel (buffer));
- max = t;
cnt++;
vch = vch->next;
}
+ max = (int) floatFromVal (vch);
- /* 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 ((needRangeCheck && cnt <= 2) || max > (255 / 3))
+ /* Exit if the range is too large to handle with a jump table. */
+ if (1 + max - min > port->jumptableCost.maxCount)
return 0;
- if (tree->values.switchVals.swDefault)
+ switch (getSize (operandType (cond)))
{
- SNPRINTF (buffer, sizeof(buffer), "_default_%d", tree->values.switchVals.swNum);
+ case 1: sizeIndex = 0; break;
+ case 2: sizeIndex = 1; break;
+ case 4: sizeIndex = 2; break;
+ default: return 0;
}
- else
+
+ /* Compute the size cost of the range check and subtraction. */
+ sizeofMinCost = 0;
+ sizeofMaxCost = 0;
+ if (needRangeCheck)
{
- SNPRINTF (buffer, sizeof(buffer), "_swBrk_%d", tree->values.switchVals.swNum);
+ if (!(min==0 && IS_UNSIGNED (cetype)))
+ sizeofMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+ sizeofMaxCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+ }
+ if (min)
+ sizeofMinCost += port->jumptableCost.sizeofSubtract;
+
+ /* If the size cost of handling a non-zero minimum exceeds the */
+ /* cost of extending the range down to zero, then it might be */
+ /* better to extend the range to zero. */
+ if (min > 0 && sizeofMinCost >= (min * port->jumptableCost.sizeofElement))
+ {
+ /* Only extend the jump table if it would still be manageable. */
+ if (1 + max <= port->jumptableCost.maxCount)
+ min = 0;
}
+ /* Compute the total size cost of a jump table. */
+ sizeofJumpTable = (1 + max - min) * port->jumptableCost.sizeofElement
+ + port->jumptableCost.sizeofDispatch
+ + sizeofMinCost + sizeofMaxCost;
+
+ /* Compute the total size cost of a match & jump sequence */
+ sizeofMatchJump = cnt * port->jumptableCost.sizeofMatchJump[sizeIndex];
+
+ /* If the size cost of the jump table is uneconomical then exit */
+ if (sizeofMatchJump < sizeofJumpTable)
+ return 0;
+ /* The jump table is preferable. */
+
+ /* First, a label for the default or missing cases. */
+ if (tree->values.switchVals.swDefault)
+ {
+ SNPRINTF (buffer, sizeof(buffer),
+ "_default_%d",
+ tree->values.switchVals.swNum);
+ }
+ else
+ {
+ SNPRINTF (buffer, sizeof(buffer),
+ "_swBrk_%d",
+ tree->values.switchVals.swNum);
+ }
falseLabel = newiTempLabel (buffer);
- /* so we can create a jumptable */
+ /* Build the list of labels for the jump table. */
+ vch = caseVals;
+ t = (int) floatFromVal (vch);
+ for (i=min; i<=max; i++)
+ {
+ if (vch && t==i)
+ {
+ /* Explicit case: make a new label for it. */
+ SNPRINTF (buffer, sizeof(buffer),
+ "_case_%d_%d",
+ tree->values.switchVals.swNum,
+ i);
+ addSet (&labels, newiTempLabel (buffer));
+ vch = vch->next;
+ if (vch)
+ t = (int) floatFromVal (vch);
+ }
+ else
+ {
+ /* Implicit case: use the default label. */
+ addSet (&labels, falseLabel);
+ }
+ }
+
+ /* If cond is volatile, it might change after the boundary */
+ /* conditions are tested to an out of bounds value, causing */
+ /* a jump to a location outside of the jump table. To avoid */
+ /* this possibility, use a non-volatile copy of it instead. */
+ if (IS_OP_VOLATILE (cond))
+ {
+ operand * newcond;
+ iCode * ic;
+
+ newcond = newiTempOperand (operandType (cond), TRUE);
+ newcond->isvolatile = 0;
+ ic = newiCode ('=', NULL, cond);
+ IC_RESULT (ic) = newcond;
+ ADDTOCHAIN (ic);
+ cond = newcond;
+ }
+
/* first we rule out the boundary conditions */
/* if only optimization says so */
if (needRangeCheck)
tree->opval.op != '?' &&
tree->opval.op != CALL &&
tree->opval.op != IFX &&
+ tree->opval.op != AND_OP &&
+ tree->opval.op != OR_OP &&
tree->opval.op != LABEL &&
tree->opval.op != GOTO &&
tree->opval.op != SWITCH &&
setOperandType (op, UCHARTYPE);
return op;
}
+ case AND_OP:
+ case OR_OP:
+ return geniCodeLogicAndOr (tree, lvl);
case '>':
case '<':
case LE_OP:
case GE_OP:
case EQ_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.
+ 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);
*/
{
- operand *leftOp, *rightOp;
+ operand *leftOp, *rightOp;
- rightOp = geniCodeRValue (right, FALSE);
- leftOp = geniCodeRValue (left , FALSE);
+ leftOp = geniCodeRValue (left , FALSE);
+ rightOp = geniCodeRValue (right, FALSE);
- return geniCodeLogic (leftOp, rightOp, tree->opval.op);
+ return geniCodeLogic (leftOp, rightOp, tree->opval.op);
}
case '?':
return geniCodeConditional (tree,lvl);
else
right = geniCodeRValue (right, FALSE);
- geniCodeAssign (left, right, 0);
+ geniCodeAssign (left, right, 0, 1);
return right;
}
case MUL_ASSIGN:
geniCodeAssign (left,
geniCodeMultiply (geniCodeRValue (operandFromOperand (left),
FALSE),
- geniCodeRValue (right, FALSE), FALSE),
- getResultTypeFromType (tree->ftype));
+ geniCodeRValue (right, FALSE),
+ getResultTypeFromType (tree->ftype)),
+ 0, 1);
case DIV_ASSIGN:
return
FALSE),
geniCodeRValue (right, FALSE),
getResultTypeFromType (tree->ftype)),
- 0);
+ 0, 1);
case MOD_ASSIGN:
return
geniCodeAssign (left,
FALSE),
geniCodeRValue (right, FALSE),
getResultTypeFromType (tree->ftype)),
- 0);
+ 0, 1);
case ADD_ASSIGN:
{
sym_link *rtype = operandType (right);
right,
getResultTypeFromType (tree->ftype),
lvl),
- 0);
+ 0, 1);
}
case SUB_ASSIGN:
{
FALSE),
right,
getResultTypeFromType (tree->ftype)),
- 0);
+ 0, 1);
}
case LEFT_ASSIGN:
return
,FALSE),
geniCodeRValue (right, FALSE),
getResultTypeFromType (tree->ftype)),
- 0);
+ 0, 1);
case RIGHT_ASSIGN:
return
geniCodeAssign (left,
geniCodeRightShift (geniCodeRValue (operandFromOperand (left)
,FALSE),
- geniCodeRValue (right, FALSE)), 0);
+ geniCodeRValue (right, FALSE)), 0, 1);
case AND_ASSIGN:
return
geniCodeAssign (left,
FALSE),
geniCodeRValue (right, FALSE),
BITWISEAND,
- operandType (left)), 0);
+ operandType (left)), 0, 1);
case XOR_ASSIGN:
return
geniCodeAssign (left,
FALSE),
geniCodeRValue (right, FALSE),
'^',
- operandType (left)), 0);
+ operandType (left)), 0, 1);
case OR_ASSIGN:
return
geniCodeAssign (left,
,FALSE),
geniCodeRValue (right, FALSE),
'|',
- operandType (left)), 0);
+ operandType (left)), 0, 1);
case ',':
return geniCodeRValue (right, FALSE);