{
newic = newiCode (IPUSH, right, NULL);
newic->parmPush = 1;
- bytesPushed+=4;
+ //bytesPushed+=4;
+ bytesPushed += getSize(operandType(right));
}
addiCodeToeBBlock (ebp, newic, ip);
{
newic = newiCode (IPUSH, left, NULL);
newic->parmPush = 1;
- bytesPushed+=4;
+ //bytesPushed+=4;
+ bytesPushed += getSize(operandType(left));
}
addiCodeToeBBlock (ebp, newic, ip);
newic->lineno = lineno;
IC_RESULT (newic) = IC_RESULT (ic);
newic->lineno = lineno;
newic->parmBytes+=bytesPushed;
+ ebp->hasFcall = 1;
+ if (currFunc)
+ FUNC_HASFCALL (currFunc->type) = 1;
+
+ if(TARGET_IS_PIC16) {
+ /* normally these functions aren't marked external, so we can use their
+ * _extern field to marked as already added to symbol table */
+
+ if(!SPEC_EXTR(func->etype)) {
+ memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+
+ SPEC_EXTR(func->etype) = 1;
+ seg = SPEC_OCLS( func->etype );
+ addSet(&seg->syms, func);
+ }
+ }
+
addiCodeToeBBlock (ebp, newic, ip);
}
sym_link *type = operandType (IC_RIGHT (ic));
int linenno = ic->lineno;
int bwd, su;
+ int bytesPushed=0;
ip = ic->next;
/* remove it from the iCode */
{
newic = newiCode (IPUSH, IC_RIGHT (ic), NULL);
newic->parmPush = 1;
+ bytesPushed += getSize(operandType(IC_RIGHT(ic)));
}
addiCodeToeBBlock (ebp, newic, ip);
newic->lineno = linenno;
/* make the call */
newic = newiCode (CALL, operandFromSymbol (func), NULL);
IC_RESULT (newic) = IC_RESULT (ic);
+ newic->parmBytes+=bytesPushed;
+ ebp->hasFcall = 1;
+ if (currFunc)
+ FUNC_HASFCALL (currFunc->type) = 1;
+
+ if(TARGET_IS_PIC16) {
+ /* normally these functions aren't marked external, so we can use their
+ * _extern field to marked as already added to symbol table */
+
+ if(!SPEC_EXTR(func->etype)) {
+ memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+
+ SPEC_EXTR(func->etype) = 1;
+ seg = SPEC_OCLS( func->etype );
+ addSet(&seg->syms, func);
+ }
+ }
+
addiCodeToeBBlock (ebp, newic, ip);
newic->lineno = linenno;
-
}
/*-----------------------------------------------------------------*/
sym_link *type = operandType (IC_LEFT (ic));
int lineno = ic->lineno;
int bwd, su;
+ int bytesPushed=0;
ip = ic->next;
/* remove it from the iCode */
{
newic = newiCode (IPUSH, IC_RIGHT (ic), NULL);
newic->parmPush = 1;
+ bytesPushed += getSize(operandType(IC_RIGHT(ic)));
}
addiCodeToeBBlock (ebp, newic, ip);
newic->lineno = lineno;
/* make the call */
newic = newiCode (CALL, operandFromSymbol (func), NULL);
IC_RESULT (newic) = IC_RESULT (ic);
+ newic->parmBytes+=bytesPushed;
+ ebp->hasFcall = 1;
+ if (currFunc)
+ FUNC_HASFCALL (currFunc->type) = 1;
+
+ if(TARGET_IS_PIC16) {
+ /* normally these functions aren't marked external, so we can use their
+ * _extern field to marked as already added to symbol table */
+
+ if(!SPEC_EXTR(func->etype)) {
+ memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+
+ SPEC_EXTR(func->etype) = 1;
+ seg = SPEC_OCLS( func->etype );
+ addSet(&seg->syms, func);
+ }
+ }
+
addiCodeToeBBlock (ebp, newic, ip);
newic->lineno = lineno;
-
}
+extern operand *geniCodeRValue (operand *, bool);
+
/*-----------------------------------------------------------------*/
/* convilong - converts int or long mults or divs to fcalls */
/*-----------------------------------------------------------------*/
int su;
int bytesPushed=0;
- remiCodeFromeBBlock (ebp, ic);
-
+ // Easy special case which avoids function call: modulo by a literal power
+ // of two can be replaced by a bitwise AND.
+ if (op == '%' && isOperandLiteral(IC_RIGHT(ic)))
+ {
+ unsigned litVal = (unsigned)(operandLitValue(IC_RIGHT(ic)));
+
+ // See if literal value is a power of 2.
+ while (litVal && !(litVal & 1))
+ {
+ litVal >>= 1;
+ }
+ if (litVal)
+ {
+ // discard first high bit set.
+ litVal >>= 1;
+ }
+
+ if (!litVal)
+ {
+ ic->op = BITWISEAND;
+ IC_RIGHT(ic) = operandFromLit(operandLitValue(IC_RIGHT(ic)) - 1);
+ return;
+ }
+ }
+
+ remiCodeFromeBBlock (ebp, ic);
+
+
/* depending on the type */
for (bwd = 0; bwd < 3; bwd++)
{
IC_RESULT (newic) = IC_RESULT (ic);
newic->lineno = lineno;
newic->parmBytes+=bytesPushed; // to clear the stack after the call
+ ebp->hasFcall = 1;
+ if (currFunc)
+ FUNC_HASFCALL (currFunc->type) = 1;
+
+ if(TARGET_IS_PIC16) {
+ /* normally these functions aren't marked external, so we can use their
+ * _extern field to marked as already added to symbol table */
+
+ if(!SPEC_EXTR(func->etype)) {
+ memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+
+ SPEC_EXTR(func->etype) = 1;
+ seg = SPEC_OCLS( func->etype );
+ addSet(&seg->syms, func);
+ }
+ }
+
addiCodeToeBBlock (ebp, newic, ip);
}
}
}
+/*-----------------------------------------------------------------*/
+/* isLocalWithoutDef - return 1 if sym might be used without a */
+/* defining iCode */
+/*-----------------------------------------------------------------*/
+static int
+isLocalWithoutDef (symbol * sym)
+{
+ if (!IS_AUTO (sym))
+ return 0;
+
+ if (IS_VOLATILE (sym->type))
+ return 0;
+
+ if (sym->_isparm)
+ return 0;
+
+ if (IS_AGGREGATE (sym->type))
+ return 0;
+
+ if (sym->addrtaken)
+ return 0;
+
+ return !sym->defs;
+}
+
/*-----------------------------------------------------------------*/
/* replaceRegEqv - replace all local variables with their reqv */
/*-----------------------------------------------------------------*/
{
int i;
+ /* Update the symbols' def bitvector so we know if there is */
+ /* a defining iCode or not. Only replace a local variable */
+ /* with its register equivalent if there is a defining iCode; */
+ /* otherwise, the port's register allocater may choke. */
+ cseAllBlocks (ebbs, count, TRUE);
+
for (i = 0; i < count; i++)
{
if (ic->op == IFX)
{
-
+ if (IC_COND (ic) &&
+ IS_TRUE_SYMOP (IC_COND (ic)) &&
+ isLocalWithoutDef (OP_SYMBOL (IC_COND (ic))))
+ {
+ werrorfl (ic->filename, ic->lineno,
+ W_LOCAL_NOINIT,
+ OP_SYMBOL (IC_COND (ic))->name);
+ OP_REQV (IC_COND (ic)) = NULL;
+ OP_SYMBOL (IC_COND (ic))->allocreq = 1;
+ }
+
if (IS_TRUE_SYMOP (IC_COND (ic)) &&
OP_REQV (IC_COND (ic)))
IC_COND (ic) = opFromOpWithDU (OP_REQV (IC_COND (ic)),
continue;
}
+
if (ic->op == JUMPTABLE)
{
+ if (IC_JTCOND (ic) &&
+ IS_TRUE_SYMOP (IC_JTCOND (ic)) &&
+ isLocalWithoutDef (OP_SYMBOL (IC_JTCOND (ic))))
+ {
+ werrorfl (ic->filename, ic->lineno,
+ W_LOCAL_NOINIT,
+ OP_SYMBOL (IC_JTCOND (ic))->name);
+ OP_REQV (IC_JTCOND (ic)) = NULL;
+ OP_SYMBOL (IC_JTCOND (ic))->allocreq = 1;
+ }
+
if (IS_TRUE_SYMOP (IC_JTCOND (ic)) &&
OP_REQV (IC_JTCOND (ic)))
IC_JTCOND (ic) = opFromOpWithDU (OP_REQV (IC_JTCOND (ic)),
OP_SYMBOL (IC_RESULT (ic))->uses);
}
+ if (IC_RIGHT (ic) &&
+ IS_TRUE_SYMOP (IC_RIGHT (ic)) &&
+ isLocalWithoutDef (OP_SYMBOL (IC_RIGHT (ic))))
+ {
+ werrorfl (ic->filename, ic->lineno,
+ W_LOCAL_NOINIT,
+ OP_SYMBOL (IC_RIGHT (ic))->name);
+ OP_REQV (IC_RIGHT (ic)) = NULL;
+ OP_SYMBOL (IC_RIGHT (ic))->allocreq = 1;
+ }
+
if (IC_RIGHT (ic) &&
IS_TRUE_SYMOP (IC_RIGHT (ic)) &&
OP_REQV (IC_RIGHT (ic)))
IC_RIGHT (ic)->isaddr = 0;
}
+ if (IC_LEFT (ic) &&
+ IS_TRUE_SYMOP (IC_LEFT (ic)) &&
+ isLocalWithoutDef (OP_SYMBOL (IC_LEFT (ic))))
+ {
+ werrorfl (ic->filename, ic->lineno,
+ W_LOCAL_NOINIT,
+ OP_SYMBOL (IC_LEFT (ic))->name);
+ OP_REQV (IC_LEFT (ic)) = NULL;
+ OP_SYMBOL (IC_LEFT (ic))->allocreq = 1;
+ }
+
if (IC_LEFT (ic) &&
IS_TRUE_SYMOP (IC_LEFT (ic)) &&
OP_REQV (IC_LEFT (ic)))
}
}
+/*-----------------------------------------------------------------*/
+/* findReqv - search for a register equivalent */
+/*-----------------------------------------------------------------*/
+operand *
+findReqv (symbol * prereqv, eBBlock ** ebbs, int count)
+{
+ int i;
+ iCode * ic;
+
+ /* for all blocks do */
+ for (i=0; i<count; i++)
+ {
+ /* for all instructions in the block do */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ if (ic->op == IFX)
+ {
+ if (IS_ITEMP (IC_COND (ic))
+ && OP_SYMBOL (IC_COND (ic))->prereqv == prereqv)
+ return IC_COND (ic);
+ }
+ else if (ic->op == JUMPTABLE)
+ {
+ if (IS_ITEMP (IC_JTCOND (ic))
+ && OP_SYMBOL (IC_JTCOND (ic))->prereqv == prereqv)
+ return IC_JTCOND (ic);
+ }
+ else
+ {
+ if (IS_ITEMP (IC_LEFT (ic))
+ && OP_SYMBOL (IC_LEFT (ic))->prereqv == prereqv)
+ return IC_LEFT (ic);
+ if (IS_ITEMP (IC_RIGHT (ic))
+ && OP_SYMBOL (IC_RIGHT (ic))->prereqv == prereqv)
+ return IC_RIGHT (ic);
+ if (IS_ITEMP (IC_RESULT (ic))
+ && OP_SYMBOL (IC_RESULT (ic))->prereqv == prereqv)
+ return IC_RESULT (ic);
+ }
+ }
+ }
+
+ return NULL;
+}
+
/*-----------------------------------------------------------------*/
/* killDeadCode - eliminates dead assignments */
/*-----------------------------------------------------------------*/
if (SKIP_IC (ic) ||
ic->op == IFX ||
- ic->op == RETURN)
+ ic->op == RETURN ||
+ ic->op == DUMMY_READ_VOLATILE ||
+ ic->op == CRITICAL ||
+ ic->op == ENDCRITICAL)
continue;
+ /* Since both IFX & JUMPTABLE (in SKIP_IC) have been tested for */
+ /* it is now safe to assume IC_LEFT, IC_RIGHT, & IC_RESULT are */
+ /* valid. */
+
/* if the result is volatile then continue */
if (IC_RESULT (ic) && isOperandVolatile (IC_RESULT (ic), FALSE))
continue;
/* if the result is a temp & isaddr then skip */
if (IC_RESULT (ic) && POINTER_SET (ic))
continue;
+
+ if (POINTER_GET (ic) && IS_VOLATILE (operandType (IC_LEFT (ic))->next)
+ && !SPIL_LOC (IC_RESULT (ic)))
+ continue;
/* if the result is used in the remainder of the */
/* block then skip */
continue;
kill = 1;
- }
+ }
kill:
/* kill this one if required */
if (kill)
{
+ bool volLeft = IS_SYMOP (IC_LEFT (ic))
+ && isOperandVolatile (IC_LEFT (ic), FALSE);
+ bool volRight = IS_SYMOP (IC_RIGHT (ic))
+ && isOperandVolatile (IC_RIGHT (ic), FALSE);
+
+ /* a dead address-of operation should die, even if volatile */
+ if (ic->op == ADDRESS_OF)
+ volLeft = FALSE;
+
+ if (ic->next && ic->seqPoint == ic->next->seqPoint
+ && (ic->next->op == '+' || ic->next->op == '-'))
+ {
+ if (isOperandEqual (IC_LEFT(ic), IC_LEFT(ic->next))
+ || isOperandEqual (IC_LEFT(ic), IC_RIGHT(ic->next)))
+ volLeft = FALSE;
+ if (isOperandEqual (IC_RIGHT(ic), IC_LEFT(ic->next))
+ || isOperandEqual (IC_RIGHT(ic), IC_RIGHT(ic->next)))
+ volRight = FALSE;
+ }
+
+ if (POINTER_GET (ic) && IS_VOLATILE (operandType (IC_LEFT (ic))->next))
+ {
+ if (SPIL_LOC (IC_RESULT (ic)))
+ {
+ IC_RESULT (ic) = newiTempFromOp (IC_RESULT (ic));
+ SPIL_LOC (IC_RESULT (ic)) = NULL;
+ }
+ continue;
+ }
+
change = 1;
gchange++;
- /* eliminate this */
- remiCodeFromeBBlock (ebbs[i], ic);
-
+
/* now delete from defUseSet */
deleteItemIf (&ebbs[i]->outExprs, ifDiCodeIsX, ic);
bitVectUnSetBit (ebbs[i]->outDefs, ic->key);
/* and defset of the block */
bitVectUnSetBit (ebbs[i]->defSet, ic->key);
- /* for the left & right remove the usage */
- if (IS_SYMOP (IC_LEFT (ic)))
- bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key);
+ /* If this is the last of a register equivalent, */
+ /* look for a successor register equivalent. */
+ bitVectUnSetBit (OP_DEFS (IC_RESULT (ic)), ic->key);
+ if (IS_ITEMP (IC_RESULT (ic))
+ && OP_SYMBOL (IC_RESULT (ic))->isreqv
+ && bitVectIsZero (OP_DEFS (IC_RESULT (ic))))
+ {
+ symbol * resultsym = OP_SYMBOL (IC_RESULT (ic));
+ symbol * prereqv = resultsym->prereqv;
+
+ if (OP_SYMBOL (prereqv->reqv) == resultsym)
+ {
+ operand * newreqv;
+
+ IC_RESULT (ic) = NULL;
+ newreqv = findReqv (prereqv, ebbs, count);
+ if (newreqv)
+ {
+ prereqv->reqv = newreqv;
+ }
+ }
+ }
+
+ /* delete the result */
+ IC_RESULT (ic) = NULL;
+
+ if (volLeft || volRight)
+ {
+ /* something is volatile, so keep the iCode */
+ /* and change the operator instead */
+ ic->op = DUMMY_READ_VOLATILE;
+
+ /* keep only the volatile operands */
+ if (!volLeft)
+ IC_LEFT (ic) = NULL;
+ if (!volRight)
+ IC_RIGHT (ic) = NULL;
+ }
+ else
+ {
+ /* nothing is volatile, eliminate the iCode */
+ remiCodeFromeBBlock (ebbs[i], ic);
+
+ /* for the left & right remove the usage */
+ if (IS_SYMOP (IC_LEFT (ic)))
+ bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key);
- if (IS_SYMOP (IC_RIGHT (ic)))
- bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key);
+ if (IS_SYMOP (IC_RIGHT (ic)))
+ bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key);
+ }
}
} /* end of all instructions */
}
}
+/*-----------------------------------------------------------------*/
+/* optimizeCastCast - remove unneeded intermediate casts. */
+/* Integer promotion may cast (un)signed char to int and then */
+/* recast the int to (un)signed long. If the signedness of the */
+/* char and long are the same, the cast can be safely performed in */
+/* a single step. */
+/*-----------------------------------------------------------------*/
+static void
+optimizeCastCast (eBBlock ** ebbs, int count)
+{
+ int i;
+ iCode *ic;
+ iCode *uic;
+ sym_link * type1;
+ sym_link * type2;
+ sym_link * type3;
+ symbol * sym;
+
+ for (i = 0; i < count; i++)
+ {
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+
+ if (ic->op == CAST && IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
+ {
+ type1 = operandType (IC_RIGHT (ic));
+ type2 = operandType (IC_RESULT (ic));
+
+ /* Look only for a cast from an integer type to an */
+ /* integer type that has no loss of bits */
+ if (!IS_INTEGRAL (type1) || !IS_INTEGRAL (type2))
+ continue;
+ if (getSize (type2) < getSize (type1))
+ continue;
+
+ /* There must be only one use of this first result */
+ if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) != 1)
+ continue;
+
+ /* This use must be a second cast */
+ uic = hTabItemWithKey (iCodehTab,
+ bitVectFirstBit (OP_USES (IC_RESULT (ic))));
+ if (!uic || uic->op != CAST)
+ continue;
+
+ /* It must be a cast to another integer type that */
+ /* has no loss of bits */
+ type3 = operandType (IC_RESULT (uic));
+ if (!IS_INTEGRAL (type3))
+ continue;
+ if (getSize (type3) < getSize (type2))
+ continue;
+
+ /* The signedness between the first and last types */
+ /* must match */
+ if (SPEC_USIGN (type3) != SPEC_USIGN (type1))
+ continue;
+
+ /* Change the first cast to a simple assignment and */
+ /* let the second cast do all the work */
+ ic->op = '=';
+ IC_LEFT (ic) = NULL;
+ sym = OP_SYMBOL (IC_RESULT (ic));
+ sym->type = copyLinkChain (type1);
+ sym->etype = getSpec (sym->type);
+ }
+ }
+ }
+}
+
/*-----------------------------------------------------------------*/
/* eBBlockFromiCode - creates extended basic blocks from iCode */
/* will return an array of eBBlock pointers */
ebbs = iCodeBreakDown (ic, &count);
saveCount = count;
+ /* hash the iCode keys so that we can quickly index */
+ /* them in the rest of the optimization steps */
+ setToNull ((void *) &iCodehTab);
+ iCodehTab = newHashTable (iCodeKey);
+ hashiCodeKeys (ebbs, count);
+
/* compute the control flow */
computeControlFlow (ebbs, count, 0);
if (options.dump_raw)
dumpEbbsToFileExt (DUMP_RAW1, ebbs, count);
+ optimizeCastCast (ebbs, saveCount);
+
/* do common subexpression elimination for each block */
change = cseAllBlocks (ebbs, saveCount, FALSE);
if (!options.lessPedantic) {
// this is a good place to check missing return values
if (currFunc) {
- if (!IS_VOID(currFunc->etype)) {
+ // the user is on his own with naked functions...
+ if (!IS_VOID(currFunc->etype)
+ && !FUNC_ISNAKED(currFunc->type)) {
eBBlock *bp;
// make sure all predecessors of the last block end in a return
for (bp=setFirstItem(ebbs[saveCount-1]->predList);
bp;
bp=setNextItem(ebbs[saveCount-1]->predList)) {
if (bp->ech->op != RETURN) {
- werror (W_VOID_FUNC, currFunc->name);
+ werrorfl (bp->ech->filename, bp->ech->lineno,
+ W_VOID_FUNC, currFunc->name);
}
}
}
port->assignRegisters (ebbs, count);
/* throw away blocks */
- setToNull ((void **) &graphEdges);
+ setToNull ((void *) &graphEdges);
ebbs = NULL;
return NULL;