Newer
Older
} // end of SMPFunction::AnalyzeMetadataLiveness()
// Propagate the metadata Status for UseOp/SSANum to its global DEF.
// Return true if successful.
bool SMPFunction::PropagateGlobalMetadata(op_t UseOp, SMPMetadataType Status, int SSANum) {
bool changed = false;
if ((0 > SSANum) || (o_void == UseOp.type))
return false;
// Find the DEF of UseOp with SSANum.
bool FoundDef = false;
list<SMPInstr *>::iterator InstIter;
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
set<DefOrUse, LessDefUse>::iterator CurrDef;
set<DefOrUse, LessDefUse>::iterator CurrUse;
CurrDef = CurrInst->FindDef(UseOp);
if (CurrDef != CurrInst->GetLastDef()) {
if (SSANum == CurrDef->GetSSANum()) {
FoundDef = true;
if (Status != CurrDef->GetMetadataStatus()) {
CurrDef = CurrInst->SetDefMetadata(UseOp, Status);
changed = (CurrDef != CurrInst->GetLastDef());
// If source operand was memory, we have two cases.
// (1) The instruction could be a load, in which
// case we should simply terminate the
// propagation, because the prior DEF of a memory
// location is always considered live metadata
// already, and we do not want to propagate liveness
// to the address regs in the USE list.
// EXCEPTION: For safe funcs, we propagate liveness
// for stack locations.
// (2) We could have an arithmetic operation such
// as reg := reg arithop memsrc. In this case, we
// still do not want to propagate through the memsrc,
// (with the same safe func EXCEPTION),
// but the register is both DEF and USE and we need
// to propagate through the register.
if (CurrInst->HasSourceMemoryOperand()) {
if (this->SafeFunc) {
op_t MemSrcOp = CurrInst->MDGetMemUseOp();
assert(o_void != MemSrcOp.type);
if (MDIsStackAccessOpnd(MemSrcOp, this->UseFP)) {
// We have a SafeFunc stack access. This is
// the EXCEPTION case where we want to
// propagate metadata liveness for a memory
// location.
CurrUse = CurrInst->FindUse(MemSrcOp);
assert(CurrUse != CurrInst->GetLastUse());
if (this->IsGlobalName(MemSrcOp)) {
changed |= this->PropagateGlobalMetadata(MemSrcOp,
Status, CurrUse->GetSSANum());
}
else {
changed |= CurrInst->GetBlock()->PropagateLocalMetadata(MemSrcOp,
Status, CurrUse->GetSSANum());
}
} // end if stack access operand
} // end if SafeFunc
if (3 == CurrInst->GetOptType()) { // move inst
clc5q
committed
break; // load address regs are not live metadata
}
else if ((5 == CurrInst->GetOptType())
|| (NN_and == CurrInst->GetCmd().itype)
|| (NN_or == CurrInst->GetCmd().itype)
|| (NN_xor == CurrInst->GetCmd().itype)) {
// add, subtract, and, or with memsrc
// Find the DEF reg in the USE list.
CurrUse = CurrInst->FindUse(UseOp);
assert(CurrUse != CurrInst->GetLastUse());
changed |= this->PropagateGlobalMetadata(UseOp,
Status, CurrUse->GetSSANum());
break;
}
} // end if memory source
// Now, propagate the metadata status to all the
// non-memory, non-flags-reg, non-special-reg
// (i.e. regular registers) USEs.
CurrUse = CurrInst->GetFirstUse();
while (CurrUse != CurrInst->GetLastUse()) {
op_t UseOp = CurrUse->GetOp();
// NOTE: **!!** To be less conservative, we
// should propagate less for exchange category
// instructions.
if ((UseOp.type == o_reg) && (!UseOp.is_reg(R_sp))
&& (!(this->UseFP && UseOp.is_reg(R_bp)))
&& (!UseOp.is_reg(X86_FLAGS_REG))) {
changed |= this->PropagateGlobalMetadata(UseOp,
Status, CurrUse->GetSSANum());
}
else {
changed |= CurrInst->GetBlock()->PropagateLocalMetadata(UseOp,
Status, CurrUse->GetSSANum());
}
}
break;
}
}
}
if (!FoundDef) {
// Check the Phi functions
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
set<SMPPhiFunction, LessPhi>::iterator DefPhi;
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
DefPhi = CurrBlock->FindPhi(UseOp);
if (DefPhi != CurrBlock->GetLastPhi()) {
if (SSANum == DefPhi->GetDefSSANum()) {
if (Status != DefPhi->GetDefMetadata()) {
DefPhi = CurrBlock->SetPhiDefMetadata(UseOp, Status);
changed = true;
// If the Phi DEF has live metadata, then the Phi
// USEs each have live metadata. Propagate.
int UseSSANum;
for (size_t index = 0; index < DefPhi->GetPhiListSize(); ++index) {
UseSSANum = DefPhi->GetUseSSANum(index);
// UseSSANum can be -1 in some cases because
// we conservatively make EAX and EDX be USEs
// of all return instructions, when the function
// might have a void return type, making it
// appear as if an uninitialized EAX or EDX
// could make it to the return block.
if (0 <= UseSSANum) {
changed |= this->PropagateGlobalMetadata(UseOp,
Status, UseSSANum);
}
}
}
FoundDef = true;
break;
}
}
} // end for all blocks
} // end if !FoundDef
if (!FoundDef) {
clc5q
committed
SMP_msg("ERROR: Could not find DEF of SSANum %d for: ", SSANum);
clc5q
committed
SMP_msg(" in function %s\n", this->GetFuncName());
}
return changed;
} // end of SMPFunction::PropagateGlobalMetadata()
// Find consecutive DEFs of the same type and mark the second one redundant.
void SMPFunction::FindRedundantMetadata(void) {
list<SMPBasicBlock *>::iterator CurrBlock;
bool changed = false;
for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
changed |= (*CurrBlock)->FindRedundantLocalMetadata(this->SafeFunc);
}
return;
} // end of SMPFunction::FindRedundantMetadata()
clc5q
committed
// Do we not care if DEF underflowed, due to how it is used?
bool SMPFunction::IsBenignUnderflowDEF(op_t DefOp, int DefSSANum, size_t DefAddr) {
bool benign = false;
list<SMPInstr *>::iterator InstIter;
clc5q
committed
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
set<DefOrUse, LessDefUse>::iterator DefIter, UseIter;
int UseSSANum;
SMPOperandType DefType;
op_t UseInstDefOp;
// We are looking to suppress overflow and underflow warnings on the following
// code sequence: PTR1-PTR2+1 gets a loop invariant code motion optimization
// that pulls temp := 1-PTR2 out of the loop, and leaves temp2 := PTR1+temp
// inside the loop. The hoisted subtraction could underflow, and the addition
// that is not hoisted could overflow. The net effect of these two instructions
// is benign, however, so we want to suppress underflow and overflow checks on
// both of them, but only if we can match the pair of instructions.
// We know that DefOp/DefAddr/DefSSANum refer to a subtraction instruction that
// produces a NEGATEDPTR result. We only need to find the paired addition instruction
// that USEs the same SSA name to produce a PTROFFSET result to prove that we have
// a case of benign underflow and overflow. If we find such a pair, we will mark
// both of their DEF results as benign overflows to suppress overflow checks.
// PAINFUL: Linear search of instructions. Need to address this in the future.
// Perhaps we should have a map of UseHashValue to InstAddr, but that is more
// memory consumption. Sure would be useful, though.
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
clc5q
committed
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
UseIter = CurrInst->FindUse(DefOp);
UseSSANum = UseIter->GetSSANum();
if (UseSSANum == DefSSANum) {
// Only remaining question: Do we produce a PTROFFSET in CurrInst? (If we do,
// that implies we had an addition, so we don't need to check that.)
DefIter = CurrInst->GetFirstNonFlagsDef();
DefType = DefIter->GetType();
// NOTE: Make this more general. What if we just move the NEGATEDPTR into a register
// and then the next instruction, with different SSA name, produces the PTROFFSET?
// !!!!!*****!!!!!
if (IsEqType(DefType, PTROFFSET)) {
// Found a pair. Mark both DEFs as benign and return true.
benign = true;
// Note that we have two possibilities for the addition. The NEGATEDPTR could be
// both the DEF and a USE, e.g. add negptr,ptr1; or the NEGATEDPTR could be
// just a USE, e.g. add reg,negptr, so that reg is overwritten and becomes a
// PTROFFSET. It really does not matter. The point is that we want to ignore
// overflow on this addition, and also on the subtraction that produced the
// NEGATEDPTR, so we mark the DEF in each instruction as benignly overflowing.
UseInstDefOp = DefIter->GetOp();
CurrInst->SetDefNoOverflow(UseInstDefOp, true);
SMPInstr *DefInst = this->GetInstFromAddr(DefAddr);
DefInst->SetDefNoOverflow(DefOp, true);
clc5q
committed
break;
}
}
}
return benign;
} // end of SMPFunction::IsBenignUnderflowDEF()
bool SMPFunction::HasIntErrorCallSink(op_t DefOp, int DefSSANum, size_t DefAddr, std::string &SinkString) {
bool FoundSink = false;
this->ResetProcessedBlocks(); // prepare for recursion through blocks
SinkString.clear();
SMPBasicBlock *CurrBlock = this->GetBlockFromInstAddr(DefAddr);
assert(CurrBlock != NULL);
clc5q
committed
FoundSink = CurrBlock->IsCriticalSink(DefOp, DefSSANum, SinkString);
clc5q
committed
return FoundSink;
} // end of SMPFunction::HasIntErrorCallSink()
// Compute SSA form data structures across the function.
void SMPFunction::ComputeSSA(void) {
clc5q
committed
bool DumpFlag = false;
#if SMP_DEBUG_DATAFLOW
DumpFlag |= (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
DebugFlag |= (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
#if 1
if (DumpFlag)
this->Dump();
#endif
clc5q
committed
if (DebugFlag) SMP_msg("Computing IDoms.\n");
clc5q
committed
if (DebugFlag) SMP_msg("Computing Dom frontiers.\n");
this->ComputeDomFrontiers();
clc5q
committed
if (DebugFlag) SMP_msg("Computing global names.\n");
this->ComputeGlobalNames();
clc5q
committed
if (DebugFlag) SMP_msg("Computing blocks defined in.\n");
this->ComputeBlocksDefinedIn();
clc5q
committed
if (DebugFlag) SMP_msg("Inserting Phi functions.\n");
this->InsertPhiFunctions();
clc5q
committed
if (DebugFlag) SMP_msg("Building dominator tree.\n");
this->BuildDominatorTree();
clc5q
committed
if (DebugFlag) SMP_msg("Computing SSA renumbering.\n");
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
if (DumpFlag) CurrBlock->Dump();
clc5q
committed
if (DebugFlag) SMP_msg("Computing local names.\n");
CurrBlock->SetLocalNames();
clc5q
committed
if (DebugFlag) SMP_msg("Computing local SSA renumbering.\n");
CurrBlock->SSALocalRenumber();
if (DumpFlag) CurrBlock->Dump();
clc5q
committed
if (DebugFlag) SMP_msg("Computing global chains.\n");
CurrBlock->CreateGlobalChains();
#if 1
clc5q
committed
if (DebugFlag) SMP_msg("Marking dead registers.\n");
CurrBlock->MarkDeadRegs();
#endif
}
#if SMP_DEBUG_DATAFLOW
if (DumpFlag)
this->Dump();
// Once SSA numbers have been set into all DEFs, USES, and DU-chains, then
// the SSA numbering data structures will no longer be used and can be
// de-allocated.
this->FreeSSAMemory();
return;
} // end of SMPFunction::ComputeSSA()
// Find memory writes (DEFs) with possible aliases
void SMPFunction::AliasAnalysis(void) {
// First task: Mark which memory DEFs MIGHT be aliased because an
// indirect memory write occurs somewhere in the DEF-USE chain.
// Memory DEF-USE chains with no possible aliasing can be subjected
// to type inference and type-based optimizing annotations, e.g. a
// register spill to memory followed by retrieval from spill memory
// followed by NUMERIC USEs should be typed as a continuous NUMERIC
// chain if there is no possibility of aliasing.
// Preparatory step: For each indirect write, mark all def-use chains
// (maintained at the basic block level) that include the indirect
// write instruction. If there are no indirect writes in the function,
// leave all DEFs marked as unaliased and exit.
if (!(this->HasIndirectWrites))
return;
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
list<SMPInstr *>::iterator InstIter;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
for (InstIter = CurrBlock->GetFirstInstr();
InstIter != CurrBlock->GetLastInstr();
++InstIter) {
SMPInstr *CurrInst = (*InstIter);
if (CurrInst->HasIndirectMemoryWrite()) {
CurrBlock->MarkIndWriteChains(CurrInst->GetAddr());
// Until we get true aliasing analysis, any indirect write
// is classified as may-be-aliased.
CurrBlock->SetMaybeAliased(true);
}
} // end for all insts in block
} // end for all blocks in function
// Step one: Find only the memory DEFs to start with.
bool FoundIndWrite = false;
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
if (CurrInst->HasDestMemoryOperand()) {
// Starting with the DEF instruction, traverse the control flow
// until we run into (A) the re-definition of the operand, including
// a re-definition of any of its addressing registers, or (B) an
// indirect write. Return false if condition A terminates the
// search, and true if condition B terminates the search.
this->ResetProcessedBlocks();
op_t MemDefOp = CurrInst->MDGetMemDefOp();
assert(o_void != MemDefOp.type);
set<DefOrUse, LessDefUse>::iterator CurrMemDef = CurrInst->FindDef(MemDefOp);
assert(CurrMemDef != CurrInst->GetLastDef());
int SSANum = CurrMemDef->GetSSANum();
FoundIndWrite = this->FindPossibleChainAlias(CurrInst, MemDefOp, SSANum);
if (FoundIndWrite) {
// Mark the DEF as aliased.
CurrMemDef = CurrInst->SetDefIndWrite(CurrMemDef->GetOp(), true);
break; // Don't waste time after first alias found
}
} // end if inst has dest memory operand
} // end for all instructions
return;
} // end of SMPFunction::AliasAnalysis()
// Does the DefOp DEF_USE chain have an indirect mem write starting at CurrInst?
bool SMPFunction::FindPossibleChainAlias(SMPInstr *CurrInst, op_t DefOp, int SSANum) {
bool DebugFlag = false;
if (0 == strcmp("sdissect", this->GetFuncName())) {
// Next line is just a good place to set a break point.
DebugFlag = true;
}
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
// Starting with the DEF instruction, traverse the control flow
// until we run into (A) the re-definition of the operand, including
// a re-definition of any of its addressing registers, or (B) an
// indirect write. Return false if condition A terminates the
// search, and true if condition B terminates the search.
SMPBasicBlock *CurrBlock = CurrInst->GetBlock();
if (!(CurrBlock->IsProcessed())) {
CurrBlock->SetProcessed(true);
}
else
return false; // block already processed
// Proceed by cases:
ea_t DefAddr = CurrInst->GetAddr();
// Case 1: Local name. Return the IndWrite flag for the local Def-Use
// chain begun by CurrInst.
if (CurrBlock->IsLocalName(DefOp)) {
return CurrBlock->GetLocalDUChainIndWrite(DefOp, SSANum);
}
// Case 2: Global name.
// Case 2A: If Def-Use chain within this block for this memory operand
// has its IndWrite flag set to true, then stop and return true.
else if (CurrBlock->GetGlobalDUChainIndWrite(DefOp, DefAddr)) {
return true;
}
// Case 2B: Else if Def-Use chain is not the last chain in this block
// for this operand, then there must be a later redefinition of the
// memory operand (with new SSA number assigned) later in this block.
// Because we did not fall into case 2A, we know there is no IndWrite
// within the current memory operand's chain, so we return false.
else if (CurrBlock->IsLastGlobalChain(DefOp, DefAddr)) {
return false;
}
// Case 2C: Else if current memory operand is NOT LiveOut, even though
// this is the last def-use chain in the block, then there is no more
// traversing of the control flow graph to be done. The chain has ended
// without encountering an IndWrite, so return false.
else if (!(CurrBlock->IsLiveOut(DefOp))) {
return false;
}
// Case 2D: We have passed all previous checks, so we must have a memory
// operand that reaches the end of the block without encountering an
// IndWrite and is LiveOut. Its may-alias status will be determined by
// following the control flow graph for all successor blocks and examining
// the def-use chains in those blocks.
list<SMPBasicBlock *>::iterator SuccBlock;
SuccBlock = CurrBlock->GetFirstSucc();
bool FoundAliasedWrite = false;
FoundAliasedWrite = this->FindChainAliasHelper(SuccBlock, DefOp);
++SuccBlock;
} while (!FoundAliasedWrite && (SuccBlock != CurrBlock->GetLastSucc()));
return FoundAliasedWrite;
} // end of SMPFunction::FindPossibleChainAlias()
// recursive helper for global DU-chains that traverse CFG
bool SMPFunction::FindChainAliasHelper(list<SMPBasicBlock *>::iterator BlockIter, op_t DefOp) {
bool DebugFlag = false;
SMPBasicBlock *CurrBlock = (*BlockIter);
if (0 == strcmp("mem2chunk_check", this->GetFuncName())) {
// Next line is just a good place to set a break point.
DebugFlag = true;
}
if (!(CurrBlock->IsProcessed())) {
CurrBlock->SetProcessed(true);
}
else
return false; // block already processed
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
// The LVA sets can be used to decide whether it is possible that
// the incoming DU chain overlaps a may-alias write. We can express
// the decision making in a truth table:
//
// Case # LiveIn? Killed? AliasedWrite in block? Action to take
// ------- ------- ------- ---------------------- --------------
// 1 N N N return false
// 2 N N Y return false
// 3 N Y N return false
// 4 N Y Y return false
// 5 Y N N recurse into successors
// 6 Y N Y return true
// 7 Y Y N return false
// 8 Y Y Y check location of aliased write
//
// In the last case, if there is an aliased write before the
// incoming DEF is killed and after it is used, then the
// incoming DU chain overlaps an aliased write, otherwise
// it does not.
// If not LiveIn, incoming DU chain does not run through this block
// at all, so return false.
if (!(CurrBlock->IsLiveIn(DefOp)))
return false; // cases 1-4
bool killed = CurrBlock->IsVarKill(DefOp);
bool BlockHasAliasedWrite = CurrBlock->MaybeAliasedWrite();
if (BlockHasAliasedWrite) {
// If DefOp is LiveIn and is not killed, then any aliased
// write in the block overlaps the incoming DU chain.
if (!killed) {
return true; // case 6
}
// If DefOp is LiveIn and is killed, then the location
// of the aliased write is the determining factor.
else {
// Incoming global DU chains get a new global DU chain
// built within the block with a pseudo-DefAddr of
// one byte before the first address of the block.
ea_t PseudoDefAddr = CurrBlock->GetFirstAddr() - 1;
return CurrBlock->GetGlobalDUChainIndWrite(DefOp, PseudoDefAddr); // case 8
}
else {
// If killed, no aliased write, then cannot overlap an aliased write.
if (killed)
return false; // case 7
else {
// Need to recurse into all successors, because we passed through
// the block without seeing an aliased write and without killing
// the DefOp.
list<SMPBasicBlock *>::iterator SuccBlock;
SuccBlock = CurrBlock->GetFirstSucc();
bool FoundAliasedWrite = false;
while (!FoundAliasedWrite && (SuccBlock != CurrBlock->GetLastSucc())) {
FoundAliasedWrite = this->FindChainAliasHelper(SuccBlock, DefOp);
++SuccBlock;
};
if (DebugFlag) {
clc5q
committed
SMP_msg("FindChainAliasHelper is returning %d\n", FoundAliasedWrite);
}
return FoundAliasedWrite;
}
assert(false); // statement should be unreachable
return false;
} // end of SMPFunction::FindChainAliasHelper()
// Link basic blocks to their predecessors and successors, and build the map
// of instruction addresses to basic blocks.
void SMPFunction::SetLinks(void) {
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
SMP_msg("SetLinks called for %s\n", this->GetFuncName());
#endif
// First, set up the map of instructions to basic blocks.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
list<SMPInstr *>::iterator CurrInst;
for (CurrInst = CurrBlock->GetFirstInstr();
CurrInst != CurrBlock->GetLastInstr();
++CurrInst) {
pair<ea_t, SMPBasicBlock *> MapItem((*CurrInst)->GetAddr(), CurrBlock);
InstBlockMap.insert(MapItem);
}
}
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
SMP_msg("SetLinks finished mapping: %s\n", this->GetFuncName());
#endif
// Next, set successors of each basic block, also setting up the predecessors in the
// process.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
list<SMPInstr *>::iterator InstIter = (--(CurrBlock->GetLastInstr()));
SMPInstr *CurrInst = (*InstIter);
clc5q
committed
bool CondTailCall = false;
if (CurrBlock->HasReturn()) {
if (!(CurrInst->IsCondTailCall())) {
// We either have a return instruction or an unconditional
// tail call instruction. We don't want to link to the
// tail call target, and there is no link for a return
continue;
}
else {
// We have a conditional tail call. We don't want to
// link to the tail call target, but we do want fall
// through to the next instruction.
CondTailCall = true;
}
}
// Last instruction in block; set successors
bool CallFlag = (CALL == CurrInst->GetDataFlowType());
bool IndirCallFlag = (INDIR_CALL == CurrInst->GetDataFlowType());
clc5q
committed
bool TailCallFlag = CondTailCall && CurrInst->IsCondTailCall();
bool IndirJumpFlag = (INDIR_JUMP == CurrInst->GetDataFlowType());
clc5q
committed
SMP_xref_t CurrXrefs;
bool LinkedToTarget = false;
clc5q
committed
for (bool ok = CurrXrefs.SMP_first_from(CurrInst->GetAddr(), XREF_ALL);
clc5q
committed
ok = CurrXrefs.SMP_next_from()) {
if ((CurrXrefs.GetTo() != 0) && (CurrXrefs.GetIscode())) {
// Found a code target, with its address in CurrXrefs.to
if ((CallFlag || IndirCallFlag || TailCallFlag)
clc5q
committed
&& (CurrXrefs.GetTo() != (CurrInst->GetAddr() + CurrInst->GetCmd().size))) {
// A call instruction will have two targets: the fall through to the
// next instruction, and the called function. We want to link to the
// fall-through instruction, but not to the called function.
// Some blocks end with a call just because the fall-through instruction
// is a jump target from elsewhere.
continue;
}
map<ea_t, SMPBasicBlock *>::iterator MapEntry;
clc5q
committed
MapEntry = this->InstBlockMap.find(CurrXrefs.GetTo());
if (MapEntry == this->InstBlockMap.end()) {
clc5q
committed
SMP_msg("WARNING: addr %x not found in map for %s\n", CurrXrefs.GetTo(),
clc5q
committed
SMP_msg(" Referenced from %s\n", CurrInst->GetDisasm());
SMPBasicBlock *Target = MapEntry->second;
// Make target block a successor of current block.
CurrBlock->LinkToSucc(Target);
// Make current block a predecessor of target block.
Target->LinkToPred(CurrBlock);
LinkedToTarget = true;
#if SMP_USE_SWITCH_TABLE_INFO
if (IndirJumpFlag) {
clc5q
committed
SMP_msg("Switch table link: jump at %x target at %x\n",
CurrInst->GetAddr(), CurrXrefs.GetTo());
}
}
} // end for all xrefs
if (IndirJumpFlag && (!LinkedToTarget)) {
this->UnresolvedIndirectJumps = true;
clc5q
committed
SMP_msg("WARNING: Unresolved indirect jump at %x\n", CurrInst->GetAddr());
}
else if (IndirCallFlag && (!LinkedToTarget)) {
this->UnresolvedIndirectCalls = true;
clc5q
committed
SMP_msg("WARNING: Unresolved indirect call at %x\n", CurrInst->GetAddr());
} // end for all blocks
// If we have any blocks that are all no-ops and have no predecessors, remove those
// blocks. They are dead and make the CFG no longer a lattice. Any blocks that have
// no predecessors but are not all no-ops should also be removed with a different
// log message.
// NOTE: Prior to construction of hell nodes in functions with unresolved indirect jumps,
// we cannot conclude that a block with no predecessors is unreachable. Also, the block
// order might be such that removal of a block makes an already processed block
// unreachable, so we have to iterate until there are no more changes.
// NOTE: An odd new gcc recursion optimization uses indirect calls within the function, so
// they can behave like indirect jumps.
#if SMP_USE_SWITCH_TABLE_INFO
if (!(this->HasUnresolvedIndirectJumps() || this->HasUnresolvedIndirectCalls())) {
if (!(this->HasIndirectJumps() || this->HasIndirectCalls())) {
bool changed;
bool NoPredecessors;
bool OnlyPredIsItself;
list<SMPBasicBlock *>::iterator CurrPred;
do {
changed = false;
BlockIter = this->Blocks.begin();
++BlockIter; // don't delete the top block, no matter what.
while (BlockIter != this->Blocks.end()) {
CurrBlock = (*BlockIter);
OnlyPredIsItself = false;
CurrPred = CurrBlock->GetFirstPred();
NoPredecessors = (CurrPred == CurrBlock->GetLastPred());
if (!NoPredecessors) {
if ((*CurrPred)->GetFirstAddr() == CurrBlock->GetFirstAddr()) { // self-recursion
++CurrPred; // any more preds besides itself?
OnlyPredIsItself = (CurrPred == CurrBlock->GetLastPred());
// Only predecessor was the self-recursion if no more preds
}
}
if (NoPredecessors || OnlyPredIsItself) {
if (CurrBlock->AllNops())
clc5q
committed
SMP_msg("Removing all nops block at %x\n", CurrBlock->GetFirstAddr());
clc5q
committed
SMP_msg("Removing block with no predecessors at %x\n", CurrBlock->GetFirstAddr());
// Remove this block from the predecessors list of its successors.
list<SMPBasicBlock *>::iterator SuccIter;
ea_t TempAddr = CurrBlock->GetFirstAddr();
for (SuccIter = CurrBlock->GetFirstSucc(); SuccIter != CurrBlock->GetLastSucc(); ++SuccIter) {
(*SuccIter)->ErasePred(TempAddr);
}
// Remove the unreachable instructions from the function inst list.
list<SMPInstr *>::iterator InstIter;
InstIter = CurrBlock->GetFirstInstr();
ea_t FirstBadAddr = (*InstIter)->GetAddr();
InstIter = CurrBlock->GetLastInstr();
--InstIter; // get last real instruction
ea_t LastBadAddr = (*InstIter)->GetAddr();
this->EraseInstRange(FirstBadAddr, LastBadAddr);
// Finally, remove the block from the blocks list.
BlockIter = this->Blocks.erase(BlockIter);
this->BlockCount -= 1;
changed = true;
}
else {
++BlockIter;
}
} // end while all blocks after the first one
} while (changed);
} // end if not indirect jumps
return;
} // end of SMPFunction::SetLinks()
// Number all basic blocks in reverse postorder (RPO) and set RPOBlocks vector to
// access them.
void SMPFunction::RPONumberBlocks(void) {
#if SMP_DEBUG_DATAFLOW
clc5q
committed
bool DebugFlag = false;
DebugFlag = (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
clc5q
committed
if (DebugFlag) SMP_msg("Entered RPONumberBlocks\n");
list<SMPBasicBlock *> WorkList;
// Number the first block with 0.
list<SMPBasicBlock *>::iterator BlockIter = this->Blocks.begin();
SMPBasicBlock *CurrBlock = (*BlockIter);
#if 0
if (this->RPOBlocks.capacity() <= (size_t) this->BlockCount) {
clc5q
committed
SMP_msg("Reserving %d RPOBlocks old value: %d\n", 2+this->BlockCount, this->RPOBlocks.capacity());
this->RPOBlocks.reserve(2 + this->BlockCount);
this->RPOBlocks.assign(2 + this->BlockCount, this->Blocks.end());
}
#endif
CurrBlock->SetNumber(CurrNum);
this->RPOBlocks.push_back(CurrBlock);
++CurrNum;
// Push the first block's successors onto the work list.
list<SMPBasicBlock *>::iterator CurrSucc = CurrBlock->GetFirstSucc();
while (CurrSucc != CurrBlock->GetLastSucc()) {
WorkList.push_back(*CurrSucc);
++CurrSucc;
}
// Use the WorkList to iterate through all blocks in the function
list<SMPBasicBlock *>::iterator CurrListItem = WorkList.begin();
bool change;
while (!WorkList.empty()) {
change = false;
while (CurrListItem != WorkList.end()) {
if ((*CurrListItem)->GetNumber() != SMP_BLOCKNUM_UNINIT) {
// Duplicates get pushed onto the WorkList because a block
// can be the successor of multiple other blocks. If it is
// already numbered, it is a duplicate and can be removed
// from the list.
CurrListItem = WorkList.erase(CurrListItem);
change = true;
continue;
}
if ((*CurrListItem)->AllPredecessorsNumbered()) {
// Ready to be numbered.
(*CurrListItem)->SetNumber(CurrNum);
#if 0
clc5q
committed
SMP_msg("Set RPO number %d\n", CurrNum);
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
if (DebugFlag && (7 == CurrNum))
this->Dump();
#endif
this->RPOBlocks.push_back(*CurrListItem);
++CurrNum;
change = true;
// Push its unnumbered successors onto the work list.
CurrSucc = (*CurrListItem)->GetFirstSucc();
while (CurrSucc != (*CurrListItem)->GetLastSucc()) {
if ((*CurrSucc)->GetNumber() == SMP_BLOCKNUM_UNINIT)
WorkList.push_back(*CurrSucc);
++CurrSucc;
}
CurrListItem = WorkList.erase(CurrListItem);
}
else {
++CurrListItem;
}
} // end while (CurrListItem != WorkList.end())
if (change) {
// Reset CurrListItem to beginning of work list for next iteration.
CurrListItem = WorkList.begin();
}
else {
// Loops can cause us to not be able to find a WorkList item that has
// all predecessors numbered. Take the WorkList item with the lowest address
// and number it so we can proceed.
CurrListItem = WorkList.begin();
ea_t LowAddr = (*CurrListItem)->GetFirstAddr();
list<SMPBasicBlock *>::iterator SaveItem = CurrListItem;
++CurrListItem;
while (CurrListItem != WorkList.end()) {
if (LowAddr > (*CurrListItem)->GetFirstAddr()) {
SaveItem = CurrListItem;
LowAddr = (*CurrListItem)->GetFirstAddr();
}
++CurrListItem;
}
// SaveItem should now be numbered.
(*SaveItem)->SetNumber(CurrNum);
#if SMP_DEBUG_DATAFLOW
clc5q
committed
SMP_msg("Picked LowAddr %x and set RPO number %d\n", LowAddr, CurrNum);
this->RPOBlocks.push_back(*SaveItem);
++CurrNum;
// Push its unnumbered successors onto the work list.
CurrSucc = (*SaveItem)->GetFirstSucc();
while (CurrSucc != (*SaveItem)->GetLastSucc()) {
if ((*CurrSucc)->GetNumber() == SMP_BLOCKNUM_UNINIT)
WorkList.push_back(*CurrSucc);
++CurrSucc;
}
CurrListItem = WorkList.erase(SaveItem);
CurrListItem = WorkList.begin();
} // end if (change) ... else ...
} // end while work list is nonempty
// Prior to construction of hell nodes for functions with indirect jumps, there
// could still be unnumbered blocks because they appear to be unreachable
// (no predecessors from SetLinks() because they are reached only via indirect
// jumps). We need to number these and push them on the RPOBlocks vector so
// that the vector contains all the blocks.
// NOTE: Odd new gcc recursion optimization seems to use indirect calls to reach
// some blocks within a recursive function, operating somewhat like an indirect
// jump.
if (this->HasIndirectJumps() || this->HasIndirectCalls()) {
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
if (SMP_BLOCKNUM_UNINIT == CurrBlock->GetNumber()) {
clc5q
committed
SMP_msg("WARNING: Numbering indirectly reachable block at %x\n", CurrBlock->GetFirstAddr());
CurrBlock->SetNumber(CurrNum);
this->RPOBlocks.push_back(CurrBlock);
++CurrNum;
}
}
}
clc5q
committed
// If we still have unnumbered blocks, it is not because of indirect jumps or calls.
// We have some mysterious dead code.
if (this->BlockCount > this->RPOBlocks.size()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: RPONumberBlocks method: Function %s has BlockCount %d and RPOBlocks size %zu\n",
this->GetFuncName(), this->BlockCount, this->RPOBlocks.size());
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
clc5q
committed
if (SMP_BLOCKNUM_UNINIT == CurrBlock->GetNumber()) {
clc5q
committed
SMP_msg("WARNING: Numbering apparently unreachable block at %x\n", CurrBlock->GetFirstAddr());
clc5q
committed
CurrBlock->SetNumber(CurrNum);
this->RPOBlocks.push_back(CurrBlock);
++CurrNum;
}
}
}
return;
} // end of SMPFunction::RPONumberBlocks()
// Perform live variable analysis on all blocks in the function.
// See chapter 9 of Cooper/Torczon, Engineering a Compiler, for the algorithm.
void SMPFunction::LiveVariableAnalysis(void) {
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
#if SMP_DEBUG_DATAFLOW
bool DebugFlag = (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
#endif
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
SMP_msg("LiveVariableAnalysis for %s\n", this->GetFuncName());
clc5q
committed
#endif
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
// Initialize the Killed and UpwardExposed sets for each block.
CurrBlock->InitKilledExposed();
}
bool changed;
// Iterate over each block, updating LiveOut sets until no more changes are made.
// NOTE: LVA is more efficient when computed over a reverse post-order list of blocks
// from the inverted CFG. We have an RPO list from the forward CFG, so it is just as
// good to simply iterate through the blocks in layout order.
#if 1
do {
changed = false;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
changed |= CurrBlock->UpdateLiveOut();
}
} while (changed);
#else // Use reverse postorder
do {
changed = false;
for (size_t index = 0; index < this->RPOBlocks.size(); ++index) {
CurrBlock = this->RPOBlocks.at(index);
changed |= CurrBlock->UpdateLiveOut();
}
} while (changed);
#if SMP_USE_SSA_FNOP_MARKER
// Create DEFs in the marker instruction for all names in the LiveInSet
// of the first block. These are the names for the function that
// would otherwise look like USEs of uninitialized variables later.
// Note that the LiveVariableAnalysis work does not actually populate
// a LiveInSet for the first block, so we simulate it with its
// dataflow equation, UpExposed union (LiveOut minus VarKill).
set<op_t, LessOp>::iterator UpExposedIter, LiveOutIter;
list<SMPInstr *>::iterator MarkerInst = this->Instrs.begin();
SMPBasicBlock *FirstBlock = this->Blocks.front();
for (UpExposedIter = FirstBlock->GetFirstUpExposed();
UpExposedIter != FirstBlock->GetLastUpExposed();
++UpExposedIter) {
// Add DEF with SSANum of 0.
(*MarkerInst)->AddDef(*UpExposedIter, UNINIT, 0);
clc5q
committed
// Add to the VarKill and LiveIn sets.
FirstBlock->AddVarKill(*UpExposedIter);
FirstBlock->AddLiveIn(*UpExposedIter);
for (LiveOutIter = FirstBlock->GetFirstLiveOut();
LiveOutIter != FirstBlock->GetLastLiveOut();
if (!(FirstBlock->IsVarKill(*LiveOutIter))) {
(*MarkerInst)->AddDef(*LiveOutIter, UNINIT, 0);
clc5q
committed
// Add to the VarKill and LiveIn sets.
FirstBlock->AddVarKill(*LiveOutIter);
FirstBlock->AddLiveIn(*LiveOutIter);
}
#endif
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
if (DebugFlag) SMP_msg("Exiting LiveVariableAnalysis\n");
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
#endif
return;
} // end of SMPFunction::LiveVariableAnalysis()
// Return the IDom index that is the end of the intersection prefix of the Dom sets of
// the two blocks designated by the RPO numbers passed in.
// See Cooper & Torczon, "Engineering a Compiler" 1st edition figure 9.8.
int SMPFunction::IntersectDoms(int block1, int block2) const {
int finger1 = block1;
int finger2 = block2;
while (finger1 != finger2) {
while (finger1 > finger2)
finger1 = this->IDom.at(finger1);
while (finger2 > finger1)
finger2 = this->IDom.at(finger2);
}
return finger1;
} // end of SMPFunction::IntersectDoms()
// Compute immediate dominators of all blocks into IDom[] vector.
void SMPFunction::ComputeIDoms(void) {
bool DebugFlag = false;
#if SMP_DEBUG_DATAFLOW
clc5q
committed
DebugFlag = (0 == strcmp("_ZN6soplex7NameSetC2Eiidd", this->GetFuncName()));
clc5q
committed
if (DebugFlag) SMP_msg("Entered ComputeIDoms\n");
// Initialize the IDom[] vector to uninitialized values for all blocks.
this->IDom.reserve(this->BlockCount);
this->IDom.assign(this->BlockCount, SMP_BLOCKNUM_UNINIT);
clc5q
committed
if (DebugFlag) {
clc5q
committed
SMP_msg("BlockCount = %d RPOBlocks size = %zu\n", this->BlockCount, this->RPOBlocks.size());
clc5q
committed
}
if (this->BlockCount != this->RPOBlocks.size()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: Function %s has BlockCount of %d and RPOBlocks size of %zu\n",
this->GetFuncName(), this->BlockCount, this->RPOBlocks.size());
clc5q
committed
}
this->IDom[0] = 0; // Start block dominated only by itself
bool changed;
do {
changed = false;
for (size_t RPONum = 1; RPONum < (size_t) this->BlockCount; ++RPONum) {
clc5q
committed
if (DebugFlag) SMP_msg("RPONum %zu\n", RPONum);
clc5q
committed
#if 0
clc5q
committed
SMP_msg("RPOBlocks vector size: %d\n", this->RPOBlocks.size());
for (size_t index = 0; index < this->RPOBlocks.size(); ++index) {
clc5q
committed
SMP_msg("RPOBlocks entry %d is %d\n", index, RPOBlocks[index]->GetNumber());
clc5q
committed
#endif
// To avoid infinite loops on blocks that dominate themselves but otherwise have no
// predecessors (probably reachable only through indirect jumps), we stop processing
// the blocks once the IDom becomes the top (entry) block. This probably saves time
// on other blocks as well.
if (0 == this->IDom[RPONum])
continue;
SMPBasicBlock *CurrBlock = this->RPOBlocks.at(RPONum);
clc5q
committed
// if (DebugFlag) SMP_msg("CurrBlock: %x\n", CurrBlock._Ptr);
list<SMPBasicBlock *>::iterator CurrPred;
// Initialize NewIdom to the first processed predecessor of block RPONum.
int NewIdom = SMP_BLOCKNUM_UNINIT;
for (CurrPred = CurrBlock->GetFirstPred(); CurrPred != CurrBlock->GetLastPred(); ++CurrPred) {
int PredNum = (*CurrPred)->GetNumber();
clc5q
committed
if (DebugFlag) SMP_msg("Pred: %d\n", PredNum);
// **!!** See comment below about unreachable blocks.
if (SMP_BLOCKNUM_UNINIT == PredNum)
continue;
int PredIDOM = this->IDom.at(PredNum);
clc5q
committed
if (DebugFlag) SMP_msg("Pred IDom: %d\n", PredIDOM);
if (SMP_BLOCKNUM_UNINIT != PredIDOM) {
NewIdom = PredNum;
if (NewIdom == SMP_BLOCKNUM_UNINIT) {
clc5q
committed
SMP_msg("Failure on NewIdom in ComputeIDoms for %s\n", this->GetFuncName());
if (this->HasIndirectJumps() || this->HasIndirectCalls()) {
// Might be reachable only through indirect jumps.
NewIdom = 0; // make it dominated by entry block
clc5q
committed
SMP_msg("Assuming block %d at address %d is reachable indirectly.\n",
clc5q
committed
CurrBlock->GetNumber(), CurrBlock->GetFirstAddr());
}
else {
// Might be exception handling code, reachable only by call stack walking.
NewIdom = 0; // make it be dominated by entry block
clc5q
committed
SMP_msg("Assuming block %d at address %d is reachable by exception handling.\n",
clc5q
committed
CurrBlock->GetNumber(), CurrBlock->GetFirstAddr());
}
}
assert(NewIdom != SMP_BLOCKNUM_UNINIT);
// Loop through all predecessors of block RPONum except block NewIdom.