Newer
Older
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.
clc5q
committed
FirstBlock->AddVarKill(*UpExposedIter); // "killed" by marker inst def
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.
clc5q
committed
FirstBlock->AddVarKill(*LiveOutIter); // "killed" by marker inst def
FirstBlock->AddLiveIn(*LiveOutIter);
}
#endif
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
if (DebugFlag) SMP_msg("Exiting LiveVariableAnalysis\n");
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
#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
}
clc5q
committed
this->IDom[0] = 0; // First block is 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) {
SMP_msg("WARNING: 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
SMP_msg("WARNING: Assuming block %d at address %lx is reachable indirectly.\n",
CurrBlock->GetNumber(), (unsigned long) CurrBlock->GetFirstAddr());
clc5q
committed
}
else {
// Might be exception handling code, reachable only by call stack walking.
NewIdom = 0; // make it be dominated by entry block
SMP_msg("WARNING: Assuming block %d at address %lx is reachable by exception handling.\n",
CurrBlock->GetNumber(), (unsigned long) CurrBlock->GetFirstAddr());
}
}
assert(NewIdom != SMP_BLOCKNUM_UNINIT);
// Loop through all predecessors of block RPONum except block NewIdom.
// Set NewIdom to the intersection of its Dom set and the Doms set of
// each predecessor that has had its Doms set computed.
for (CurrPred = CurrBlock->GetFirstPred(); CurrPred != CurrBlock->GetLastPred(); ++CurrPred) {
int PredNum = (*CurrPred)->GetNumber();
clc5q
committed
if (DebugFlag) SMP_msg("PredNum: %d\n", PredNum);
// **!!** We can avoid failure on unreachable basic blocks
// by executing a continue statement if PredNum is -1. Long term solution
clc5q
committed
// is to prune out unreachable basic blocks, or better yet, create hell nodes
// if the function has indirect jumps.
if (PredNum == SMP_BLOCKNUM_UNINIT)
continue;
int PredIDOM = this->IDom.at(PredNum);
clc5q
committed
if (DebugFlag) SMP_msg("PredIDOM: %d\n", PredIDOM);
if ((SMP_BLOCKNUM_UNINIT == PredIDOM) || (NewIdom == PredIDOM)) {
// Skip predecessors that have uncomputed Dom sets, or are the
// current NewIdom.
continue;
}
clc5q
committed
if (DebugFlag) SMP_msg("Old NewIdom value: %d\n", NewIdom);
NewIdom = this->IntersectDoms(PredNum, NewIdom);
clc5q
committed
if (DebugFlag) SMP_msg("New NewIdom value: %d\n", NewIdom);
}
// If NewIdom is not the value currently in vector IDom[], update the
// vector entry and set changed to true.
if (NewIdom != this->IDom.at(RPONum)) {
clc5q
committed
if (DebugFlag) SMP_msg("IDOM changed from %d to %d\n", this->IDom.at(RPONum), NewIdom);
this->IDom[RPONum] = NewIdom;
changed = true;
}
}
} while (changed);
return;
} // end of SMPFunction::ComputeIDoms()
// Compute dominance frontier sets for each block.
void SMPFunction::ComputeDomFrontiers(void) {
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *RunnerBlock;
SMPBasicBlock *CurrBlock;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
// We look only at join points in the CFG, as per Cooper/Torczon chapter 9.
if (1 < CurrBlock->GetNumPreds()) { // join point; more than 1 predecessor
int runner;
list<SMPBasicBlock *>::iterator PredIter;
SMPBasicBlock *CurrPred;
for (PredIter = CurrBlock->GetFirstPred(); PredIter != CurrBlock->GetLastPred(); ++PredIter) {
CurrPred = (*PredIter);
// For each predecessor, we run up the IDom[] vector and add CurrBlock to the
// DomFrontier for all blocks that are between CurrPred and IDom[CurrBlock],
// not including IDom[CurrBlock] itself.
runner = CurrPred->GetNumber();
while (runner != this->IDom.at(CurrBlock->GetNumber())) {
// Cooper/Harvey/Kennedy paper does not quite agree with the later
// text by Cooper/Torczon. Text says that the start node has no IDom
// in the example on pages 462-463, but it shows an IDOM for the
// root node in Figure 9.9 of value == itself. The first edition text
// on p.463 seems correct, as the start node dominates every node and
// thus should have no dominance frontier.
if (SMP_TOP_BLOCK == runner)
break;
RunnerBlock = this->RPOBlocks.at(runner);
RunnerBlock->AddToDomFrontier(CurrBlock->GetNumber());
runner = this->IDom.at(runner);
}
} // end for all predecessors
} // end if join point
} // end for all blocks
return;
} // end of SMPFunction::ComputeDomFrontiers()
// Compute the GlobalNames set, which includes all operands that are used in more than
// one basic block. It is the union of all UpExposedSets of all blocks.
void SMPFunction::ComputeGlobalNames(void) {
set<op_t, LessOp>::iterator SetIter;
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
unsigned int index = 0;
if (this->Blocks.size() < 2)
return; // cannot have global names if there is only one block
bool DebugFlag = false;
#if SMP_DEBUG_DATAFLOW
DebugFlag = (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
for (SetIter = CurrBlock->GetFirstUpExposed(); SetIter != CurrBlock->GetLastUpExposed(); ++SetIter) {
op_t TempOp = *SetIter;
// The GlobalNames set will have the complete collection of operands that we are
// going to number in our SSA computations. We now assign an operand number
// within the op_t structure for each, so that we can index into the
// BlocksUsedIn[] vector, for example. This operand number is not to be
// confused with SSA numbers.
// We use the operand number field op_t.n for the lower 8 bits, and the offset
// fields op_t.offb:op_t.offo for the upper 16 bits. We are overwriting IDA
// values here, but operands in the data flow analysis sets should never be
// inserted back into the program anyway.
SetGlobalIndex(&TempOp, index);
#if SMP_DEBUG_DATAFLOW
clc5q
committed
if (DebugFlag) {
clc5q
committed
SMP_msg("Global Name: ");
clc5q
committed
PrintListOperand(TempOp);
}
#endif
set<op_t, LessOp>::iterator AlreadyInSet;
pair<set<op_t, LessOp>::iterator, bool> InsertResult;
InsertResult = this->GlobalNames.insert(TempOp);
if (!InsertResult.second) {
// Already in GlobalNames, so don't assign an index number.
;
#if SMP_DEBUG_DATAFLOW
clc5q
committed
if (DebugFlag) {
clc5q
committed
SMP_msg(" already in GlobalNames.\n");
clc5q
committed
}
#endif
}
else {
++index;
#if SMP_DEBUG_DATAFLOW
clc5q
committed
if (DebugFlag) {
clc5q
committed
SMP_msg(" inserted as index %d\n", ExtractGlobalIndex(TempOp));
clc5q
committed
}
#endif
}
} // for each upward exposed item in the current block
} // for each basic block
assert(16777215 >= this->GlobalNames.size()); // index fits in 24 bits
return;
} // end of SMPFunction::ComputeGlobalNames()
// For each item in GlobalNames, record the blocks that DEF the item.
void SMPFunction::ComputeBlocksDefinedIn(void) {
// Loop through all basic blocks and examine all DEFs. For Global DEFs, record
// the block number in BlocksDefinedIn. The VarKillSet records DEFs without
// having to examine every instruction.
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
this->BlocksDefinedIn.clear();
for (size_t i = 0; i < this->GlobalNames.size(); ++i) {
list<int> TempList;
this->BlocksDefinedIn.push_back(TempList);
}
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
SMP_msg("Number of GlobalNames: %d\n", this->GlobalNames.size());
SMP_msg("Size of BlocksDefinedIn: %d\n", this->BlocksDefinedIn.size());
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
set<op_t, LessOp>::iterator KillIter;
for (KillIter = CurrBlock->GetFirstVarKill(); KillIter != CurrBlock->GetLastVarKill(); ++KillIter) {
// If killed item is not a block-local item (it is global), record it.
set<op_t, LessOp>::iterator NameIter = this->GlobalNames.find(*KillIter);
if (NameIter != this->GlobalNames.end()) { // found in GlobalNames set
// We have a kill of a global name. Get index from three 8-bit fields.
unsigned int index = ExtractGlobalIndex(*NameIter);
if (index >= this->GlobalNames.size()) {
// We are about to assert false.
clc5q
committed
SMP_msg("ComputeBlocksDefinedIn: Bad index: %d limit: %zu\n", index,
this->GlobalNames.size());
clc5q
committed
SMP_msg("Block number %d\n", CurrBlock->GetNumber());
SMP_msg("Killed item: ");
PrintListOperand(*KillIter);
clc5q
committed
SMP_msg("\n");
SMP_msg("This is a fatal error.\n");
assert(index < this->GlobalNames.size());
// index is a valid subscript for the BlocksDefinedIn vector. Push the
// current block number onto the list of blocks that define this global name.
this->BlocksDefinedIn[index].push_back(CurrBlock->GetNumber());
}
}
}
return;
} // end of SMPFunction::ComputeBlocksDefinedIn()
// Compute the phi functions at the entry point of each basic block that is a join point.
void SMPFunction::InsertPhiFunctions(void) {
set<op_t, LessOp>::iterator NameIter;
list<int> WorkList; // list of block numbers
bool DebugFlag = false;
#if SMP_DEBUG_DATAFLOW
DebugFlag = (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
clc5q
committed
if (DebugFlag) SMP_msg("GlobalNames size: %zu\n", this->GlobalNames.size());
for (NameIter = this->GlobalNames.begin(); NameIter != this->GlobalNames.end(); ++NameIter) {
int CurrNameIndex = (int) (ExtractGlobalIndex(*NameIter));
clc5q
committed
if (DebugFlag) SMP_msg("CurrNameIndex: %d\n", CurrNameIndex);
#if 0
DebugFlag = (DebugFlag && (6 == CurrNameIndex));
#endif
// Initialize the work list to all blocks that define the current name.
WorkList.clear();
list<int>::iterator WorkIter;
for (WorkIter = this->BlocksDefinedIn.at((size_t) CurrNameIndex).begin();
WorkIter != this->BlocksDefinedIn.at((size_t) CurrNameIndex).end();
++WorkIter) {
WorkList.push_back(*WorkIter);
}
// Iterate through the work list, inserting phi functions for the current name
// into all the blocks in the dominance frontier of each work list block.
// Insert into the work list each block that had a phi function added.
while (!WorkList.empty()) {
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
if (DebugFlag) SMP_msg("WorkList size: %d\n", WorkList.size());
list<int>::iterator WorkIter = WorkList.begin();
while (WorkIter != WorkList.end()) {
set<int>::iterator DomFrontIter;
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
if (DebugFlag) SMP_msg("WorkIter: %d\n", *WorkIter);
#endif
if (DebugFlag && (*WorkIter > this->BlockCount)) {
clc5q
committed
SMP_msg("ERROR: WorkList block # %d out of range.\n", *WorkIter);
SMPBasicBlock *WorkBlock = this->RPOBlocks[*WorkIter];
for (DomFrontIter = WorkBlock->GetFirstDomFrontier();
DomFrontIter != WorkBlock->GetLastDomFrontier();
++DomFrontIter) {
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
if (DebugFlag) SMP_msg("DomFront: %d\n", *DomFrontIter);
#endif
if (DebugFlag && (*DomFrontIter > this->BlockCount)) {
clc5q
committed
SMP_msg("ERROR: DomFront block # %d out of range.\n", *DomFrontIter);
SMPBasicBlock *PhiBlock = this->RPOBlocks[*DomFrontIter];
// Before inserting a phi function for the current name in *PhiBlock,
// see if the current name is LiveIn for *PhiBlock. If not, there
// is no need for the phi function. This check is what makes the SSA
// a fully pruned SSA.
if (PhiBlock->IsLiveIn(*NameIter)) {
size_t NumPreds = PhiBlock->GetNumPreds();
DefOrUse CurrRef(*NameIter);
SMPPhiFunction CurrPhi(CurrNameIndex, CurrRef);
for (size_t NumCopies = 0; NumCopies < NumPreds; ++NumCopies) {
CurrPhi.PushBack(CurrRef); // inputs to phi
}
if (PhiBlock->AddPhi(CurrPhi)) {
// If not already in Phi set, new phi function was inserted.
WorkList.push_back(PhiBlock->GetNumber());
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
if (DebugFlag) SMP_msg("Added phi for name %d at top of block %d\n", CurrNameIndex, PhiBlock->GetNumber());
#endif
}
}
else {
if (DebugFlag) {
clc5q
committed
SMP_msg("Global %d not LiveIn for block %d\n", CurrNameIndex, PhiBlock->GetNumber());
}
}
} // end for all blocks in the dominance frontier
// Remove current block number from the work list
if (DebugFlag) {
clc5q
committed
SMP_msg("Removing block %d from work list.\n", *WorkIter);
WorkIter = WorkList.erase(WorkIter);
} // end for all block numbers in the work list
} // end while the work list is not empty
clc5q
committed
if (DebugFlag) SMP_msg("WorkList empty.\n");
} // end for all elements of the GlobalNames set
return;
} // end of SMPFunction::InsertPhiFunctions()
// Build the dominator tree.
void SMPFunction::BuildDominatorTree(void) {
size_t index;
// First, fill the DomTree vector with the parent numbers filled in and the child lists
// left empty.
for (index = 0; index < this->IDom.size(); ++index) {
pair<int, list<int> > DomTreeEntry;
DomTreeEntry.first = this->IDom.at(index);
DomTreeEntry.second.clear();
this->DomTree.push_back(DomTreeEntry);
}
// Now, push the children onto the appropriate lists.
for (index = 0; index < this->IDom.size(); ++index) {
// E.g. if block 5 has block 3 as a parent, then we fetch the number 3
// using the expression this->DomTree.at(index).first, which was just
// initialized in the previous loop. Then we go to DomTree entry 3 and push
// the number 5 on its child list.
int parent = this->DomTree.at(index).first;
if (parent != (int) index) // block can dominate itself, but not in DomTree!
this->DomTree.at(parent).second.push_back((int) index);
}
return;
} // end of SMPFunction::BuildDominatorTree()
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
// Does basic block HeadBlockNum dominate basic block TailBlockNum?
bool SMPFunction::DoesBlockDominateBlock(int HeadBlockNum, int TailBlockNum) {
if (HeadBlockNum == TailBlockNum)
return true;
else if ((HeadBlockNum == SMP_BLOCKNUM_UNINIT) || (TailBlockNum == SMP_BLOCKNUM_UNINIT)) {
return false;
}
else {
// Recurse downward from HeadBlockNum in the dominator tree until we find TailBlockNum
// or return false if we never find it.
bool FoundIt = false;
for (list<int>::iterator ChildIter = this->DomTree.at(HeadBlockNum).second.begin();
ChildIter != this->DomTree.at(HeadBlockNum).second.end();
++ChildIter) {
int ChildBlockNum = (*ChildIter);
if (this->DoesBlockDominateBlock(ChildBlockNum, TailBlockNum)) { // recurse depth-first
FoundIt = true;
break;
}
}
return FoundIt;
}
} // end of SMPFunction::DoesBlockDominateBlock()
// Is block (with block # BlockNum) inside any loop?
bool SMPFunction::IsBlockInAnyLoop(int BlockNum) {
bool FoundInsideLoop = this->FuncLoopsByBlock.at((size_t)BlockNum).IsAnyBitSet();
return FoundInsideLoop;
} // end of SMPFunction::IsBlockInAnyLoop()
// Is block (with block # BlockNum) inside loop # LoopNum?
bool SMPFunction::IsBlockInLoop(int BlockNum, size_t LoopNum) {
return ((LoopNum < this->LoopCount) && (this->FuncLoopsByBlock.at((size_t) BlockNum).GetBit(LoopNum)));
} // end of SMPFunction::IsBlockInLoop()
// build list of loop numbers that BlockNum is part of.
void SMPFunction::BuildLoopList(int BlockNum, list<size_t> &LoopList) {
size_t LoopIndex;
for (LoopIndex = 0; LoopIndex < this->LoopCount; ++LoopIndex) {
if (this->FuncLoopsByBlock.at((size_t) BlockNum).GetBit(LoopIndex)) {
LoopList.push_back(LoopIndex);
}
}
return;
} // end of SMPFunction::BuildLoopList()
// Helper for SSA subscript renumbering: return the next SSA number for the global name
// and increment the SSACounter to prepare the next number. Push the returned number onto
// the SSAStack for the global name.
int SMPFunction::SSANewNumber(size_t GlobNameIndex) {
int Subscript = this->SSACounter.at(GlobNameIndex);
++(this->SSACounter[GlobNameIndex]);
this->SSAStack[GlobNameIndex].push_back(Subscript);
return Subscript;
} // end of SMPFunction::SSANewNumber()
// Main helper for SSA subscript renumbering. Renumber within block throughout its phi
// functions, then its DEFs and USEs, then its phi successors. Recurse then on all
// successors in the dominator tree.
void SMPFunction::SSARename(int BlockNumber) {
assert(0 <= BlockNumber);
assert(BlockNumber < this->BlockCount);
SMPBasicBlock *CurrBlock = this->RPOBlocks.at((size_t) BlockNumber);
bool DumpFlag = false;
#if SMP_DEBUG_DATAFLOW_VERBOSE
DumpFlag |= (0 == strcmp("main", this->GetFuncName()));
DumpFlag |= (0 == strcmp("dohanoi", this->GetFuncName()));
DumpFlag |= (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
DumpFlag |= (0 == strcmp("_IO_sputbackc", this->GetFuncName()));
clc5q
committed
if (DumpFlag) SMP_msg("Entered SSARename for block number %d\n", BlockNumber);
// For each phi function at the top of the block, rename the DEF of the phi function
// using SSANewNumber() on the global name index.
set<SMPPhiFunction, LessPhi>::iterator CurrPhi;
list<SMPPhiFunction> TempPhiList;
int GlobalNameIndex;
for (CurrPhi = CurrBlock->GetFirstPhi(); CurrPhi != CurrBlock->GetLastPhi(); ++CurrPhi) {
op_t PhiDefOp = CurrPhi->GetAnyOp();
GlobalNameIndex = CurrPhi->GetIndex();
assert(0 <= GlobalNameIndex);
int NewSSANum = this->SSANewNumber((size_t) GlobalNameIndex);
// Cannot change the C++ STL set item directly, as sets might become unordered.
SMPPhiFunction TempPhi = (*CurrPhi);
TempPhi.SetSSADef(NewSSANum);
TempPhiList.push_back(TempPhi);
if (o_reg == PhiDefOp.type) {
if (DumpFlag && PhiDefOp.is_reg(R_ax)) {
clc5q
committed
SMP_msg("New EAX Phi Def SSANum: %d Block %d\n", NewSSANum, BlockNumber);
}
// Map the final SSA number to the block number.
int DefHashValue = HashGlobalNameAndSSA(PhiDefOp, NewSSANum);
pair<int, ea_t> DefMapEntry(DefHashValue, CurrBlock->GetNumber());
pair<map<int, ea_t>::iterator, bool> MapReturnValue;
MapReturnValue = this->GlobalDefAddrBySSA.insert(DefMapEntry);
assert(MapReturnValue.second);
}
}
// Go back through the Phi function set and replace the items that need to be updated.
list<SMPPhiFunction>::iterator TempIter;
for (TempIter = TempPhiList.begin(); TempIter != TempPhiList.end(); ++TempIter) {
// Use the op_t from the first phi use, because they are all the same.
bool Erased = CurrBlock->ErasePhi(TempIter->GetPhiRef(0).GetOp());
assert(Erased);
// Now we can add back the phi function that had the DEF SSA number changed.
bool Added = CurrBlock->AddPhi(*TempIter);
assert(Added);
}
TempPhiList.clear();
clc5q
committed
if (DumpFlag) SMP_msg("Processed phi functions at top.\n");
// For each instruction in the block, rename all global USEs and then all global DEFs.
vector<SMPInstr *>::iterator InstIter;
SMPInstr *CurrInst;
for (InstIter = CurrBlock->GetFirstInst(); InstIter != CurrBlock->GetLastInst(); ++InstIter) {
set<DefOrUse, LessDefUse>::iterator CurrUse = CurrInst->GetFirstUse();
ea_t InstAddr = CurrInst->GetAddr(); // for debugging break points
while (CurrUse != CurrInst->GetLastUse()) {
// See if Use is a global name.
op_t UseOp = CurrUse->GetOp();
set<op_t, LessOp>::iterator GlobIter = this->GlobalNames.find(UseOp);
if (GlobIter != this->GlobalNames.end()) { // found it
unsigned int GlobIndex = ExtractGlobalIndex(*GlobIter);
if (GlobIndex > this->SSAStack.size()) {
// Get some debug info out to the log file before we crash.
SMP_msg("FATAL ERROR: Bad GlobIndex: %d at %lx in %s\n", GlobIndex, (unsigned long) InstAddr, this->GetFuncName());
exit(EXIT_FAILURE);
}
// Set the SSA number for this use to the top of stack SSA # (back())
int NewSSANum;
if (this->SSAStack.at(GlobIndex).empty()) {
// No top of stack entry to read.
#if SMP_DEBUG_UNINITIALIZED_SSA_NAMES
if (!CurrInst->MDIsPopInstr() && (o_reg == UseOp.type)) {
// POP uses the stack offset and generates spurious
// uninitialized variable messages for [esp+0].
clc5q
committed
SMP_msg("WARNING: function %s : Use of uninitialized variable: ",
this->GetFuncName());
clc5q
committed
SMP_msg(" Variable: ");
PrintListOperand(*GlobIter);
SMP_msg(" Block number: %d Address: %lx Instruction: %s\n", BlockNumber,
(unsigned long) CurrInst->GetAddr(), CurrInst->GetDisasm());
}
#endif
NewSSANum = SMP_SSA_UNINIT;
}
else {
NewSSANum = this->SSAStack.at(GlobIndex).back();
}
CurrUse = CurrInst->SetUseSSA(UseOp, NewSSANum);
if (DumpFlag && (o_reg == UseOp.type) && UseOp.is_reg(R_ax)) {
SMP_msg("New EAX Use SSANum: %d at %lx\n", NewSSANum, (unsigned long) CurrInst->GetAddr());
} // end for all USEs
set<DefOrUse, LessDefUse>::iterator CurrDef = CurrInst->GetFirstDef();
while (CurrDef != CurrInst->GetLastDef()) {
// See if Def is a global name.
op_t DefOp = CurrDef->GetOp();
set<op_t, LessOp>::iterator GlobIter = this->GlobalNames.find(DefOp);
if (GlobIter != this->GlobalNames.end()) { // found it
unsigned int GlobIndex = ExtractGlobalIndex(*GlobIter);
// Set the SSA number for this DEF to the SSANewNumber top of stack
int NewSSANum = this->SSANewNumber(GlobIndex);
CurrDef = CurrInst->SetDefSSA(DefOp, NewSSANum);
if (o_reg == DefOp.type) {
clc5q
committed
ea_t DefAddr = InstAddr;
if (DumpFlag && DefOp.is_reg(R_ax)) {
SMP_msg("New EAX Def SSANum: %d at %lx\n", NewSSANum, (unsigned long) DefAddr);
}
// Map the final SSA number to the DEF address.
int DefHashValue = HashGlobalNameAndSSA(DefOp, NewSSANum);
pair<int, ea_t> DefMapEntry(DefHashValue, DefAddr);
pair<map<int, ea_t>::iterator, bool> MapReturnValue;
MapReturnValue = this->GlobalDefAddrBySSA.insert(DefMapEntry);
assert(MapReturnValue.second);
}
} // end for all DEFs
} // end for all instructions
clc5q
committed
if (DumpFlag) SMP_msg("Processed all instructions.\n");
// For all control flow graph (not dominator tree) successors, fill in the current
// (outgoing) SSA number in the corresponding USE slot in the phi function, for all
// global names appearing in phi functions.
list<SMPBasicBlock *>::iterator SuccIter;
for (SuccIter = CurrBlock->GetFirstSucc(); SuccIter != CurrBlock->GetLastSucc(); ++SuccIter) {
// What position in the Preds list of this successor is CurrBlock?
int ListPos = (*SuccIter)->GetPredPosition(BlockNumber);
assert(0 <= ListPos);
// Go through all phi functions in this successor. At ListPos position in the
// incoming arguments for that phi function, set the SSA number to the SSA number
// in the top of stack entry for the global name associated with that phi function.
set<SMPPhiFunction, LessPhi>::iterator CurrPhi;
for (CurrPhi = (*SuccIter)->GetFirstPhi(); CurrPhi != (*SuccIter)->GetLastPhi(); ++CurrPhi) {
int GlobIndex = CurrPhi->GetIndex();
int CurrSSA;
if (this->SSAStack.at(GlobIndex).empty()) {
// No top of stack entry to read.
#if SMP_DEBUG_UNINITIALIZED_SSA_NAMES
clc5q
committed
SMP_msg("WARNING: function %s : Path to use of uninitialized variable: ",
this->GetFuncName());
clc5q
committed
SMP_msg(" Variable: ");
PrintListOperand(CurrPhi->GetAnyOp());
clc5q
committed
SMP_msg(" Block number: %d Successor block number: %d\n", BlockNumber,
(*SuccIter)->GetNumber());
#endif
CurrSSA = SMP_SSA_UNINIT;
}
else {
CurrSSA = this->SSAStack.at(GlobIndex).back(); // fetch from top of stack
}
SMPPhiFunction TempPhi = (*CurrPhi);
TempPhi.SetSSARef(ListPos, CurrSSA);
TempPhiList.push_back(TempPhi);
if (DumpFlag && (BlockNumber >= 3) && (BlockNumber <= 4)) {
clc5q
committed
SMP_msg("BlockNumber: %d ListPos: %d\n", BlockNumber, ListPos);
}
} // end for all phi functions in successor
// Go back through the Phi function set and replace the items that need to be updated.
for (TempIter = TempPhiList.begin(); TempIter != TempPhiList.end(); ++TempIter) {
if (DumpFlag && (BlockNumber >= 3) && (BlockNumber <= 4)) {
clc5q
committed
SMP_msg("Special before phi dump:\n");
set<SMPPhiFunction, LessPhi>::iterator FoundPhi;
FoundPhi = (*SuccIter)->FindPhi(TempIter->GetAnyOp());
FoundPhi->Dump();
}
// Use the op_t from the first phi use, because they are all the same.
bool Erased = (*SuccIter)->ErasePhi(TempIter->GetPhiRef(0).GetOp());
assert(Erased);
// Now we can add back the phi function that had one SSA number changed.
bool Added = (*SuccIter)->AddPhi(*TempIter);
assert(Added);
if (DumpFlag && (BlockNumber >= 3) && (BlockNumber <= 4)) {
clc5q
committed
SMP_msg("Special after phi dump:\n");
set<SMPPhiFunction, LessPhi>::iterator FoundPhi;
FoundPhi = (*SuccIter)->FindPhi(TempIter->GetAnyOp());
FoundPhi->Dump();
}
}
TempPhiList.clear();
} // end for all successors of CurrBlock
clc5q
committed
if (DumpFlag) SMP_msg("Processed successor phi functions.\n");
// For each successor in the dominator tree, recurse.
list<int>::iterator ChildIter;
for (ChildIter = this->DomTree[BlockNumber].second.begin();
ChildIter != this->DomTree[BlockNumber].second.end();
++ChildIter) {
this->SSARename(*ChildIter);
}
clc5q
committed
if (DumpFlag) SMP_msg("Finished recursion.\n");
// Pop off all SSAStack entries pushed during this block. I.e. for each global name,
// pop its SSAStack once per DEF and once per phi function in this block.
for (CurrPhi = CurrBlock->GetFirstPhi(); CurrPhi != CurrBlock->GetLastPhi(); ++CurrPhi) {
GlobalNameIndex = CurrPhi->GetIndex();
this->SSAStack.at((size_t) GlobalNameIndex).pop_back();
}
clc5q
committed
if (DumpFlag) SMP_msg("Popped off entries due to phi functions.\n");
for (InstIter = CurrBlock->GetFirstInst(); InstIter != CurrBlock->GetLastInst(); ++InstIter) {
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = CurrInst->GetFirstDef(); CurrDef != CurrInst->GetLastDef(); ++CurrDef) {
// See if DEF is a global name.
set<op_t, LessOp>::iterator GlobIter = this->GlobalNames.find(CurrDef->GetOp());
if (GlobIter != this->GlobalNames.end()) { // found it
unsigned int GlobIndex = ExtractGlobalIndex(*GlobIter);
this->SSAStack.at((size_t) GlobIndex).pop_back();
}
} // end for all DEFs
} // end for all instructions
if (DumpFlag) {
clc5q
committed
SMP_msg("Popped off entries due to instructions.\n");
return;
} // end of SMPFunction::SSARename()
// Main driver of SSA subscript renumbering.
void SMPFunction::SSARenumber(void) {
bool DumpFlag = false;
DumpFlag |= (0 == strcmp("_IO_sputbackc", this->GetFuncName()));
#endif
if (0 >= this->GlobalNames.size())
return; // no names to renumber
// Initialize stacks and counters of SSA numbers.
size_t GlobIndex;
assert(0 == this->SSACounter.size());
for (GlobIndex = 0; GlobIndex < this->GlobalNames.size(); ++GlobIndex) {
list<int> DummyList;
this->SSACounter.push_back(0);
this->SSAStack.push_back(DummyList);
}
// Recurse through the dominator tree starting with node 0.
this->SSARename(0);
if (DumpFlag)
this->Dump();
} // end of SMPFunction::SSARenumber()
// Emit debugging output for analyzing time spent in InferTypes() ?
#define SMP_ANALYZE_INFER_TYPES_TIME 0
// Main driver for the type inference system.
void SMPFunction::InferTypes(bool FirstIter) {
// The type inference system is an iteration over four analysis steps, until
// a fixed point is reached:
// 1) Within an instruction, set types of operators based on the operator type,
// the operand types, and the instruction type category, and propagate the
// type of the SMP_ASSIGN operator to its DEF.
// 2) Propagate the type of a DEF along its SSA chain to all USEs of that SSA name.
// 3) If all USEs of an SSA name have the same type, but the DEF has no type,
// 4) If all references to a memory location have the same type, mark that memory
// location as having that type, if no aliasing occurs.
//
// The type inference system will mark DEFs and USEs in each instruction's DEF and USE
clc5q
committed
// sets with an inferred type. This inference on USEs is not conclusive for other USEs
// outside of that instruction. For example, a pointer could be read in from memory
// and used as a pointer, then hashed using an arithmetic operation. If the arithmetic
// operation always treats its source operands as NUMERIC and produces a NUMERIC
// result, e.g. SMP_BITWISE_XOR, then the USE of that pointer is NUMERIC within
// this xor instruction. If the DEF at the beginning of the SSA chain for the pointer
// is eventually marked as POINTER, then all USEs in the chain will be marked POINTER
// as well (see step 2 above). This inconsistency along the USE chain is perfectly
// acceptable in our type system. It is important to mark the USEs according to how
// we observe them being used, because consistent USEs will propagate back up to
// the DEF in step 3 above.
bool changed;
#if SMP_ANALYZE_INFER_TYPES_TIME
bool DebugFlag2 = false;
DebugFlag2 |= (0 == strcmp("Option", this->GetFuncName()));
long NewChangeCount;
long IterationCount = 0;
#endif
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
bool DebugFlag = false;
DebugFlag |= (0 == strcmp("__libc_csu_init", this->GetFuncName()));
list<SMPInstr *>::iterator InstIter;
SMPInstr *CurrInst;
set<DefOrUse, LessDefUse>::iterator CurrDef;
set<DefOrUse, LessDefUse>::iterator NextDef;
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
if (DebugFlag) {
this->Dump();
}
clc5q
committed
#endif
// One time only: Set the types of immediate values, flags register, stack and frame
// pointers, and floating point registers.
if (FirstIter) {
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
CurrInst = (*InstIter);
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
if (DebugFlag) {
clc5q
committed
SMP_msg("SetImmedTypes for inst at %x: %s\n", CurrInst->GetAddr(), CurrInst->GetDisasm());
clc5q
committed
#endif
CurrInst->SetImmedTypes(this->UseFP);
// Infer signedness, bit width, and other info from the nature of the instruction
// (e.g. loads from stack locations whose signedness has been inferred earlier
// in FindOutGoingArgSize(), or inherently signed arithmetic opcodes like signed
// or unsigned multiplies and divides).
CurrInst->MDSetWidthSignInfo(this->UseFP);
}
// Check for signedness inferences from conditional branches at the end of blocks.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
CurrBlock->MarkBranchSignedness();
clc5q
committed
// Find counter variables (e.g. init to zero or small constant, then just add or subtract small
// constant values. These cannot be POINTER and can be marked as NUMERIC.
this->FindCounterVariables();
// Iterate until no more changes: set types in DEF and USE lists based on RTL
// operators and the instruction category, SSA DEF-USE chains, etc.
#if SMP_ANALYZE_INFER_TYPES_TIME
if (DebugFlag2)
++IterationCount;
#endif
clc5q
committed
#if 0
do {
clc5q
committed
#endif
changed = false;
#if SMP_ANALYZE_INFER_TYPES_TIME
if (DebugFlag2)
NewChangeCount = 0;
#endif
// Step one: Infer types within instructions, context free.
// Step two, propagating DEF types to all USEs, happens within step one
// whenever a DEF type is set for the first time.
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
CurrInst = (*InstIter);
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
if (DebugFlag) SMP_msg("Inferring types for %s\n", CurrInst->GetDisasm());
clc5q
committed
#endif
NewChange = CurrInst->InferTypes();
changed = (changed || NewChange);
#if SMP_ANALYZE_INFER_TYPES_TIME
clc5q
committed
if (DebugFlag2 && NewChange) {
ea_t InstAddr = CurrInst->GetAddr();
clc5q
committed
}
#endif
}
#if SMP_ANALYZE_INFER_TYPES_TIME
if (DebugFlag2) {
clc5q
committed
SMP_msg(" InferTypes iteration: %ld NewChangeCount: %ld \n", IterationCount, NewChangeCount);
}
clc5q
committed
#if 0
} while (changed);
clc5q
committed
#endif
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
if (DebugFlag) SMP_msg("Finished type inference steps 1 and 2.\n");
clc5q
committed
#endif
// Step three: If all USEs of an SSA name have the same type, but the DEF has no
// type, then infer that the DEF must have the same type.
this->TypedDefs = 0;
this->UntypedDefs = 0;
clc5q
committed
this->TypedPhiDefs = 0;
this->UntypedPhiDefs = 0;
clc5q
committed
// This step of the type inference might converge faster if we used a reverse iterator
// to go through the instructions, because we could infer a DEF, propagate it to
// the right hand side by making SMPInstr::InferOperatorType() public and calling it
// on the SMP_ASSIGN operator after we set the type of the left hand side (DEF). Any
// additional DEF inferences would be triggered mostly in the upwards direction by
// setting the type of one or more USEs in the current instruction. How much time gain
// could be achieved by doing this sequence is questionable. !!!!****!!!!****
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
CurrInst = (*InstIter);
// Find any DEF that still has type UNINIT.
CurrDef = CurrInst->GetFirstDef();
while (CurrDef != CurrInst->GetLastDef()) {
// Set erase() and insert() are needed to change types of DEFs, so
// get hold of the next iterator value now.
NextDef = CurrDef;
++NextDef;
NewChange = false;
if (UNINIT != CurrDef->GetType()) {
++(this->TypedDefs);
}
else {
bool MemDef = (DefOp.type != o_reg);
bool AliasedMemWrite = (MemDef && CurrDef->HasIndirectWrite());
++(this->UntypedDefs);
if (MDIsIndirectMemoryOpnd(DefOp, this->UseFP) // relax this?
#if 0
#endif
|| AliasedMemWrite) {
// Don't want to infer along DEF-USE chains for indirect
// memory accesses until we have alias analysis.
++CurrDef;
continue;
}
// Call inference method based on whether it is a block-local
// name or a global name.
CurrBlock = CurrInst->GetBlock();
if (CurrBlock->IsLocalName(DefOp)) {
NameIter = CurrBlock->FindLocalName(DefOp);
assert(CurrBlock->GetLastLocalName() != NameIter);
unsigned int LocIndex = ExtractGlobalIndex(*NameIter);
NewChange = CurrBlock->InferLocalDefType(DefOp, LocIndex, DefAddr);
if (NewChange) {
--(this->UntypedDefs);
++(this->TypedDefs);
}
changed = (changed || NewChange);
}
else {
// global name
bool CallInst = ((CALL == CurrInst->GetDataFlowType())
|| (INDIR_CALL == CurrInst->GetDataFlowType()));
int DefSSANum = CurrDef->GetSSANum();
SMPOperandType DefType = UNINIT;
DefType = this->InferGlobalDefType(DefOp,
DefSSANum, CurrBlock, CallInst, DefAddr);
if (IsNotEqType(UNINIT, DefType)) {
CurrDef = CurrInst->SetDefType(DefOp, DefType);
--(this->UntypedDefs);
++(this->TypedDefs);
// If we have one or more USEs of type POINTER and the
// other USEs are UNINIT, then InferGlobalDefType() will
// infer that it is a POINTER. We want to propagate POINTER
// to all the USEs now.
if (IsDataPtr(DefType)) {
clc5q
committed
this->ResetProcessedBlocks();
CurrInst->GetBlock()->PropagateGlobalDefType(DefOp, DefType, DefSSANum, IsMemOperand(DefOp));
}
} // end if local name ... else ...
} // end if (UNINIT != CurrDef->GetType()) .. else ...
CurrDef = NextDef;
} // end while all DEFs in the DEF set
} // end for all instructions
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
if (DebugFlag) SMP_msg("Finished type inference step 3.\n");
clc5q
committed
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
clc5q
committed
changed |= CurrBlock->InferAllPhiDefTypes();
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
if (DebugFlag) SMP_msg("Finished unconditional phi type inference.\n");
clc5q
committed
#endif
#if SMP_CONDITIONAL_TYPE_PROPAGATION
if (!changed) { // Try conditional type propagation
changed |= this->ConditionalTypePropagation();
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
if (DebugFlag) {
clc5q
committed
SMP_msg("changed = %d after conditional type propagation.\n", changed);
clc5q
committed
}
#endif
}
#endif
// With type inference finished, infer signedness from the types, e.g.
// POINTER and CODEPOINTER types must be UNSIGNED.
if (FirstIter) { // Don't want profiler-dependent signedness in the system yet.
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
(*InstIter)->InferSignednessFromSMPTypes(this->UsesFramePointer());
}
}
// Record the meet of all register types that reach RETURN instructions.
this->MDFindReturnTypes();
return;
} // end of SMPFunction::InferTypes()
// determine signedness and width info for all operands