/*-----------------------------------------------------------------*/
/* 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}
};
/*-----------------------------------------------------------------*/
#if 0 // temporary disabled, leaving the warning as a reminder
if (warnings) {
- SNPRINTF (message, sizeof(message), "for %s %s in %s",
+ SNPRINTF (message, sizeof(message), "for %s %s in %s",
IS_UNSIGNED(ltype) ? "unsigned" : "signed",
nounName(ltype), msg);
werror (W_CONST_RANGE, message);
/*-----------------------------------------------------------------*/
/* operandName - returns the name of the operand */
/*-----------------------------------------------------------------*/
-int
+int
printOperand (operand * op, FILE * file)
{
sym_link *opetype;
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}" , */
+//#if REGA /* { */
+ if(REGA && !getenv("PRINT_SHORT_OPERANDS")) {
+ 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
);
fprintf (file, "]");
}
}
-#else
- fprintf (file, "%s", (OP_SYMBOL (op)->rname[0] ?
- OP_SYMBOL (op)->rname : OP_SYMBOL (op)->name));
+//#else /* } else { */
+ } else {
+ /* (getenv("PRINT_SHORT_OPERANDS") != NULL) */
+ fprintf (file, "%s ", (OP_SYMBOL (op)->rname[0] ? OP_SYMBOL (op)->rname : OP_SYMBOL (op)->name));
+
+ if(getenv("PRINT_SHORT_OPERANDS")[0] < '1')
+ {
+ fprintf (file, "[lr%d:%d so:%d]",
+ OP_LIVEFROM (op), OP_LIVETO (op),
+ OP_SYMBOL (op)->stack);
+ }
+
+ if(getenv("PRINT_SHORT_OPERANDS")[0] < '2')
+ {
+ fprintf (file, "{");
+ printTypeChain (operandType (op), file);
+ if (SPIL_LOC (op) && IS_ITEMP (op))
+ fprintf (file, "}{ sir@ %s", SPIL_LOC (op)->rname);
+ fprintf (file, "}");
+ }
+
/* if assigned to registers */
- if (OP_SYMBOL (op)->nRegs && !OP_SYMBOL (op)->isspilt)
+ if (OP_SYMBOL (op)->nRegs)
{
- int i;
- fprintf (file, "[");
- for (i = 0; i < OP_SYMBOL (op)->nRegs; i++)
- fprintf (file, "%s ", (OP_SYMBOL (op)->regs[i] ?
- OP_SYMBOL (op)->regs[i]->name :
- "err"));
- fprintf (file, "]");
+ if (OP_SYMBOL (op)->isspilt)
+ {
+ if (!OP_SYMBOL (op)->remat)
+ if (OP_SYMBOL (op)->usl.spillLoc)
+ fprintf (file, "[%s]", (OP_SYMBOL (op)->usl.spillLoc->rname[0] ?
+ OP_SYMBOL (op)->usl.spillLoc->rname :
+ OP_SYMBOL (op)->usl.spillLoc->name));
+ else
+ fprintf (file, "[err]");
+ else
+ fprintf (file, "[remat]");
+ }
+ else
+ {
+ int i;
+ fprintf (file, "[");
+ for (i = 0; i < OP_SYMBOL (op)->nRegs; i++)
+ fprintf (file, "%s ", port->getRegName (OP_SYMBOL (op)->regs[i]));
+ fprintf (file, "]");
+ }
}
-#endif
+//#endif /* } */
+ }
break;
case TYPE:
if (ic->op == SEND || ic->op == RECEIVE) {
fprintf(of,"{argreg = %d}",ic->argreg);
}
+ if (ic->op == IPUSH) {
+ fprintf(of,"{parmPush = %d}",ic->parmPush);
+ }
fprintf (of, "\n");
}
of = stdout;
icTab = getTableEntry (ic->op);
- fprintf (stdout, "%s(%d:%d:%d:%d:%d)\t",
+ fprintf (of, "%s(%d:%d:%d:%d:%d)\t",
ic->filename, ic->lineno,
ic->seq, ic->key, ic->depth, ic->supportRtn);
icTab->iCodePrint (of, ic, icTab->printName);
{
SNPRINTF (buffer, sizeof(buffer), "iTemp%d", iTempNum++);
}
-
+
itmp = newSymbol (buffer, 1);
strncpyz (itmp->rname, itmp->name, SDCC_NAME_MAX);
itmp->isitmp = 1;
{
symbol *itmplbl;
- /* check if this alredy exists */
+ /* check if this already exists */
if (s && (itmplbl = findSym (LabelTab, NULL, s)))
return itmplbl;
if (s)
{
- itmplbl = newSymbol (s, 1);
+ itmplbl = newSymbol (s, 1);
}
else
{
/*-----------------------------------------------------------------*/
/* initiCode - initialises some iCode related stuff */
/*-----------------------------------------------------------------*/
-void
+void
initiCode ()
{
/*-----------------------------------------------------------------*/
/* isParamterToCall - will return 1 if op is a parameter to args */
/*-----------------------------------------------------------------*/
-int
+int
isParameterToCall (value * args, operand * op)
{
value *tval = args;
wassert (IS_SYMOP(op));
-
+
while (tval)
{
if (tval->sym &&
/*-----------------------------------------------------------------*/
/* isOperandGlobal - return 1 if operand is a global variable */
/*-----------------------------------------------------------------*/
-int
+int
isOperandGlobal (operand * op)
{
if (!op)
/*-----------------------------------------------------------------*/
/* isOperandVolatile - return 1 if the operand is volatile */
/*-----------------------------------------------------------------*/
-int
+int
isOperandVolatile (operand * op, bool chkTemp)
{
sym_link *optype;
return 0;
opetype = getSpec (optype = operandType (op));
-
- if (IS_PTR (optype) && DCL_PTR_VOLATILE (optype))
- return 1;
-
- if (IS_VOLATILE (opetype))
- return 1;
- return 0;
+
+ if (IS_PTR (optype) && DCL_PTR_VOLATILE (optype))
+ return 1;
+
+ if (IS_VOLATILE (opetype))
+ return 1;
+ return 0;
}
/*-----------------------------------------------------------------*/
/* isOperandLiteral - returns 1 if an operand contains a literal */
/*-----------------------------------------------------------------*/
-int
+int
isOperandLiteral (operand * op)
{
sym_link *opetype;
/*-----------------------------------------------------------------*/
/* isOperandInFarSpace - will return true if operand is in farSpace */
/*-----------------------------------------------------------------*/
-bool
+bool
isOperandInFarSpace (operand * op)
{
sym_link *etype;
/*------------------------------------------------------------------*/
/* isOperandInDirSpace - will return true if operand is in dirSpace */
/*------------------------------------------------------------------*/
-bool
+bool
isOperandInDirSpace (operand * op)
{
sym_link *etype;
/*--------------------------------------------------------------------*/
/* isOperandInCodeSpace - will return true if operand is in codeSpace */
/*--------------------------------------------------------------------*/
-bool
+bool
isOperandInCodeSpace (operand * op)
{
sym_link *etype;
/*-----------------------------------------------------------------*/
/* isOperandOnStack - will return true if operand is on stack */
/*-----------------------------------------------------------------*/
-bool
+bool
isOperandOnStack (operand * op)
{
sym_link *etype;
/* isOclsExpensive - will return true if accesses to an output */
/* storage class are expensive */
/*-----------------------------------------------------------------*/
-bool
+bool
isOclsExpensive (struct memmap *oclass)
{
if (port->oclsExpense)
return IN_FARSPACE (oclass);
}
+/*-----------------------------------------------------------------*/
+/* isiCodeInFunctionCall - return TRUE if an iCode is between a */
+/* CALL/PCALL and the first IPUSH/SEND associated with the call */
+/*-----------------------------------------------------------------*/
+int
+isiCodeInFunctionCall (iCode * ic)
+{
+ iCode * lic = ic;
+
+ /* Find the next CALL/PCALL */
+ while (lic)
+ {
+ if (lic->op == CALL || lic->op == PCALL)
+ break;
+ lic = lic->next;
+ }
+
+ if (!lic)
+ return FALSE;
+
+ /* A function call was found. Scan backwards and see if an */
+ /* IPUSH or SEND is encountered */
+ while (ic)
+ {
+ if (lic != ic && (ic->op == CALL || ic->op == PCALL))
+ return FALSE;
+ if (ic->op == SEND || (ic->op == IPUSH && ic->parmPush))
+ return TRUE;
+ ic = ic->prev;
+ }
+
+ return FALSE;
+}
+
/*-----------------------------------------------------------------*/
/* operandLitValue - literal value of an operand */
/*-----------------------------------------------------------------*/
return isSymbolEqual (left->operand.symOperand,
right->operand.symOperand);
case VALUE:
- return (floatFromVal (left->operand.valOperand) ==
- floatFromVal (right->operand.valOperand));
+ return (compareType (left->operand.valOperand->type,
+ right->operand.valOperand->type) &&
+ (floatFromVal (left->operand.valOperand) ==
+ floatFromVal (right->operand.valOperand)));
case TYPE:
if (compareType (left->operand.typeOperand,
right->operand.typeOperand) == 1)
/*-------------------------------------------------------------------*/
/* isiCodeEqual - compares two iCodes are equal, returns true if yes */
/*-------------------------------------------------------------------*/
-int
+int
isiCodeEqual (iCode * left, iCode * right)
{
/* if the same pointer */
if (!isSymbolEqual (IC_FALSE (left), IC_FALSE (right)))
return 0;
}
-
+
return 1;
}
return 0;
nop->isLiteral = op->isLiteral;
nop->usesDefs = op->usesDefs;
nop->isParm = op->isParm;
-
+
switch (nop->type)
{
case SYMBOL:
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 */
)
- {
+ {
/* we will use it after all optimizations
and before liveRange calculation */
default:
assert (0);
}
-
+
/* Just to keep the compiler happy */
return (operand *) 0;
}
/*-----------------------------------------------------------------*/
/* setOperandType - sets the operand's type to the given type */
/*-----------------------------------------------------------------*/
-void
+void
setOperandType (operand * op, sym_link * type)
{
/* depending on the type of operand */
if(IS_PTR(ltype))
{
int size = getSize(ltype);
- return(IS_GENPTR(ltype)?(size-1):size);
+ return((IS_GENPTR(ltype) && GPTRSIZE > FPTRSIZE) ? (size-1) : size);
}
if(IS_ARRAY(ltype))
case FUNCTION:
return (FPTRSIZE);
case GPOINTER:
- return (GPTRSIZE-1);
+ if (GPTRSIZE > FPTRSIZE)
+ return (GPTRSIZE-1);
+ else
+ return (FPTRSIZE);
default:
return (FPTRSIZE);
*op1 = geniCodeCast (ctype, *op1, TRUE);
*op2 = geniCodeCast (ctype, *op2, TRUE);
-
+
return ctype;
}
geniCodeArray2Ptr (op);
op->isaddr = 0;
}
-
+
/* if the operand is already the desired type then do nothing */
if (compareType (type, optype) == 1)
return op;
}
}
} 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
- if ((!IS_GENPTR(type) && (DCL_TYPE(optype) != DCL_TYPE(type)))) {
+ if (!IS_GENPTR(type) &&
+ !((DCL_TYPE(optype) == DCL_TYPE(type)) ||
+ ((DCL_TYPE(optype) == POINTER) && (DCL_TYPE(type) == IPOINTER))
+ )
+ )
+ {
werror(E_INCOMPAT_PTYPES);
errors++;
}
}
/* if they are the same size create an assignment */
-
+
/* This seems very dangerous to me, since there are several */
/* optimizations (for example, gcse) that don't notice the */
/* cast hidden in this assignement and may simplify an */
restype = getSpec (operandType (IC_RESULT (ic)));
if (!IS_LITERAL(opetype) &&
!IS_BIT(opetype))
+ {
SPEC_SCLS (restype) = SPEC_SCLS (opetype);
- SPEC_OCLS (restype) = SPEC_OCLS (opetype);
-
+ SPEC_OCLS (restype) = SPEC_OCLS (opetype);
+ }
ADDTOCHAIN (ic);
return IC_RESULT (ic);
}
if (p2 && !IS_FLOAT (letype)
&& !((resultType == RESULT_TYPE_INT) && (getSize (resType) != getSize (ltype))
&& (port->support.muldiv == 1))
- && strcmp (port->target, "pic14") != 0 /* don't shift for pic */
- && strcmp (port->target, "pic16") != 0)
+ && strcmp (port->target, "pic16") != 0 /* don't shift for pic */
+ && strcmp (port->target, "pic14") != 0)
{
if ((resultType == RESULT_TYPE_INT) && (getSize (resType) != getSize (ltype)))
{
if (IS_VOID(ltype->next) || IS_VOID(rtype->next)) {
return result;
}
-
+
// should we really do this? is this ANSI?
return geniCodeDivision (result,
operandFromLit (getSize (ltype->next)),
}
/*-----------------------------------------------------------------*/
-/* 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;
op->isaddr = 0;
return op;
}
-
+
/* lvalue check already done in decorateType */
/* this must be a lvalue */
/* if (!op->isaddr && !IS_AGGREGATE(optype)) { */
/*-----------------------------------------------------------------*/
/* setOClass - sets the output class depending on the pointer type */
/*-----------------------------------------------------------------*/
-void
+void
setOClass (sym_link * ptr, sym_link * spec)
{
switch (DCL_TYPE (ptr))
/* outputclass needs 2b updated */
setOClass (optype, retype);
}
-
+
op->isGptr = IS_GENPTR (optype);
op->isaddr = (IS_PTR (rtype) ||
ic = setNextItem (iCodeChain);
}
/* if casting literal to generic pointer, then cast to rtype instead */
- if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic)))
+ if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic)))
{
left = operandFromValue (valCastLiteral (rtype, operandLitValue (IC_RIGHT (ic))));
ltype = operandType(left);
ic = setNextItem (iCodeChain);
}
/* if casting literal to generic pointer, then cast to rtype instead */
- if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic)))
+ if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic)))
{
right = operandFromValue (valCastLiteral (ltype, operandLitValue (IC_RIGHT (ic))));
rtype = operandType(right);
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);
+ geniCodeAssign (result, operandFromLit (0), 0, 0);
/* generate an unconditional goto */
geniCodeGoto (exitLabel);
geniCodeLabel (trueLabel);
- geniCodeAssign (result, operandFromLit (1), 0);
+ geniCodeAssign (result, operandFromLit (1), 0, 0);
geniCodeLabel (exitLabel);
/* 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;
check if the literal value is within bounds */
if (IS_INTEGRAL (ltype) && right->type == VALUE && IS_LITERAL (rtype))
{
- checkConstantRange(ltype,
+ checkConstantRange(ltype,
OP_VALUE(right), "= operation", 0);
}
if (!IS_VOLATILE(type))
return;
-
+
ic = newiCode (DUMMY_READ_VOLATILE, NULL, op);
ADDTOCHAIN (ic);
/*-----------------------------------------------------------------*/
/* geniCodeSEParms - generate code for side effecting fcalls */
/*-----------------------------------------------------------------*/
-static void
+static void
geniCodeSEParms (ast * parms,int lvl)
{
if (!parms)
IS_ADDRESS_OF_OP (parms->right))
parms->right->left->lvalue = 1;
- parms->opval.oprnd =
+ parms->opval.oprnd =
geniCodeRValue (ast2iCode (parms,lvl+1), FALSE);
-
+
parms->type = EX_OPERAND;
AST_ARGREG(parms) = parms->etype ? SPEC_ARGREG(parms->etype) :
SPEC_ARGREG(parms->ftype);
/* geniCodeParms - generates parameters */
/*-----------------------------------------------------------------*/
value *
-geniCodeParms (ast * parms, value *argVals, int *stack,
+geniCodeParms (ast * parms, value *argVals, int *stack,
sym_link * ftype, int lvl)
{
iCode *ic;
/* hack don't like this but too lazy to think of
something better */
if (IS_ADDRESS_OF_OP (parms))
- parms->left->lvalue = 1;
+ parms->left->lvalue = 1;
if (IS_CAST_OP (parms) &&
- IS_PTR (parms->ftype) &&
- IS_ADDRESS_OF_OP (parms->right))
- parms->right->left->lvalue = 1;
+ IS_PTR (parms->ftype) &&
+ IS_ADDRESS_OF_OP (parms->right))
+ parms->right->left->lvalue = 1;
pval = geniCodeRValue (ast2iCode (parms,lvl+1), FALSE);
}
{
/* now decide whether to push or assign */
if (!(options.stackAuto || IFFUNC_ISREENT (ftype)))
- {
+ {
- /* assign */
- 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);
- }
+ /* assign */
+ 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, 0);
+ }
else
- {
- sym_link *p = operandType (pval);
- /* push */
- ic = newiCode (IPUSH, pval, NULL);
- ic->parmPush = 1;
- /* update the stack adjustment */
- *stack += getSize (IS_AGGREGATE (p) ? aggrToPtr (p, FALSE) : p);
- ADDTOCHAIN (ic);
- }
+ {
+ sym_link *p = operandType (pval);
+ /* push */
+ ic = newiCode (IPUSH, pval, NULL);
+ ic->parmPush = 1;
+ /* update the stack adjustment */
+ *stack += getSize (IS_AGGREGATE (p) ? aggrToPtr (p, FALSE) : p);
+ ADDTOCHAIN (ic);
+ }
}
argVals=argVals->next;
sym_link *ftype;
int stack = 0;
- if (!IS_FUNC(OP_SYMBOL(left)->type) &&
+ if (!IS_FUNC(OP_SYMBOL(left)->type) &&
!IS_CODEPTR(OP_SYMBOL(left)->type)) {
werror (E_FUNCTION_EXPECTED);
return operandFromValue(valueFromLit(0));
ftype = operandType (left);
if (IS_CODEPTR (ftype))
ftype = ftype->next;
-
+
/* first the parameters */
geniCodeParms (parms, NULL, &stack, ftype, lvl);
/*-----------------------------------------------------------------*/
/* geniCodeReceive - generate intermediate code for "receive" */
/*-----------------------------------------------------------------*/
-static void
+static void
geniCodeReceive (value * args)
{
+ unsigned char paramByteCounter = 0;
+
/* for all arguments that are passed in registers */
while (args)
{
}
}
- ic = newiCode (RECEIVE, NULL, NULL);
+ ic = newiCode (RECEIVE, NULL, NULL);
ic->argreg = SPEC_ARGREG(args->etype);
if (first) {
currFunc->recvSize = getSize (sym->type);
first = 0;
}
IC_RESULT (ic) = opr;
+
+ /* misuse of parmBytes (normally used for functions)
+ * to save estimated stack position of this argument.
+ * Normally this should be zero for RECEIVE iCodes.
+ * No idea if this causes side effects on other ports. - dw
+ */
+ ic->parmBytes = paramByteCounter;
+
+ /* what stack position do we have? */
+ paramByteCounter += getSize (sym->type);
+
ADDTOCHAIN (ic);
}
/*-----------------------------------------------------------------*/
/* geniCodeFunctionBody - create the function body */
/*-----------------------------------------------------------------*/
-void
+void
geniCodeFunctionBody (ast * tree,int lvl)
{
iCode *ic;
/* 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;
}
/*-----------------------------------------------------------------*/
/* geniCodeReturn - gen icode for 'return' statement */
/*-----------------------------------------------------------------*/
-void
+void
geniCodeReturn (operand * op)
{
iCode *ic;
/*-----------------------------------------------------------------*/
/* geniCodeIfx - generates code for extended if statement */
/*-----------------------------------------------------------------*/
-void
+void
geniCodeIfx (ast * tree,int lvl)
{
iCode *ic;
/*-----------------------------------------------------------------*/
/* geniCodeJumpTable - tries to create a jump table for switch */
/*-----------------------------------------------------------------*/
-int
+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, sizeofZeroMinCost, 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);
+
+ /* Exit if the range is too large to handle with a jump table. */
+ if (1 + max - min > port->jumptableCost.maxCount)
+ return 0;
+
+ switch (getSize (operandType (cond)))
+ {
+ case 1: sizeIndex = 0; break;
+ case 2: sizeIndex = 1; break;
+ case 4: sizeIndex = 2; break;
+ default: return 0;
+ }
+
+ /* Compute the size cost of the range check and subtraction. */
+ sizeofMinCost = 0;
+ sizeofZeroMinCost = 0;
+ sizeofMaxCost = 0;
+ if (needRangeCheck)
+ {
+ if (!(min==0 && IS_UNSIGNED (cetype)))
+ sizeofMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+ if (!IS_UNSIGNED (cetype))
+ sizeofZeroMinCost = 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-sizeofZeroMinCost)
+ >= (min * port->jumptableCost.sizeofElement))
+ {
+ /* Only extend the jump table if it would still be manageable. */
+ if (1 + max <= port->jumptableCost.maxCount)
+ {
+ min = 0;
+ if (IS_UNSIGNED (cetype))
+ sizeofMinCost = 0;
+ else
+ sizeofMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+ }
+ }
+
+ /* 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 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))
+ /* 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);
+ SNPRINTF (buffer, sizeof(buffer),
+ "_default_%d",
+ tree->values.switchVals.swNum);
}
else
{
- SNPRINTF (buffer, sizeof(buffer), "_swBrk_%d", tree->values.switchVals.swNum);
+ 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);
+ }
+ }
+
/* first we rule out the boundary conditions */
/* if only optimization says so */
if (needRangeCheck)
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)
{
goto defaultOrBreak;
}
+ /* If cond is volatile, it might change while we are trying to */
+ /* find the matching case. To avoid this possibility, make a */
+ /* non-volatile copy to use 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;
+ }
+
/* if we can make this a jump table */
if (geniCodeJumpTable (cond, caseVals, tree))
goto jumpTable; /* no need for the comparison */
/*-----------------------------------------------------------------*/
/* geniCodeInline - intermediate code for inline assembler */
/*-----------------------------------------------------------------*/
-static void
+static void
geniCodeInline (ast * tree)
{
iCode *ic;
}
ADDTOCHAIN (ic);
}
-
+
/*-----------------------------------------------------------------*/
/* geniCodeCritical - intermediate code for a critical statement */
/*-----------------------------------------------------------------*/
-static void
+static void
geniCodeCritical (ast *tree, int lvl)
{
iCode *ic;
operand *op = NULL;
+ sym_link *type;
+
+ if (!options.stackAuto)
+ {
+ type = newLink(SPECIFIER);
+ SPEC_VOLATILE(type) = 1;
+ SPEC_NOUN(type) = V_BIT;
+ SPEC_SCLS(type) = S_BIT;
+ SPEC_BLEN(type) = 1;
+ SPEC_BSTR(type) = 0;
+ op = newiTempOperand(type, 1);
+ }
/* If op is NULL, the original interrupt state will saved on */
/* the stack. Otherwise, it will be saved in op. */
-
- /* Generate a save of the current interrupt state & disabled */
+
+ /* Generate a save of the current interrupt state & disable */
ic = newiCode (CRITICAL, NULL, NULL);
IC_RESULT (ic) = op;
ADDTOCHAIN (ic);
-
+
/* Generate the critical code sequence */
if (tree->left && tree->left->type == EX_VALUE)
geniCodeDummyRead (ast2iCode (tree->left,lvl+1));
else
ast2iCode (tree->left,lvl+1);
-
+
/* Generate a restore of the original interrupt state */
ic = newiCode (ENDCRITICAL, NULL, op);
ADDTOCHAIN (ic);
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);
case INLINEASM:
geniCodeInline (tree);
return NULL;
-
+
case ARRAYINIT:
geniCodeArrayInit(tree, ast2iCode (tree->left,lvl+1));
return NULL;
-
+
case CRITICAL:
geniCodeCritical (tree, lvl);
}
case VALUE: return "value";
case TYPE: return "type";
}
- return "undefined type";
+ return "undefined type";
}
-operand *validateOpType(operand *op,
+operand *validateOpType(operand *op,
const char *macro,
const char *args,
OPTYPE type,
- const char *file,
+ const char *file,
unsigned line)
-{
+{
if (op && op->type == type)
{
return op;
}
- fprintf(stderr,
+ fprintf(stderr,
"Internal error: validateOpType failed in %s(%s) @ %s:%u:"
" expected %s, got %s\n",
- macro, args, file, line,
+ macro, args, file, line,
opTypeToStr(type), op ? opTypeToStr(op->type) : "null op");
exit(-1);
return op; // never reached, makes compiler happy.