static void visit (set **visited, iCode *ic, const int key) { symbol *lbl; while (ic && !isinSet (*visited, ic) && bitVectBitValue (ic->rlive, key)) { addSet (visited, ic); switch (ic->op) { case GOTO: ic = hTabItemWithKey (labelDef, (IC_LABEL (ic))->key); break; case RETURN: ic = hTabItemWithKey (labelDef, returnLabel->key); break; case JUMPTABLE: for (lbl = setFirstItem (IC_JTLABELS (ic)); lbl; lbl = setNextItem (IC_JTLABELS (ic))) visit (visited, hTabItemWithKey (labelDef, lbl->key), key); break; case IFX: visit (visited, hTabItemWithKey (labelDef, (IC_TRUE(ic) ? IC_TRUE (ic) : IC_FALSE (ic))->key), key); ic = ic->next; break; default: ic = ic->next; if (!POINTER_SET (ic) && IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL_CONST (IC_RESULT (ic))->key == key) { addSet (visited, ic); return; } } } }
/*-----------------------------------------------------------------*/ iCode * usedInRemaining (operand * op, iCode * ic) { iCode *lic = ic; if (!IS_SYMOP (op)) return 0; for (; lic; lic = lic->next) { /* if the operand is a parameter */ /* then check for calls and return */ /* true if there is a call */ /* if this is a global variable then return true */ if (lic->op == CALL || lic->op == PCALL) { if ((IS_PARM (op) && isParameterToCall (IC_ARGS (lic), op)) || isOperandGlobal (op)) return lic; } if (ic->op == SEND && isOperandEqual (IC_LEFT (lic), op)) return lic; if (SKIP_IC1 (lic)) continue; /* if ifx then check the condition */ if (lic->op == IFX && isOperandEqual (IC_COND (lic), op)) return lic; if (lic->op == JUMPTABLE && isOperandEqual (IC_JTCOND (lic), op)) return lic; if (IC_RIGHT (lic) && isOperandEqual (IC_RIGHT (lic), op)) return lic; if (IC_LEFT (lic) && isOperandEqual (IC_LEFT (lic), op)) return lic; /* for a pointer assignment usage */ if (POINTER_SET (lic) && isOperandEqual (op, IC_RESULT (lic))) return lic; else if (IC_RESULT (lic) && isOperandEqual (IC_RESULT (lic), op)) return NULL; } return NULL; }
static bool _hasNativeMulFor (iCode * ic, sym_link * left, sym_link * right) { sym_link *test = NULL; int result_size = IS_SYMOP(IC_RESULT(ic)) ? getSize(OP_SYM_TYPE(IC_RESULT(ic))) : 4; if (ic->op != '*') { return FALSE; } if (IS_LITERAL (left)) test = left; else if (IS_LITERAL (right)) test = right; /* 8x8 unsigned multiplication code is shorter than call overhead for the multiplication routine. */ else if (IS_CHAR (right) && IS_UNSIGNED (right) && IS_CHAR (left) && IS_UNSIGNED (left) && !IS_GB) { return TRUE; } /* Same for any multiplication with 8 bit result. */ else if (result_size == 1 && !IS_GB) { return TRUE; } else { return FALSE; } if (getSize (test) <= 2) { return TRUE; } return FALSE; }
/*--------------------------------------------------------------------*/ symbol * ptrBaseRematSym (symbol *ptrsym) { iCode * ric; if (!ptrsym->remat) return NULL; ric = ptrsym->rematiCode; while (ric) { if (ric->op == '+' || ric->op == '-') ric = OP_SYMBOL (IC_LEFT (ric))->rematiCode; else if (IS_CAST_ICODE (ric)) ric = OP_SYMBOL (IC_RIGHT (ric))->rematiCode; else break; } if (ric && IS_SYMOP (IC_LEFT (ric))) return OP_SYMBOL (IC_LEFT (ric)); else return NULL; }
/*-----------------------------------------------------------------*/ static S4O_RET scan4op (lineNode **pl, const char *pReg, const char *untilOp, lineNode **plCond) { char *p; int len; bool isConditionalJump; int rIdx; S4O_RET ret; bool findPushPop; findPushPop = untilOp && (strcmp (untilOp, "push") == 0 || strcmp (untilOp, "pop") == 0); /* pReg points to e.g. "ar0"..."ar7" */ len = strlen (pReg); /* get index into pReg table */ for (rIdx = 0; rIdx < mcs51_nRegs; ++rIdx) if (strcmp (regs8051[rIdx].name, pReg + 1) == 0) break; /* sanity check */ if (rIdx >= mcs51_nRegs) { DEADMOVEERROR(); return S4O_ABORT; } for (; *pl; *pl = (*pl)->next) { if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment) continue; /* don't optimize across inline assembler, e.g. isLabel doesn't work there */ if ((*pl)->isInline) return S4O_ABORT; if ((*pl)->visited) return S4O_VISITED; (*pl)->visited = TRUE; /* found untilOp? */ if (untilOp && strncmp ((*pl)->line, untilOp, strlen (untilOp)) == 0) { p = (*pl)->line + strlen (untilOp); if (*p == '\t' && strncmp (p + 1, pReg, len) == 0) return S4O_FOUNDOPCODE; else { /* found untilOp but without our pReg */ return S4O_ABORT; } } /* found pReg? */ p = strchr ((*pl)->line, '\t'); if (p) { /* skip '\t' */ p++; /* when looking for push or pop and we find a direct access of sp: abort */ if (findPushPop && strstr (p, "sp")) return S4O_ABORT; /* course search */ if (strstr (p, pReg + 1)) { /* ok, let's have a closer look */ /* does opcode read from pReg? */ if (bitVectBitValue (port->peep.getRegsRead ((*pl)), rIdx)) return S4O_RD_OP; /* does opcode write to pReg? */ if (bitVectBitValue (port->peep.getRegsWritten ((*pl)), rIdx)) return S4O_WR_OP; /* we can get here, if the register name is part of a variable name: ignore it */ } } /* found label? */ if ((*pl)->isLabel) { const char *start; char label[SDCC_NAME_MAX + 1]; int len; if (!isLabelDefinition ((*pl)->line, &start, &len, FALSE)) return S4O_ABORT; memcpy (label, start, len); label[len] = '\0'; /* register passing this label */ if (!setLabelRefPassedLabel (label)) { DEADMOVEERROR(); return S4O_ABORT; } continue; } /* branch or terminate? */ isConditionalJump = FALSE; switch ((*pl)->line[0]) { case 'a': if (strncmp ("acall", (*pl)->line, 5) == 0) { /* for comments see 'lcall' */ ret = termScanAtFunc (*pl, rIdx); if (ret != S4O_CONTINUE) return ret; break; } if (strncmp ("ajmp", (*pl)->line, 4) == 0) { *pl = findLabel (*pl); if (!*pl) return S4O_ABORT; } break; case 'c': if (strncmp ("cjne", (*pl)->line, 4) == 0) { isConditionalJump = TRUE; break; } break; case 'd': if (strncmp ("djnz", (*pl)->line, 4) == 0) { isConditionalJump = TRUE; break; } break; case 'j': if (strncmp ("jmp", (*pl)->line, 3) == 0) /* "jmp @a+dptr": no chance to trace execution */ return S4O_ABORT; if (strncmp ("jc", (*pl)->line, 2) == 0 || strncmp ("jnc", (*pl)->line, 3) == 0 || strncmp ("jz", (*pl)->line, 2) == 0 || strncmp ("jnz", (*pl)->line, 3) == 0) { isConditionalJump = TRUE; break; } if (strncmp ("jbc", (*pl)->line, 3) == 0 || strncmp ("jb", (*pl)->line, 2) == 0 || strncmp ("jnb", (*pl)->line, 3) == 0) { isConditionalJump = TRUE; break; } break; case 'l': if (strncmp ("lcall", (*pl)->line, 5) == 0) { const char *p = (*pl)->line+5; while (*p == ' ' || *p == '\t') p++; while (isdigit (*p)) p++; if (isdigit(p[-1]) && *p == '$') /* at least one digit */ { /* this is a temp label for a pcall */ *pl = findLabel (*pl); if (!*pl) return S4O_ABORT; break; } ret = termScanAtFunc (*pl, rIdx); /* If it's a 'normal' 'caller save' function call, all registers have been saved until the 'lcall'. The 'life range' of all registers end at the lcall, and we can terminate our search. * If the function is 'banked', the registers r0, r1 and r2 are used to tell the trampoline the destination. After that their 'life range' ends just like the other registers. * If it's a 'callee save' function call, registers are saved by the callee. We've got no information, if the register might live beyond the lcall. Therefore we've to continue the search. */ if (ret != S4O_CONTINUE) return ret; break; } if (strncmp ("ljmp", (*pl)->line, 4) == 0) { *pl = findLabel (*pl); if (!*pl) return S4O_ABORT; } break; case 'p': if (strncmp ("pop", (*pl)->line, 3) == 0 || strncmp ("push", (*pl)->line, 4) == 0) return S4O_PUSHPOP; break; case 'r': if (strncmp ("reti", (*pl)->line, 4) == 0) return S4O_TERM; if (strncmp ("ret", (*pl)->line, 3) == 0) { /* pcall uses 'ret' */ if (isFunc (*pl)) { /* for comments see 'lcall' */ ret = termScanAtFunc (*pl, rIdx); if (ret != S4O_CONTINUE) return ret; break; } /* it's a normal function return */ if (!((*pl)->ic) || (IS_SYMOP (IC_LEFT ((*pl)->ic)) && IS_FUNC (OP_SYM_TYPE(IC_LEFT ((*pl)->ic))) && FUNC_CALLEESAVES (OP_SYM_TYPE(IC_LEFT ((*pl)->ic))))) return S4O_ABORT; else return S4O_TERM; } break; case 's': if (strncmp ("sjmp", (*pl)->line, 4) == 0) { *pl = findLabel (*pl); if (!*pl) return S4O_ABORT; } break; default: break; } /* switch ((*pl)->line[0]) */ if (isConditionalJump) { *plCond = findLabel (*pl); if (!*plCond) return S4O_ABORT; return S4O_CONDJMP; } } /* for (; *pl; *pl = (*pl)->next) */ return S4O_ABORT; }
/* * Actually emit the initial values in .asm format. */ static void emitIvals(struct dbuf_s *oBuf, symbol *sym, initList *list, long lit, int size) { int i; ast *node; operand *op; value *val = NULL; int inCodeSpace = 0; char *str = NULL; int in_code; assert (size <= sizeof(long)); assert (!list || (list->type == INIT_NODE)); node = list ? list->init.node : NULL; in_code = emitIvalLabel(oBuf, sym); if (!in_code) dbuf_printf (oBuf, "\tdb\t"); if (!node) { // initialize as zero for (i = 0; i < size; i++) { if (in_code) { dbuf_printf (oBuf, "\tretlw 0x%02x\n", lit & 0xff); } else { dbuf_printf (oBuf, "%s0x%02x", (i == 0) ? "" : ", ", lit & 0xff); } lit >>= 8; } // for if (!in_code) dbuf_printf (oBuf, "\n"); return; } // if op = NULL; if (constExprTree(node) && (val = constExprValue(node, 0))) { op = operandFromValue(val); DEBUGprintf ("%s: constExpr ", __FUNCTION__); } else if (IS_AST_VALUE(node)) { op = operandFromAst(node, 0); } else if (IS_AST_OP(node)) { str = parseIvalAst(node, &inCodeSpace); DEBUGprintf("%s: AST_OP: %s\n", __FUNCTION__, str); op = NULL; } else { assert ( !"Unhandled construct in intializer." ); } if (op) { aopOp(op, NULL, 1); assert(AOP(op)); //printOperand(op, of); } for (i = 0; i < size; i++) { char *text; /* * FIXME: This is hacky and needs some more thought. */ if (op && IS_SYMOP(op) && IS_FUNC(OP_SYM_TYPE(op))) { /* This branch is introduced to fix #1427663. */ PCOI(AOP(op)->aopu.pcop)->offset+=i; text = get_op(AOP(op)->aopu.pcop, NULL, 0); PCOI(AOP(op)->aopu.pcop)->offset-=i; } else { text = op ? aopGet(AOP(op), i, 0, 0) : get_op(newpCodeOpImmd(str, i, 0, inCodeSpace, 0), NULL, 0); } // if if (in_code) { dbuf_printf (oBuf, "\tretlw %s\n", text); } else { dbuf_printf (oBuf, "%s%s", (i == 0) ? "" : ", ", text); } } // for if (!in_code) dbuf_printf (oBuf, "\n"); }
/*-----------------------------------------------------------------*/ int killDeadCode (eBBlock ** ebbs, int count) { int change = 1; int gchange = 0; int i = 0; /* basic algorithm :- */ /* first the exclusion rules :- */ /* 1. if result is a global or volatile then skip */ /* 2. if assignment and result is a temp & isaddr then skip */ /* since this means array & pointer access, will be taken */ /* care of by alias analysis. */ /* 3. if the result is used in the remainder of the block skip */ /* 4. if this definition does not reach the end of the block */ /* i.e. the result is not present in the outExprs then KILL */ /* 5. if it reaches the end of block & is used by some success */ /* or then skip */ /* else KILL */ /* this whole process is carried on iteratively till no change */ while (1) { change = 0; /* for all blocks do */ for (i = 0; i < count; i++) { iCode *ic; /* for all instructions in the block do */ for (ic = ebbs[i]->sch; ic; ic = ic->next) { int kill, j; kill = 0; if (SKIP_IC (ic) || ic->op == IFX || ic->op == RETURN) continue; /* 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 the result is used in the remainder of the */ /* block then skip */ if (usedInRemaining (IC_RESULT (ic), ic->next)) continue; /* does this definition reach the end of the block or the usage is zero then we can kill */ if (!bitVectBitValue (ebbs[i]->outDefs, ic->key)) kill = 1; /* if not we can kill it */ else { /* if this is a global variable or function parameter */ /* we cannot kill anyway */ if (isOperandGlobal (IC_RESULT (ic)) || (OP_SYMBOL (IC_RESULT (ic))->_isparm && !OP_SYMBOL (IC_RESULT (ic))->ismyparm)) continue; /* if we are sure there are no usages */ if (bitVectIsZero (OP_USES (IC_RESULT (ic)))) { kill = 1; goto kill; } /* reset visited flag */ for (j = 0; j < count; ebbs[j++]->visited = 0); /* find out if this definition is alive */ if (applyToSet (ebbs[i]->succList, isDefAlive, ic)) continue; kill = 1; } kill: /* kill this one if required */ if (kill) { 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 (IS_SYMOP (IC_RIGHT (ic))) bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key); } } /* end of all instructions */ if (!ebbs[i]->sch && !ebbs[i]->noPath) disconBBlock (ebbs[i], ebbs, count); } /* end of for all blocks */ if (!change) break; } /* end of while(1) */ return gchange; }
/*-----------------------------------------------------------------*/ static void computeClash (eBBlock ** ebbs, int count) { int i; /* for all blocks do */ for (i = 0; i < count; i++) { iCode *ic; /* for every iCode do */ for (ic = ebbs[i]->sch; ic; ic = ic->next) { symbol *sym1, *sym2; int key1, key2; /* for all iTemps alive at this iCode */ for (key1 = 1; key1 < ic->rlive->size; key1++) { if (!bitVectBitValue(ic->rlive, key1)) continue; sym1 = hTabItemWithKey(liveRanges, key1); if (!sym1->isitmp) continue; /* for all other iTemps alive at this iCode */ for (key2 = key1+1; key2 < ic->rlive->size; key2++) { if (!bitVectBitValue(ic->rlive, key2)) continue; sym2 = hTabItemWithKey(liveRanges, key2); if (!sym2->isitmp) continue; /* if the result and left or right is an iTemp */ /* than possibly the iTemps do not clash */ if ((ic->op != JUMPTABLE) && (ic->op != IFX) && IS_ITEMP(IC_RESULT(ic)) && (IS_ITEMP(IC_LEFT(ic)) || IS_ITEMP(IC_RIGHT(ic)))) { if (OP_SYMBOL(IC_RESULT(ic))->key == key1 && sym1->liveFrom == ic->seq && sym2->liveTo == ic->seq) { if (IS_SYMOP(IC_LEFT(ic))) if (OP_SYMBOL(IC_LEFT(ic))->key == key2) continue; if (IS_SYMOP(IC_RIGHT(ic))) if (OP_SYMBOL(IC_RIGHT(ic))->key == key2) continue; } if (OP_SYMBOL(IC_RESULT(ic))->key == key2 && sym2->liveFrom == ic->seq && sym1->liveTo == ic->seq) { if (IS_SYMOP(IC_LEFT(ic))) if (OP_SYMBOL(IC_LEFT(ic))->key == key1) continue; if (IS_SYMOP(IC_RIGHT(ic))) if (OP_SYMBOL(IC_RIGHT(ic))->key == key1) continue; } } /* the iTemps do clash. set the bits in clashes */ sym1->clashes = bitVectSetBit (sym1->clashes, key2); sym2->clashes = bitVectSetBit (sym2->clashes, key1); /* check if they share the same spill location */ /* what is this good for? */ if (SYM_SPIL_LOC(sym1) && SYM_SPIL_LOC(sym2) && SYM_SPIL_LOC(sym1) == SYM_SPIL_LOC(sym2)) { if (sym1->reqv && !sym2->reqv) SYM_SPIL_LOC(sym2)=NULL; else if (sym2->reqv && !sym1->reqv) SYM_SPIL_LOC(sym1)=NULL; else if (sym1->used > sym2->used) SYM_SPIL_LOC(sym2)=NULL; else SYM_SPIL_LOC(sym1)=NULL; } } } } } }
/*-----------------------------------------------------------------*/ static void rlivePoint (eBBlock ** ebbs, int count, bool emitWarnings) { int i, key; eBBlock *succ; bitVect *alive; /* for all blocks do */ for (i = 0; i < count; i++) { iCode *ic; /* for all instructions in this block do */ for (ic = ebbs[i]->sch; ic; ic = ic->next) { if (!ic->rlive) ic->rlive = newBitVect (operandKey); if (SKIP_IC2(ic)) continue; if (ic->op == JUMPTABLE && IS_SYMOP(IC_JTCOND(ic))) { incUsed (ic, IC_JTCOND(ic)); if (!IS_AUTOSYM(IC_JTCOND(ic))) continue; findPrevUse (ebbs[i], ic, IC_JTCOND(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_JTCOND(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_JTCOND(ic)->key); findNextUse (ebbs[i], ic->next, IC_JTCOND(ic)); } continue; } if (ic->op == IFX && IS_SYMOP(IC_COND(ic))) { incUsed (ic, IC_COND(ic)); if (!IS_AUTOSYM(IC_COND(ic))) continue; findPrevUse (ebbs[i], ic, IC_COND(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_COND(ic))) { unvisitBlocks (ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_COND(ic)->key); findNextUse (ebbs[i], ic->next, IC_COND(ic)); } continue; } if (IS_SYMOP(IC_LEFT(ic))) { incUsed (ic, IC_LEFT(ic)); if (IS_AUTOSYM(IC_LEFT(ic)) && ic->op != ADDRESS_OF) { findPrevUse (ebbs[i], ic, IC_LEFT(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_LEFT(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_LEFT(ic)->key); findNextUse (ebbs[i], ic->next, IC_LEFT(ic)); /* if this is a send extend the LR to the call */ if (ic->op == SEND) { iCode *lic; for (lic = ic; lic; lic = lic->next) { if (lic->op == CALL || lic->op == PCALL) { markAlive (ic, lic->prev, IC_LEFT (ic)->key); break; } } } } } } if (IS_SYMOP(IC_RIGHT(ic))) { incUsed (ic, IC_RIGHT(ic)); if (IS_AUTOSYM(IC_RIGHT(ic))) { findPrevUse (ebbs[i], ic, IC_RIGHT(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_RIGHT(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_RIGHT(ic)->key); findNextUse (ebbs[i], ic->next, IC_RIGHT(ic)); } } } if (POINTER_SET(ic) && IS_SYMOP(IC_RESULT(ic))) incUsed (ic, IC_RESULT(ic)); if (IS_AUTOSYM(IC_RESULT(ic))) { if (POINTER_SET(ic)) { findPrevUse (ebbs[i], ic, IC_RESULT(ic), ebbs, count, emitWarnings); } if (IS_ITEMP(IC_RESULT(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_RESULT(ic)->key); findNextUse (ebbs[i], ic->next, IC_RESULT(ic)); /* findNextUse sometimes returns 0 here, which means that ic is dead code. Something should be done about this dead code since e.g. register allocation suffers. */ } } if (!POINTER_SET(ic) && IC_RESULT(ic)) ic->defKey = IC_RESULT(ic)->key; } /* check all symbols that are alive in the last instruction */ /* but are not alive in all successors */ succ = setFirstItem (ebbs[i]->succList); if (!succ) continue; alive = succ->sch->rlive; while ((succ = setNextItem (ebbs[i]->succList))) { if (succ->sch) alive = bitVectIntersect (alive, succ->sch->rlive); } if (ebbs[i]->ech) alive = bitVectCplAnd ( bitVectCopy (ebbs[i]->ech->rlive), alive); if(!alive) continue; for (key = 1; key < alive->size; key++) { if (!bitVectBitValue (alive, key)) continue; unvisitBlocks(ebbs, count); findNextUseSym (ebbs[i], NULL, hTabItemWithKey (liveRanges, key)); } } }
/** Register reduction for assignment. */ static int packRegsForAssign (iCode *ic, eBBlock *ebp) { iCode *dic, *sic; if (!IS_ITEMP (IC_RIGHT (ic)) || OP_SYMBOL (IC_RIGHT (ic))->isind || OP_LIVETO (IC_RIGHT (ic)) > ic->seq) return 0; /* Avoid having multiple named address spaces in one iCode. */ if (IS_SYMOP (IC_RESULT (ic)) && SPEC_ADDRSPACE (OP_SYMBOL (IC_RESULT (ic))->etype)) return 0; /* find the definition of iTempNN scanning backwards if we find a a use of the true symbol in before we find the definition then we cannot */ for (dic = ic->prev; dic; dic = dic->prev) { /* PENDING: Don't pack across function calls. */ if (dic->op == CALL || dic->op == PCALL) { dic = NULL; break; } if (SKIP_IC2 (dic)) continue; if (dic->op == IFX) { if (IS_SYMOP (IC_COND (dic)) && (IC_COND (dic)->key == IC_RESULT (ic)->key || IC_COND (dic)->key == IC_RIGHT (ic)->key)) { dic = NULL; break; } } else { if (IS_TRUE_SYMOP (IC_RESULT (dic)) && IS_OP_VOLATILE (IC_RESULT (dic))) { dic = NULL; break; } if (IS_SYMOP (IC_RESULT (dic)) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key) { if (POINTER_SET (dic)) dic = NULL; break; } if (IS_SYMOP (IC_RIGHT (dic)) && (IC_RIGHT (dic)->key == IC_RESULT (ic)->key || IC_RIGHT (dic)->key == IC_RIGHT (ic)->key)) { dic = NULL; break; } if (IS_SYMOP (IC_LEFT (dic)) && (IC_LEFT (dic)->key == IC_RESULT (ic)->key || IC_LEFT (dic)->key == IC_RIGHT (ic)->key)) { dic = NULL; break; } if (IS_SYMOP (IC_RESULT (dic)) && IC_RESULT (dic)->key == IC_RESULT (ic)->key) { dic = NULL; break; } } } if (!dic) return 0; /* did not find */ /* if assignment then check that right is not a bit */ if (ASSIGNMENT (ic) && !POINTER_SET (ic)) { sym_link *etype = operandType (IC_RESULT (dic)); if (IS_BITFIELD (etype)) { /* if result is a bit too then it's ok */ etype = operandType (IC_RESULT (ic)); if (!IS_BITFIELD (etype)) { return 0; } } } /* if the result is on stack or iaccess then it must be the same atleast one of the operands */ if (OP_SYMBOL (IC_RESULT (ic))->onStack || OP_SYMBOL (IC_RESULT (ic))->iaccess) { /* the operation has only one symbol operator then we can pack */ if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) || (IC_RIGHT (dic) && !IS_SYMOP (IC_RIGHT (dic)))) goto pack; if (!((IC_LEFT (dic) && IC_RESULT (ic)->key == IC_LEFT (dic)->key) || (IC_RIGHT (dic) && IC_RESULT (ic)->key == IC_RIGHT (dic)->key))) return 0; } pack: /* found the definition */ /* replace the result with the result of */ /* this assignment and remove this assignment */ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key); IC_RESULT (dic) = IC_RESULT (ic); if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq) { OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq; } /* delete from liverange table also delete from all the points inbetween and the new one */ for (sic = dic; sic != ic; sic = sic->next) { bitVectUnSetBit (sic->rlive, IC_RESULT (ic)->key); if (IS_ITEMP (IC_RESULT (dic))) bitVectSetBit (sic->rlive, IC_RESULT (dic)->key); } remiCodeFromeBBlock (ebp, ic); // PENDING: Check vs mcs51 bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key); hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); return 1; }
/*--------------------------------------------------------------------*/ int ptrPseudoSymSafe (symbol *sym, iCode *dic) { symbol * ptrsym; symbol * basesym; iCode * ric; iCode * ic; int ptrsymDclType; //int isGlobal; assert(POINTER_GET (dic)); /* Can't if spills to this symbol are prohibited */ if (sym->noSpilLoc) return 0; /* Get the pointer */ if (!IS_SYMOP (IC_LEFT (dic))) return 0; ptrsym = OP_SYMBOL (IC_LEFT (dic)); /* Must be a rematerializable pointer */ if (!ptrsym->remat) return 0; /* The pointer type must be uncasted */ if (IS_CAST_ICODE (ptrsym->rematiCode)) return 0; /* The symbol's live range must not preceed its definition */ if (dic->seq > sym->liveFrom) return 0; /* Ok, this is a good candidate for a pseudo symbol. */ /* However, we must check for two hazards: */ /* 1) The symbol's live range must not include a CALL */ /* or PCALL iCode. */ /* 2) The symbol's live range must not include any */ /* writes to the variable the pointer rematerializes */ /* within (to avoid aliasing problems) */ /* Find the base symbol the rematerialization is based on */ ric = ptrsym->rematiCode; while (ric->op == '+' || ric->op == '-') ric = OP_SYMBOL (IC_LEFT (ric))->rematiCode; if (IS_CAST_ICODE(ric)) return 0; basesym = OP_SYMBOL (IC_LEFT (ric)); //isGlobal = !basesym->islocal && !basesym->ismyparm; ptrsymDclType = aggrToPtrDclType (ptrsym->type, FALSE); ic = dic->next; while (ic && ic->seq <= sym->liveTo) { if (!(SKIP_IC3 (ic) || ic->op == IFX)) { /* Check for hazard #1 */ if ((ic->op == CALL || ic->op == PCALL) /* && isGlobal */ ) { if (ic->seq <= sym->liveTo) return 0; } /* Check for hazard #2 */ else if (POINTER_SET (ic)) { symbol * ptrsym2 = OP_SYMBOL (IC_RESULT (ic)); if (ptrsym2->remat) { /* Must not be the same base symbol */ if (basesym == ptrBaseRematSym (ptrsym2)) return 0; } else { int ptrsym2DclType = aggrToPtrDclType (ptrsym2->type, FALSE); /* Pointer must have no memory space in common */ if (ptrsym2DclType == ptrsymDclType || ptrsym2DclType == GPOINTER || ptrsymDclType == GPOINTER) return 0; } } else if (IC_RESULT (ic)) { symbol * rsym = OP_SYMBOL (IC_RESULT (ic)); /* Make sure there is no conflict with another pseudo symbol */ if (rsym->psbase == basesym) return 0; if (rsym->isspilt && rsym->usl.spillLoc) rsym = rsym->usl.spillLoc; if (rsym->psbase == basesym) return 0; } } if (ic->seq == sym->liveTo) break; ic = ic->next; } /* If the live range went past the end of the defining basic */ /* block, then a full analysis is too complicated to attempt */ /* here. To be safe, we must assume the worst. */ if (!ic) return 0; /* Ok, looks safe */ return 1; }