Newer
Older
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
// mark e as executed
if (0 <= SrcBlockNum) {
ExecutedEdgeBitSet.at((size_t) DestBlockNum).SetBit((size_t) SrcBlockNum);
}
// EvaluateAllPhisInBlock(n)
this->EvaluateAllPhiConstants(DestBlockNum, ExecutedEdgeBitSet, SSAWorkList);
// if (e is only edge into n marked as executed) then
SMPBasicBlock *CurrBlock = this->GetBlockByNum(DestBlockNum);
if (!(CurrBlock->IsSCCPVisited())) {
// for (each instruction i in block n) do
// if (i is an assignment) then
// EvaluateAssign(i)
// else if (i is a conditional branch) then
// EvaluateConditional(i)
// endif
// endfor
enum STARSBranchConst BranchEval = STARS_BRANCH_UNKNOWN;
CurrBlock->SCCPEvaluateConstants(BranchEval, CFGWorkList, SSAWorkList); // also marks block as SCCP visited
// endif
}
// endif
}
// endif
}
//
// if (SSAWorkList is not empty) then
// remove an edge e = (s, d) from SSAWorkList
// c := CFG node that uses d
// if (any edge entering c is marked as executable) then
// if (d is a phi function argument) then
// EvaluatePhi(d)
// else
// for (each instruction i in block c) do
// if (i is an assignment that uses d) then
// EvaluateAssign(i)
// else if (i is a conditional branch that uses d) then
// EvaluateConditional(i)
// endif
// endfor
// endif
// endif
// endif
// if (SSAWorkList is not empty) then
if (!(SSAWorkList.empty())) {
// remove an edge e = (s, d) from SSAWorkList
pair<int, int> SSAEdge = SSAWorkList.front();
SSAWorkList.pop_front();
int BlockNum = SSAEdge.first;
int DefHashValue = SSAEdge.second;
// c := CFG node that uses d
assert(0 <= BlockNum);
SMPBasicBlock *CurrBlock = this->GetBlockByNum((size_t) BlockNum);
op_t DefOp = InitOp;
DefOp.type = o_reg;
DefOp.reg = (DefHashValue & 0x0000ffff);
int DefSSANum = ((DefHashValue & 0x7fff0000) >> 16);
bool LocalName = CurrBlock->IsLocalName(DefOp);
// if (any edge entering c is marked as executable) then
// if (d is a phi function argument) then
// EvaluatePhi(d)
// else
// for (each instruction i in block c) do
// if (i is an assignment that uses d) then
// EvaluateAssign(i)
// else if (i is a conditional branch that uses d) then
// EvaluateConditional(i)
// endif
// endfor
// endif
// endif
assert(CurrBlock->IsSCCPVisited()); // a local name is only added to SSAWorkList from within the block
vector<SMPInstr *>::iterator InstIter;
bool FoundReDEF = false;
for (InstIter = CurrBlock->GetFirstInst(); InstIter != CurrBlock->GetLastInst(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
set<DefOrUse, LessDefUse>::iterator UseIter = CurrInst->FindUse(DefOp);
if (UseIter != CurrInst->GetLastUse()) { // operand is USEd; check SSANum
int UseSSANum = UseIter->GetSSANum();
if (UseSSANum == DefSSANum) {
SMPitype DataFlowType = CurrInst->GetDataFlowType();
if (DEFAULT == DataFlowType) {
CurrInst->SCCPEvaluateAssignment(SSAWorkList);
}
else if (COND_BRANCH == DataFlowType) {
enum STARSBranchConst BranchEval;
CurrInst->SCCPEvaluateCondBranch(BranchEval);
CurrBlock->SCCPHandleSuccessors(BranchEval, CFGWorkList);
}
}
}
set<DefOrUse, LessDefUse>::iterator DefIter = CurrInst->FindDef(DefOp);
if (DefIter != CurrInst->GetLastDef()) { // check for re-DEF
int NewDefSSANum = DefIter->GetSSANum();
if (NewDefSSANum > DefSSANum) { // re-DEF; we can stop searching for USEs of DefOp/DefSSANum in this block
FoundReDEF = true;
break;
}
}
} // end for all insts in block
// See if we need to search for other blocks that use DefOp/DefSSANum
if (!(LocalName || FoundReDEF)) { // we have global name that is not redefined
list<SMPBasicBlock *>::iterator SuccIter;
for (SuccIter = CurrBlock->GetFirstSucc(); SuccIter != CurrBlock->GetLastSucc(); ++SuccIter) {
SMPBasicBlock *SuccBlock = (*SuccIter);
if (SuccBlock->IsSCCPVisited() && SuccBlock->IsLiveIn(DefOp)) {
this->ResetProcessedBlocks();
SuccBlock->SCCPGlobalPropagationHelper(DefOp, DefSSANum, ExecutedEdgeBitSet, CFGWorkList, SSAWorkList);
}
}
}
// endif
}
#if 0
SSAWorkList.clear(); // temporary stub
#endif
// endwhile
}
// Go back over the basic blocks and detect never-visited blocks. Label these as unreachable.
list<SMPBasicBlock *>::iterator BlockIter;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
SMPBasicBlock *CurrBlock = (*BlockIter);
if (!(CurrBlock->IsSCCPVisited())) {
CurrBlock->SetUnreachableBlock(true);
#if STARS_DEBUG_SCCP
ea_t BlockAddr = CurrBlock->GetFirstAddr();
SMP_msg("INFO: SCCP found unreachable block at %lx\n", (unsigned long) BlockAddr);
#endif
#if STARS_SCCP_CONVERT_UNREACHABLE_BLOCKS
CurrBlock->SCCPNullifyUnreachableBlock();
#if STARS_SCCP_GATHER_STATISTICS
else if (CurrBlock->HasCallInstruction()) {
CurrBlock->SCCPGatherStatistics();
}
#endif
return;
} // end of SMPFunction::SparseConditionalConstantPropagation()
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
// part of SCCP processing; propagate const DEFs into Phi USEs and Phi DEFs
void SMPFunction::EvaluateAllPhiConstants(int BlockNum, vector<STARSBitSet> ExecutedEdgeBitSet, list<pair<int, int> > &SSAWorkList) {
// For all Phi DEFs of the type we are tracking for const values:
// If Phi DEF const value is not already the lattice bottom value:
// Accumulate const DEF values only for Phi USEs that correspond to incoming
// edges that are executed.
// If we have a consistent const value, set Phi DEF const value to it; if
// we have conflicting const values, set Phi DEF const value to type lattice bottom.
// If we set the Phi DEF const value to a new value, then propagate along SSA edges.
// For all Phi DEFs of the type we are tracking for const values:
SMPBasicBlock *CurrBlock = this->GetBlockByNum(BlockNum);
set<SMPPhiFunction, LessPhi>::iterator PhiIter;
for (PhiIter = CurrBlock->GetFirstPhi(); PhiIter != CurrBlock->GetLastPhi(); ++PhiIter) {
op_t PhiOp = PhiIter->GetAnyOp();
if (!(o_reg == PhiOp.type)) // !!!!****!!!! Add stack locations also in safe functions
continue;
int DefSSANum = PhiIter->GetDefSSANum();
int DefHashValue = HashGlobalNameAndSSA(PhiOp, DefSSANum);
// If Phi DEF const value is not already the lattice bottom value:
map<int, struct STARS_SCCP_Const_Struct>::iterator ConstIter = this->FindConstValue(DefHashValue);
STARSConstantValueType DefConstValType = STARS_CONST_TOP; // default; no entry in map
if (ConstIter != this->GetLastConstValueIter()) { // found entry in map
DefConstValType = ConstIter->second.ConstType;
}
if (DefConstValType != STARS_CONST_BOTTOM) {
// Accumulate const DEF values only for Phi USEs that correspond to incoming
// edges that are executed.
uval_t ConstUseVal;
bool ConstUseValueSeen = false;
list<SMPBasicBlock *>::iterator PredIter;
size_t PredIndex = 0;
STARSConstantValueType DefFinalConstValType = DefConstValType;
for (PredIter = CurrBlock->GetFirstPred(); PredIter != CurrBlock->GetLastPred(); ++PredIter) {
int IncomingBlockNum = (*PredIter)->GetNumber();
bool ExecutedIncomingEdge = ExecutedEdgeBitSet.at(BlockNum).GetBit(IncomingBlockNum);
if (ExecutedIncomingEdge) {
int UseSSANum = PhiIter->GetUseSSANum(PredIndex);
int UseHashValue = HashGlobalNameAndSSA(PhiOp, UseSSANum);
// If we have a consistent const value, set Phi DEF const value to it; if
// we have conflicting const values, set Phi DEF const value to type lattice bottom.
ConstIter = this->FindConstValue(UseHashValue);
STARSConstantValueType UseConstValType = STARS_CONST_TOP; // default; no entry in map
if (ConstIter != this->GetLastConstValueIter()) { // found entry in map
UseConstValType = ConstIter->second.ConstType;
}
if (UseConstValType == STARS_CONST_HAS_VALUE) {
if (ConstUseValueSeen) { // check for consistency of values
if (ConstUseVal != ConstIter->second.ConstValue) { // inconsistent const values
DefFinalConstValType = STARS_CONST_BOTTOM;
break; // no need to see more Phi USEs
}
}
else { // this is the first const value we have seen
DefFinalConstValType = STARS_CONST_HAS_VALUE; // so far, anyway
ConstUseValueSeen = true;
ConstUseVal = ConstIter->second.ConstValue; // only value seen so far
}
}
else if (UseConstValType == STARS_CONST_BOTTOM) {
// Any BOTTOM value in a USE makes the DEF also become BOTTOM.
DefFinalConstValType = STARS_CONST_BOTTOM;
break; // no need to see more Phi USEs
}
// else must be STARS_CONST_TOP, which is a don't-care case
} // end if (ExecutedIncomingEdge)
++PredIndex; // keep index in sync with PredIter
} // end for PredIter iteration through predecessor blocks
// If we set the Phi DEF const value to a new value, then propagate along SSA edges.
if (DefFinalConstValType != DefConstValType) { // const entry is changing
struct STARS_SCCP_Const_Struct NewConstEntry;
NewConstEntry.ConstType = DefFinalConstValType;
NewConstEntry.ConstValue = ConstUseVal;
if (DefConstValType == STARS_CONST_TOP) { // there was no old map entry; insert new one
pair<int, struct STARS_SCCP_Const_Struct> NewMapEntry(DefHashValue, NewConstEntry);
pair<map<int, struct STARS_SCCP_Const_Struct>::iterator, bool> InsertResult = this->ConstantDefs.insert(NewMapEntry);
assert(InsertResult.second);
}
else { // old map entry needs to be changed
this->ConstantDefs[DefHashValue] = NewConstEntry;
}
// Propagate along SSA edges.
pair<int, int> SSAEdge(BlockNum, DefHashValue);
SSAWorkList.push_back(SSAEdge);
} // end if entry is changing
} // end if previous DEF value was not already BOTTOM
} // end for all Phi functions
return;
} // end of SMPFunction::EvaluateAllPhiConstants()
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, int &IdiomCode) {
clc5q
committed
bool benign = false;
list<SMPInstr *>::iterator InstIter;
clc5q
committed
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
set<DefOrUse, LessDefUse>::iterator DefIter, UseIter;
int UseSSANum;
SMPOperandType DefType;
// 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
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;
IdiomCode = 4;
clc5q
committed
// 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.
op_t UseInstDefOp = DefIter->GetOp();
DefIter = CurrInst->SetDefNoOverflow(UseInstDefOp, true);
SMPInstr *DefInst = this->GetInstFromAddr(DefAddr);
(void) 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) {
this->ResetProcessedBlocks(); // prepare for recursion through blocks
SinkString.clear();
SMPBasicBlock *CurrBlock = this->GetBlockFromInstAddr(DefAddr);
assert(CurrBlock != NULL);
clc5q
committed
bool 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 (CurrBlock->FindLoopHeadsAndTails()) {
++this->LoopCount;
}
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();
#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()
// Detect which blocks are in which loops and populate FuncLoopsByBlock data structure.
void SMPFunction::DetectLoops(void) {
list<SMPBasicBlock *>::iterator BlockIter;
size_t LoopNumber = 0;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
SMPBasicBlock *CurrBlock = (*BlockIter);
if (CurrBlock->IsLoopTailBlock()) {
// For each loop tail block, get its loop header block number (the target
// block for its back edge). Then traverse the CFG upwards, recording all
// of the basic block numbers that lie between the loop tail and loop head,
// along with the tail and head.
this->ResetProcessedBlocks();
int TailBlockNum = CurrBlock->GetNumber();
int HeadBlockNum = CurrBlock->GetLoopHeaderNumber();
assert((TailBlockNum != SMP_BLOCKNUM_UNINIT) && (HeadBlockNum != SMP_BLOCKNUM_UNINIT));
list<list<SMPBasicBlock *>::iterator> BlockWorkList;
BlockWorkList.push_back(BlockIter);
SMPBasicBlock *WorkBlock;
SMPBasicBlock *PredBlock;
list<SMPBasicBlock *>::iterator WorkIter;
list<SMPBasicBlock *>::iterator PredIter;
BlockWorkList.pop_front();
int WorkBlockNum = WorkBlock->GetNumber();
assert(WorkBlockNum != SMP_BLOCKNUM_UNINIT);
if (!(WorkBlock->IsProcessed())) {
this->FuncLoopsByBlock[(size_t) WorkBlockNum].SetBit(LoopNumber);
WorkBlock->SetProcessed(true);
// Add unprocessed predecessors to the work list until we reach the loop head.
if (WorkBlockNum != HeadBlockNum) {
for (PredIter = WorkBlock->GetFirstPred(); PredIter != WorkBlock->GetLastPred(); ++PredIter) {
PredBlock = (*PredIter);
bool AlreadyProcessed = PredBlock->IsProcessed();
if (!AlreadyProcessed) {
BlockWorkList.push_back(PredIter);
}
}
}
}
} while (!BlockWorkList.empty());
++LoopNumber;
}
}
return;
} // end of SMPFunction::DetectLoops()
// 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;
vector<SMPInstr *>::iterator BlkInstIter;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
for (BlkInstIter = CurrBlock->GetFirstInst(); BlkInstIter != CurrBlock->GetLastInst(); ++BlkInstIter) {
SMPInstr *CurrInst = (*BlkInstIter);
if (CurrInst->HasIndirectMemoryWrite()) {
// 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;
list<SMPInstr *>::iterator InstIter;
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
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);
}
} // 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) {
#if 0
bool DebugFlag = false;
if (0 == strcmp("sdissect", this->GetFuncName())) {
// Next line is just a good place to set a break point.
DebugFlag = true;
}
#endif
// 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();
vector<SMPInstr *>::iterator InstIter = CurrBlock->GetInstIterFromAddr(DefAddr);
bool IndWriteFound, ReDef;
++InstIter;
// Case 1: Local name. Return the IndWrite flag for the local Def-Use
// chain begun by CurrInst.
bool UseAfterIndirectWrite = CurrBlock->HasUseAfterIndWrite(DefOp, InstIter, IndWriteFound, ReDef);
bool LiveOutFlag = CurrBlock->IsLiveOut(DefOp);
if (CurrBlock->IsLocalName(DefOp)) {
return (UseAfterIndirectWrite);
}
// Case 2: Global name.
#if 1
if (UseAfterIndirectWrite) {
return true;
}
else if (IndWriteFound) {
// We found an indirect write, but no USE of DefOp after it.
// If DefOp is LiveOut, then there is a USE of DefOp in a
// successor block, so DefOp can be aliased.
return (LiveOutFlag && !ReDef);
}
#else
// 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;
if (LiveOutFlag && !ReDef) {
do {
if ((*SuccBlock)->IsLiveIn(DefOp)) {
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
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
// 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 { // case 8; depends on finding indirect write, then USE, before re-DEF.
vector<SMPInstr *>::iterator InstIter = CurrBlock->GetFirstInst();
bool IndWriteFound, ReDef;
return CurrBlock->HasUseAfterIndWrite(DefOp, InstIter, IndWriteFound, ReDef);
}
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;
list<SMPBasicBlock *> UnresolvedBranchWorkList;
ea_t InstAddr;
#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);
vector<SMPInstr *>::iterator InstIter;
for (InstIter = CurrBlock->GetFirstInst(); InstIter != CurrBlock->GetLastInst(); ++InstIter) {
InstAddr = (*InstIter)->GetAddr();
pair<ea_t, SMPBasicBlock *> MapItem(InstAddr, 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);
vector<SMPInstr *>::iterator InstIter = (--(CurrBlock->GetLastInst()));
SMPInstr *CurrInst = (*InstIter);
InstAddr = CurrInst->GetAddr();
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 IndirJumpFlag = (INDIR_JUMP == CurrInst->GetDataFlowType());
bool IndirCallFlag = (INDIR_CALL == CurrInst->GetDataFlowType());
// NOTE: Dues to phase re-ordering, we cannot yet identify tail calls,
// so CondTailCall and TailCallFlag will always be false, which is harmless.
// SMPInstr::SetTailCall() will do a little cleanup later.
clc5q
committed
bool TailCallFlag = CondTailCall && CurrInst->IsCondTailCall();
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()) {
ea_t TargetAddr = CurrXrefs.GetTo();
if ((TargetAddr != 0) && (CurrXrefs.GetIscode())) {
// Found a code target, with its address in CurrXrefs.to
if ((CallFlag || IndirCallFlag || TailCallFlag)
&& (TargetAddr != (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;
MapEntry = this->InstBlockMap.find(TargetAddr);
if (MapEntry == this->InstBlockMap.end()) {
; // do nothing; probably a tail call (not yet identified)
#if 0
SMP_msg("WARNING: addr %x not found in map for %s\n", TargetAddr,
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(), TargetAddr);
}
}
} // end for all xrefs
if (IndirJumpFlag && (!LinkedToTarget)) {
this->UnresolvedIndirectJumps = true;
UnresolvedBranchWorkList.push_back(CurrBlock);
SMP_msg("WARNING: Unresolved indirect jump at %lx\n", (unsigned long) CurrInst->GetAddr());
}
else if (IndirCallFlag && (!LinkedToTarget)) {
this->UnresolvedIndirectCalls = true;
SMP_msg("WARNING: Unresolved indirect call at %lx\n", (unsigned long) CurrInst->GetAddr());
} // end for all blocks
// Mark all blocks that can be reached from the entry block, so we can find the unreachable ones.
this->ResetProcessedBlocks();
this->Blocks.front()->DepthFirstMark();
// We have two cases: (1) Unresolved indirect branches could be targeting the unmarked blocks, making
// these blocks reachable, in which case we should link the unresolved branches to the unmarked blocks;
// or (2) there are no unresolved branches, in which case the unmarked blocks are unreachable within
// the function. They might be reachable from outside the function using exception handling jumps, but
// that still would not allow us to link them into the CFG of this function properly, so in any case we
// are deleting those unreachable blocks and not emitting annotations for them.
// NOTE: An odd new gcc recursion optimization uses indirect calls within the function, so
// they can behave like indirect jumps. However, we don't want to link unresolved calls to unmarked blocks
// at this time.
bool HellNodeCase = (!UnresolvedBranchWorkList.empty() && (this->HasUnresolvedIndirectCalls() || this->HasUnresolvedIndirectJumps()));
bool AddedMissingLinks = false;
bool changed;
do {
changed = false;
list<SMPBasicBlock *>::iterator BlockIter = this->Blocks.begin();
while (BlockIter != this->Blocks.end()) {
if (CurrBlock->IsProcessed()) {
++BlockIter;
}
else {
// Block cannot be reached from entry node, even after we have added links
// on previous loop iterations.
if (!HellNodeCase) {
if (CurrBlock->AllNops())
SMP_msg("INFO: Removing all nops block at %lx\n", (unsigned long) CurrBlock->GetFirstAddr());
SMP_msg("INFO: Removing unreachable block at %lx\n", (unsigned long) 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.
vector<SMPInstr *>::iterator InstIter;
InstIter = CurrBlock->GetFirstInst();
ea_t FirstBadAddr = (*InstIter)->GetAddr();
InstIter = CurrBlock->GetLastInst();
--InstIter; // get last real instruction
ea_t LastBadAddr = (*InstIter)->GetAddr();
this->EraseInstRange(FirstBadAddr, LastBadAddr);
// Remove the block from the blocks list.
BlockIter = this->Blocks.erase(BlockIter);
this->BlockCount -= 1;
#if 0 // Exception handling code requires something more delicate than this. Later checks for stack adjustment etc. can look at these blocks.
// Finally, call destructors on the block and insts removed.
InstIter = CurrBlock->GetFirstInst();
while (InstIter != CurrBlock->GetLastInst()) {
SMPInstr *DeadInst = (*InstIter);
++InstIter;
if (NULL != DeadInst) delete DeadInst;
}
delete CurrBlock;
#endif
}
else { // HellNodeCase
// Block must be reachable only through an unresolved indirect branch.
// Make each unresolved indirect branch link to the block so it is reachable.
list<SMPBasicBlock *>::iterator WorkIter;
AddedMissingLinks = true;
for (WorkIter = UnresolvedBranchWorkList.begin(); WorkIter != UnresolvedBranchWorkList.end(); ++ WorkIter) {
SMPBasicBlock *WorkBlock = (*WorkIter);
WorkBlock->LinkToSucc(CurrBlock);
}
// Mark CurrBlock as now being reachable, along with the blocks it dominates.
CurrBlock->DepthFirstMark();
++BlockIter;
}
changed = true;
} // end if (processed) ... else ...
} // end loop through blocks
} while (changed);
if (HellNodeCase && (!AddedMissingLinks)) {
SMP_msg("SERIOUS WARNING: Function at %lx has unresolved indirect branches but no unreachable blocks.\n",
(unsigned long) this->FirstEA);
}
#if 0
// 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.
bool NoPredecessors;
bool OnlyPredIsItself;
list<SMPBasicBlock *>::iterator CurrPred;
#if SMP_USE_SWITCH_TABLE_INFO
if (!(this->HasUnresolvedIndirectJumps() || this->HasUnresolvedIndirectCalls())) {
if (!(this->HasIndirectJumps() || this->HasIndirectCalls())) {
bool changed;
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.
vector<SMPInstr *>::iterator InstIter;
InstIter = CurrBlock->GetFirstInst();
ea_t FirstBadAddr = (*InstIter)->GetAddr();
InstIter = CurrBlock->GetLastInst();
--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);
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
} // end if not unresolved indirect jumps or indirect calls
else if (this->UnresolvedIndirectJumps) {
// Make each unresolved indirect branch have each block with no predecessor as a target,
// so that the resulting CFG has a proper structure.
BlockIter = this->Blocks.begin();
++BlockIter; // The top block is expected to have no predecessors, which is not a CFG problem.
bool AddedMissingLinks = false;
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) {
// Block must be reachable only through an unresolved indirect branch.
// Make each unresolved indirect branch link to the block so it is reachable.
list<SMPBasicBlock *>::iterator WorkIter;
AddedMissingLinks = true;
for (WorkIter = UnresolvedBranchWorkList.begin(); WorkIter != UnresolvedBranchWorkList.end(); ++ WorkIter) {
SMPBasicBlock *WorkBlock = (*WorkIter);
WorkBlock->LinkToSucc(CurrBlock);
}
}
++BlockIter;
} // end for all blocks
if (!AddedMissingLinks) {
SMP_msg("SERIOUS WARNING: Function at %x has unresolved indirect branches but no unreachable blocks.\n", this->FirstEA);
}
}
#endif
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()) {