Newer
Older
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
int PredIDOM = this->IDom.at(PredNum);
if (DebugFlag) 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;
}
if (DebugFlag) msg("Old NewIdom value: %d\n", NewIdom);
NewIdom = this->IntersectDoms(PredNum, NewIdom);
if (DebugFlag) 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)) {
if (DebugFlag) 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) {
msg("Global Name: ");
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) {
msg(" already in GlobalNames.\n");
}
#endif
}
else {
++index;
#if SMP_DEBUG_DATAFLOW
clc5q
committed
if (DebugFlag) {
msg(" inserted as index %d\n", ExtractGlobalIndex(TempOp));
}
#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
msg("Number of GlobalNames: %d\n", this->GlobalNames.size());
msg("Size of BlocksDefinedIn: %d\n", this->BlocksDefinedIn.size());
#endif
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.
msg("ComputeBlocksDefinedIn: Bad index: %d limit: %u\n", index,
this->GlobalNames.size());
msg("Block number %d\n", CurrBlock->GetNumber());
msg("Killed item: ");
PrintListOperand(*KillIter);
msg("\n");
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()));
if (DebugFlag) msg("GlobalNames size: %u\n", this->GlobalNames.size());
for (NameIter = this->GlobalNames.begin(); NameIter != this->GlobalNames.end(); ++NameIter) {
int CurrNameIndex = (int) (ExtractGlobalIndex(*NameIter));
if (DebugFlag) 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
if (DebugFlag) 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
if (DebugFlag) msg("WorkIter: %d\n", *WorkIter);
#endif
if (DebugFlag && (*WorkIter > this->BlockCount)) {
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
if (DebugFlag) msg("DomFront: %d\n", *DomFrontIter);
#endif
if (DebugFlag && (*DomFrontIter > this->BlockCount)) {
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
if (DebugFlag) msg("Added phi for name %d at top of block %d\n", CurrNameIndex, PhiBlock->GetNumber());
#endif
}
}
else {
if (DebugFlag) {
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) {
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
if (DebugFlag) 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!
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
this->DomTree.at(parent).second.push_back((int) index);
}
return;
} // end of SMPFunction::BuildDominatorTree()
// 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);
op_t UseOp, DefOp;
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()));
if (DumpFlag) 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 && DefOp.is_reg(R_ax)) {
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();
if (DumpFlag) msg("Processed phi functions at top.\n");
// For each instruction in the block, rename all global USEs and then all global DEFs.
list<SMPInstr *>::iterator InstIter;
SMPInstr *CurrInst;
for (InstIter = CurrBlock->GetFirstInstr(); InstIter != CurrBlock->GetLastInstr(); ++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.
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.
clc5q
committed
msg("Bad GlobIndex: %d at %x in %s\n", GlobIndex, 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].
msg("WARNING: function %s : Use of uninitialized variable: ",
this->GetFuncName());
msg(" Variable: ");
PrintListOperand(*GlobIter);
msg(" Block number: %d Address: %x Instruction: %s\n", BlockNumber,
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)) {
msg("New EAX Use SSANum: %d at %x\n", NewSSANum, CurrInst->GetAddr());
} // end for all USEs
set<DefOrUse, LessDefUse>::iterator CurrDef = CurrInst->GetFirstDef();
while (CurrDef != CurrInst->GetLastDef()) {
// See if Def is a global name.
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)) {
msg("New EAX Def SSANum: %d at %x\n", NewSSANum, 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
if (DumpFlag) 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
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
msg("WARNING: function %s : Path to use of uninitialized variable: ",
this->GetFuncName());
msg(" Variable: ");
PrintListOperand(CurrPhi->GetAnyOp());
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)) {
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)) {
msg("Special before phi dump:\n");
set<SMPPhiFunction, LessPhi>::iterator FoundPhi;
FoundPhi = (*SuccIter)->FindPhi(TempIter->GetAnyOp());
FoundPhi->Dump();
}
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
// 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)) {
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
if (DumpFlag) 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);
}
if (DumpFlag) 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();
}
if (DumpFlag) msg("Popped off entries due to phi functions.\n");
for (InstIter = CurrBlock->GetFirstInstr(); InstIter != CurrBlock->GetLastInstr(); ++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) {
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) {
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();
// 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
if (DebugFlag) 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) {
msg(" InferTypes iteration: %ld NewChangeCount: %ld \n", IterationCount, NewChangeCount);
}
clc5q
committed
#if 0
} while (changed);
clc5q
committed
#endif
#if SMP_DEBUG_TYPE_INFERENCE
if (DebugFlag) 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;
}
ea_t DefAddr = CurrInst->GetAddr();
// 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()));
SMPOperandType DefType = UNINIT;
DefType = this->InferGlobalDefType(DefOp,
clc5q
committed
CurrDef->GetSSANum(), CurrBlock, CallInst, DefAddr);
if (IsNotEqType(UNINIT, DefType)) {
CurrDef = CurrInst->SetDefType(DefOp, DefType);
--(this->UntypedDefs);
++(this->TypedDefs);
} // 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
if (DebugFlag) 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
if (DebugFlag) 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) {
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
void SMPFunction::InferFGInfo(void) {
bool changed, NewChange;
unsigned short IterCount = 0;
list<SMPInstr *>::iterator InstIter;
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
do {
changed = false;
++IterCount;
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
NewChange = CurrInst->InferFGInfo(IterCount);
changed = (changed || NewChange);
}
if (changed) {
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
CurrBlock->PropagatePhiFGInfo();
}
}
} while (changed);
return;
} // end of SMPFunction::InferFGInfo()
// Apply the profiler information to this function once we've inferred everything we can about it.
void SMPFunction::ApplyProfilerInformation(ProfilerInformation* pi)
{
assert(pi);
// If no profiler annotations are available, save time.
if (0 == pi->GetProfilerAnnotationCount())
return;
SetIsSpeculative(true);
list<SMPInstr *>::iterator InstIter;
set<DefOrUse, LessDefUse>::iterator CurrDef, NextDef;
bool DebugFlag = false;
DebugFlag |= (0 == strcmp("dohanoi", this->GetFuncName()));
#endif
// for each instruction in this function
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
// lookup whether a load at this instruction was profiled as always numeric
InstructionInformation* ii = pi->GetInfo(CurrInst->GetAddr());
msg("Found instruction information for %x\n", CurrInst->GetAddr());
if (ii && ii->isNumeric()) {
#if SMP_DEBUG_PROFILED_TYPE_INFERENCE
msg("Found instruction information for %x and it's numeric!\n", CurrInst->GetAddr());
CurrInst->UpdateMemLoadTypes((SMPOperandType)(NUMERIC|PROF_BASE));
}
// lookup whether this instruction has been profiled as an indirect call
set<ea_t> indirect_call_targets = pi->GetIndirectCallTargets(CurrInst->GetAddr());
for (set<ea_t>::iterator ict_iter = indirect_call_targets.begin();
ict_iter != indirect_call_targets.end();
++ict_iter)
ea_t target = *ict_iter;
if (vector_exists(target, IndirectCallTargets))
IndirectCallTargets.push_back(target);
if (vector_exists(target, AllCallTargets))
AllCallTargets.push_back(target);
}
return;
} // end of SMPFunction::ApplyProfilerInformation
clc5q
committed
// For the UNINIT type DEF DefOp, see if all its USEs have a single type.
// If so, set the DEF to that type and return type,
clc5q
committed
// If DefAddr == BADADDR, then the DEF is in a Phi function, not an instruction.
SMPOperandType SMPFunction::InferGlobalDefType(op_t DefOp, int SSANum, SMPBasicBlock *DefBlock, bool CallInst, ea_t DefAddr) {
bool DebugFlag = false;
bool FoundNumeric = false;
bool FoundPointer = false;
bool FoundUnknown = false;
bool FoundUninit = false;
clc5q
committed
bool FoundDEF;
bool DefEscapes = true;
#if SMP_DEBUG_TYPE_INFERENCE
DebugFlag |= (0 == strcmp("mem_init", this->GetFuncName()));
if (DebugFlag) {
msg("InferGlobalDefType for SSANum %d of ", SSANum);
PrintOperand(DefOp);
msg("\n");
}
list<SMPInstr *>::iterator InstIter;
clc5q
committed
set<DefOrUse, LessDefUse>::iterator CurrUse, CurrDef;
// Go through all instructions in the block and find the instructions
// that have USEs of DefOp with SSANum. If all USEs in the chain have
// a single type (other than UNINIT), change the DEF type to match the
// USE type and set changed to true.
SMPOperandType UseType = UNINIT;
SMPOperandType PtrType = UNINIT;
clc5q
committed
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
if (BADADDR == DefAddr) { // DEF is in a Phi function
FoundDEF = true;
}
else { // DEF is in an instruction
FoundDEF = false; // need to see the DefAddr first
}
for (InstIter = DefBlock->GetFirstInstr(); InstIter != DefBlock->GetLastInstr(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
if ((!FoundDEF) && (DefAddr == CurrInst->GetAddr())) {
FoundDEF = true;
}
else if (FoundDEF) {
CurrDef = CurrInst->FindDef(DefOp);
if (CurrDef != CurrInst->GetLastDef()) {
// Found re-DEF of DefOp.
DefEscapes = false;
}
}
CurrUse = CurrInst->FindUse(DefOp);
if (CurrUse != CurrInst->GetLastUse()) { // found a USE of DefOp
if (CurrUse->GetSSANum() == SSANum) { // matched SSA number
UseType = CurrUse->GetType();
FoundNumeric |= (IsNumeric(UseType));
FoundUnknown |= (IsUnknown(UseType));
FoundUninit |= (IsEqType(UNINIT, UseType));
if (IsDataPtr(UseType)) {
if (FoundPointer) {
if (IsNotEqType(PtrType, UseType)) {
clc5q
committed
msg("WARNING: Differing ptr types in global chain:");
msg(" Prev: %d Current: %d %s\n", PtrType, UseType,
CurrInst->GetDisasm());
clc5q
committed
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
else {
FoundPointer = true;
PtrType = UseType;
}
}
} // end if matched SSA #
} // end if found a USE of DefOp
} // end for all instructions
if (DefEscapes) { // did not find re-def
DefEscapes = DefBlock->IsLiveOut(DefOp);
}
if (DefEscapes) { // Need to recurse into successor blocks
list<SMPBasicBlock *>::iterator SuccIter;
ea_t TempAddr;
this->ResetProcessedBlocks(); // set up recursion
for (SuccIter = DefBlock->GetFirstSucc(); SuccIter != DefBlock->GetLastSucc(); ++SuccIter) {
SMPBasicBlock *CurrBlock = (*SuccIter);
set<SMPPhiFunction, LessPhi>::iterator PhiIter = CurrBlock->FindPhi(DefOp);
TempAddr = DefAddr;
if (PhiIter != CurrBlock->GetLastPhi()) {
TempAddr = BADADDR; // signals that DefOp will get re-DEFed in a Phi function.
}
else if (BADADDR == TempAddr) { // was BADADDR coming in to this function
// We don't want to pass BADADDR down the recursion chain, because it will be interpreted
// by each successor block to mean that DefOp was a Phi USE that got re-DEFed in a Phi function
// within itself. Pass the dummy address that indicates LiveIn to the block.
TempAddr = CurrBlock->GetFirstAddr() - 1;
clc5q
committed
// Should we screen the recursive call below using CurrBlock->IsLiveIn(DefOp) for speed? !!!!****!!!!
CurrBlock->InferGlobalDefType(DefOp, SSANum, TempAddr, FoundNumeric, FoundPointer, FoundUnknown, FoundUninit, PtrType);
clc5q
committed
// Do we have a consistent type?
// If we see any definite POINTER uses, we must set the DEF
// to type POINTER or a refinement of it.
if (FoundPointer)
UseType = PtrType;
else if (FoundNumeric && !FoundUninit && !FoundUnknown)
UseType = NUMERIC;
else
return UNINIT; // no POINTER, but no consistent type
assert(UNINIT != UseType);
if (DebugFlag) msg("Inferring global DEF of type %d\n", UseType);
#define SMP_SIMPLE_CONDITIONAL_TYPE_PROPAGATION 1
#if SMP_SIMPLE_CONDITIONAL_TYPE_PROPAGATION
// The simple form of conditional type propagation observes that we
// simply need to apply the meet operator over Phi function USEs and
// then propagate any DEF type changes using PropagateGlobalDefType().
// The outermost iteration over all type inference methods in InferTypes()
// will take care of all the propagation that is handled by the work list
// processing in the textbook algorithm.
// Iteration convergence might be slower in the simple approach, but the code
// is much simpler to debug.