Newer
Older
// Ready to be numbered.
(*CurrListItem)->SetNumber(CurrNum);
#if 0
clc5q
committed
SMP_msg("Set RPO number %d\n", CurrNum);
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
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()) {
SMP_msg("WARNING: Numbering indirectly reachable block at %lx\n", (unsigned long) 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()) {
SMP_msg("WARNING: Numbering apparently unreachable block at %lx\n", (unsigned long) 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
#if SMP_ANALYZE_STACK_POINTER
;
#else
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
// Initialize the Killed and UpwardExposed sets for each block.
CurrBlock->InitKilledExposed(this->UsesFramePointer());
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.
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");
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
#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
#if SMP_DEBUG_DATAFLOW
bool DebugFlag = false;
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
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.
SMP_msg("ComputeBlocksDefinedIn: Bad index: %u 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()
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
// 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: %u 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 (this->GlobalNames.empty())
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);