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
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
return false; // block already processed
// Proceed by cases:
ea_t DefAddr = CurrInst->GetAddr();
// Case 1: Local name. Return the IndWrite flag for the local Def-Use
// chain begun by CurrInst.
if (CurrBlock->IsLocalName(DefOp)) {
return CurrBlock->GetLocalDUChainIndWrite(DefOp, SSANum);
}
// Case 2: Global name.
// Case 2A: If Def-Use chain within this block for this memory operand
// has its IndWrite flag set to true, then stop and return true.
else if (CurrBlock->GetGlobalDUChainIndWrite(DefOp, DefAddr)) {
return true;
}
// Case 2B: Else if Def-Use chain is not the last chain in this block
// for this operand, then there must be a later redefinition of the
// memory operand (with new SSA number assigned) later in this block.
// Because we did not fall into case 2A, we know there is no IndWrite
// within the current memory operand's chain, so we return false.
else if (CurrBlock->IsLastGlobalChain(DefOp, DefAddr)) {
return false;
}
// Case 2C: Else if current memory operand is NOT LiveOut, even though
// this is the last def-use chain in the block, then there is no more
// traversing of the control flow graph to be done. The chain has ended
// without encountering an IndWrite, so return false.
else if (!(CurrBlock->IsLiveOut(DefOp))) {
return false;
}
// Case 2D: We have passed all previous checks, so we must have a memory
// operand that reaches the end of the block without encountering an
// IndWrite and is LiveOut. Its may-alias status will be determined by
// following the control flow graph for all successor blocks and examining
// the def-use chains in those blocks.
list<SMPBasicBlock *>::iterator SuccBlock;
SuccBlock = CurrBlock->GetFirstSucc();
bool FoundAliasedWrite = false;
FoundAliasedWrite = this->FindChainAliasHelper(SuccBlock, DefOp);
++SuccBlock;
} while (!FoundAliasedWrite && (SuccBlock != CurrBlock->GetLastSucc()));
return FoundAliasedWrite;
} // end of SMPFunction::FindPossibleChainAlias()
// recursive helper for global DU-chains that traverse CFG
bool SMPFunction::FindChainAliasHelper(list<SMPBasicBlock *>::iterator BlockIter, op_t DefOp) {
bool DebugFlag = false;
SMPBasicBlock *CurrBlock = (*BlockIter);
if (0 == strcmp("mem2chunk_check", this->GetFuncName())) {
// Next line is just a good place to set a break point.
DebugFlag = true;
}
if (!(CurrBlock->IsProcessed())) {
CurrBlock->SetProcessed(true);
}
else
return false; // block already processed
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
// The LVA sets can be used to decide whether it is possible that
// the incoming DU chain overlaps a may-alias write. We can express
// the decision making in a truth table:
//
// Case # LiveIn? Killed? AliasedWrite in block? Action to take
// ------- ------- ------- ---------------------- --------------
// 1 N N N return false
// 2 N N Y return false
// 3 N Y N return false
// 4 N Y Y return false
// 5 Y N N recurse into successors
// 6 Y N Y return true
// 7 Y Y N return false
// 8 Y Y Y check location of aliased write
//
// In the last case, if there is an aliased write before the
// incoming DEF is killed and after it is used, then the
// incoming DU chain overlaps an aliased write, otherwise
// it does not.
// If not LiveIn, incoming DU chain does not run through this block
// at all, so return false.
if (!(CurrBlock->IsLiveIn(DefOp)))
return false; // cases 1-4
bool killed = CurrBlock->IsVarKill(DefOp);
bool BlockHasAliasedWrite = CurrBlock->MaybeAliasedWrite();
if (BlockHasAliasedWrite) {
// If DefOp is LiveIn and is not killed, then any aliased
// write in the block overlaps the incoming DU chain.
if (!killed) {
return true; // case 6
}
// If DefOp is LiveIn and is killed, then the location
// of the aliased write is the determining factor.
else {
// Incoming global DU chains get a new global DU chain
// built within the block with a pseudo-DefAddr of
// one byte before the first address of the block.
ea_t PseudoDefAddr = CurrBlock->GetFirstAddr() - 1;
return CurrBlock->GetGlobalDUChainIndWrite(DefOp, PseudoDefAddr); // case 8
}
else {
// If killed, no aliased write, then cannot overlap an aliased write.
if (killed)
return false; // case 7
else {
// Need to recurse into all successors, because we passed through
// the block without seeing an aliased write and without killing
// the DefOp.
list<SMPBasicBlock *>::iterator SuccBlock;
SuccBlock = CurrBlock->GetFirstSucc();
bool FoundAliasedWrite = false;
while (!FoundAliasedWrite && (SuccBlock != CurrBlock->GetLastSucc())) {
FoundAliasedWrite = this->FindChainAliasHelper(SuccBlock, DefOp);
++SuccBlock;
};
if (DebugFlag) {
clc5q
committed
SMP_msg("FindChainAliasHelper is returning %d\n", FoundAliasedWrite);
}
return FoundAliasedWrite;
}
assert(false); // statement should be unreachable
return false;
} // end of SMPFunction::FindChainAliasHelper()
// Link basic blocks to their predecessors and successors, and build the map
// of instruction addresses to basic blocks.
void SMPFunction::SetLinks(void) {
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
SMP_msg("SetLinks called for %s\n", this->GetFuncName());
#endif
// First, set up the map of instructions to basic blocks.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
list<SMPInstr *>::iterator CurrInst;
for (CurrInst = CurrBlock->GetFirstInstr();
CurrInst != CurrBlock->GetLastInstr();
++CurrInst) {
pair<ea_t, SMPBasicBlock *> MapItem((*CurrInst)->GetAddr(), CurrBlock);
InstBlockMap.insert(MapItem);
}
}
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
SMP_msg("SetLinks finished mapping: %s\n", this->GetFuncName());
#endif
// Next, set successors of each basic block, also setting up the predecessors in the
// process.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
list<SMPInstr *>::iterator InstIter = (--(CurrBlock->GetLastInstr()));
SMPInstr *CurrInst = (*InstIter);
clc5q
committed
bool CondTailCall = false;
if (CurrBlock->HasReturn()) {
if (!(CurrInst->IsCondTailCall())) {
// We either have a return instruction or an unconditional
// tail call instruction. We don't want to link to the
// tail call target, and there is no link for a return
continue;
}
else {
// We have a conditional tail call. We don't want to
// link to the tail call target, but we do want fall
// through to the next instruction.
CondTailCall = true;
}
}
// Last instruction in block; set successors
bool CallFlag = (CALL == CurrInst->GetDataFlowType());
bool IndirCallFlag = (INDIR_CALL == CurrInst->GetDataFlowType());
clc5q
committed
bool TailCallFlag = CondTailCall && CurrInst->IsCondTailCall();
bool IndirJumpFlag = (INDIR_JUMP == CurrInst->GetDataFlowType());
clc5q
committed
SMP_xref_t CurrXrefs;
bool LinkedToTarget = false;
clc5q
committed
for (bool ok = CurrXrefs.SMP_first_from(CurrInst->GetAddr(), XREF_ALL);
clc5q
committed
ok = CurrXrefs.SMP_next_from()) {
if ((CurrXrefs.GetTo() != 0) && (CurrXrefs.GetIscode())) {
// Found a code target, with its address in CurrXrefs.to
if ((CallFlag || IndirCallFlag || TailCallFlag)
clc5q
committed
&& (CurrXrefs.GetTo() != (CurrInst->GetAddr() + CurrInst->GetCmd().size))) {
// A call instruction will have two targets: the fall through to the
// next instruction, and the called function. We want to link to the
// fall-through instruction, but not to the called function.
// Some blocks end with a call just because the fall-through instruction
// is a jump target from elsewhere.
continue;
}
map<ea_t, SMPBasicBlock *>::iterator MapEntry;
clc5q
committed
MapEntry = this->InstBlockMap.find(CurrXrefs.GetTo());
if (MapEntry == this->InstBlockMap.end()) {
clc5q
committed
SMP_msg("WARNING: addr %x not found in map for %s\n", CurrXrefs.GetTo(),
clc5q
committed
SMP_msg(" Referenced from %s\n", CurrInst->GetDisasm());
SMPBasicBlock *Target = MapEntry->second;
// Make target block a successor of current block.
CurrBlock->LinkToSucc(Target);
// Make current block a predecessor of target block.
Target->LinkToPred(CurrBlock);
LinkedToTarget = true;
#if SMP_USE_SWITCH_TABLE_INFO
if (IndirJumpFlag) {
clc5q
committed
SMP_msg("Switch table link: jump at %x target at %x\n",
CurrInst->GetAddr(), CurrXrefs.GetTo());
}
}
} // end for all xrefs
if (IndirJumpFlag && (!LinkedToTarget)) {
this->UnresolvedIndirectJumps = true;
clc5q
committed
SMP_msg("WARNING: Unresolved indirect jump at %x\n", CurrInst->GetAddr());
}
else if (IndirCallFlag && (!LinkedToTarget)) {
this->UnresolvedIndirectCalls = true;
clc5q
committed
SMP_msg("WARNING: Unresolved indirect call at %x\n", CurrInst->GetAddr());
} // end for all blocks
// If we have any blocks that are all no-ops and have no predecessors, remove those
// blocks. They are dead and make the CFG no longer a lattice. Any blocks that have
// no predecessors but are not all no-ops should also be removed with a different
// log message.
// NOTE: Prior to construction of hell nodes in functions with unresolved indirect jumps,
// we cannot conclude that a block with no predecessors is unreachable. Also, the block
// order might be such that removal of a block makes an already processed block
// unreachable, so we have to iterate until there are no more changes.
// NOTE: An odd new gcc recursion optimization uses indirect calls within the function, so
// they can behave like indirect jumps.
#if SMP_USE_SWITCH_TABLE_INFO
if (!(this->HasUnresolvedIndirectJumps() || this->HasUnresolvedIndirectCalls())) {
if (!(this->HasIndirectJumps() || this->HasIndirectCalls())) {
bool changed;
bool NoPredecessors;
bool OnlyPredIsItself;
list<SMPBasicBlock *>::iterator CurrPred;
do {
changed = false;
BlockIter = this->Blocks.begin();
++BlockIter; // don't delete the top block, no matter what.
while (BlockIter != this->Blocks.end()) {
CurrBlock = (*BlockIter);
OnlyPredIsItself = false;
CurrPred = CurrBlock->GetFirstPred();
NoPredecessors = (CurrPred == CurrBlock->GetLastPred());
if (!NoPredecessors) {
if ((*CurrPred)->GetFirstAddr() == CurrBlock->GetFirstAddr()) { // self-recursion
++CurrPred; // any more preds besides itself?
OnlyPredIsItself = (CurrPred == CurrBlock->GetLastPred());
// Only predecessor was the self-recursion if no more preds
}
}
if (NoPredecessors || OnlyPredIsItself) {
if (CurrBlock->AllNops())
clc5q
committed
SMP_msg("Removing all nops block at %x\n", CurrBlock->GetFirstAddr());
clc5q
committed
SMP_msg("Removing block with no predecessors at %x\n", CurrBlock->GetFirstAddr());
// Remove this block from the predecessors list of its successors.
list<SMPBasicBlock *>::iterator SuccIter;
ea_t TempAddr = CurrBlock->GetFirstAddr();
for (SuccIter = CurrBlock->GetFirstSucc(); SuccIter != CurrBlock->GetLastSucc(); ++SuccIter) {
(*SuccIter)->ErasePred(TempAddr);
}
// Remove the unreachable instructions from the function inst list.
list<SMPInstr *>::iterator InstIter;
InstIter = CurrBlock->GetFirstInstr();
ea_t FirstBadAddr = (*InstIter)->GetAddr();
InstIter = CurrBlock->GetLastInstr();
--InstIter; // get last real instruction
ea_t LastBadAddr = (*InstIter)->GetAddr();
this->EraseInstRange(FirstBadAddr, LastBadAddr);
// Finally, remove the block from the blocks list.
BlockIter = this->Blocks.erase(BlockIter);
this->BlockCount -= 1;
changed = true;
}
else {
++BlockIter;
}
} // end while all blocks after the first one
} while (changed);
} // end if not indirect jumps
return;
} // end of SMPFunction::SetLinks()
// Number all basic blocks in reverse postorder (RPO) and set RPOBlocks vector to
// access them.
void SMPFunction::RPONumberBlocks(void) {
#if SMP_DEBUG_DATAFLOW
clc5q
committed
bool DebugFlag = false;
DebugFlag = (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
clc5q
committed
if (DebugFlag) SMP_msg("Entered RPONumberBlocks\n");
list<SMPBasicBlock *> WorkList;
// Number the first block with 0.
list<SMPBasicBlock *>::iterator BlockIter = this->Blocks.begin();
SMPBasicBlock *CurrBlock = (*BlockIter);
#if 0
if (this->RPOBlocks.capacity() <= (size_t) this->BlockCount) {
clc5q
committed
SMP_msg("Reserving %d RPOBlocks old value: %d\n", 2+this->BlockCount, this->RPOBlocks.capacity());
this->RPOBlocks.reserve(2 + this->BlockCount);
this->RPOBlocks.assign(2 + this->BlockCount, this->Blocks.end());
}
#endif
CurrBlock->SetNumber(CurrNum);
this->RPOBlocks.push_back(CurrBlock);
++CurrNum;
// Push the first block's successors onto the work list.
list<SMPBasicBlock *>::iterator CurrSucc = CurrBlock->GetFirstSucc();
while (CurrSucc != CurrBlock->GetLastSucc()) {
WorkList.push_back(*CurrSucc);
++CurrSucc;
}
// Use the WorkList to iterate through all blocks in the function
list<SMPBasicBlock *>::iterator CurrListItem = WorkList.begin();
bool change;
while (!WorkList.empty()) {
change = false;
while (CurrListItem != WorkList.end()) {
if ((*CurrListItem)->GetNumber() != SMP_BLOCKNUM_UNINIT) {
// Duplicates get pushed onto the WorkList because a block
// can be the successor of multiple other blocks. If it is
// already numbered, it is a duplicate and can be removed
// from the list.
CurrListItem = WorkList.erase(CurrListItem);
change = true;
continue;
}
if ((*CurrListItem)->AllPredecessorsNumbered()) {
// Ready to be numbered.
(*CurrListItem)->SetNumber(CurrNum);
#if 0
clc5q
committed
SMP_msg("Set RPO number %d\n", CurrNum);
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
if (DebugFlag && (7 == CurrNum))
this->Dump();
#endif
this->RPOBlocks.push_back(*CurrListItem);
++CurrNum;
change = true;
// Push its unnumbered successors onto the work list.
CurrSucc = (*CurrListItem)->GetFirstSucc();
while (CurrSucc != (*CurrListItem)->GetLastSucc()) {
if ((*CurrSucc)->GetNumber() == SMP_BLOCKNUM_UNINIT)
WorkList.push_back(*CurrSucc);
++CurrSucc;
}
CurrListItem = WorkList.erase(CurrListItem);
}
else {
++CurrListItem;
}
} // end while (CurrListItem != WorkList.end())
if (change) {
// Reset CurrListItem to beginning of work list for next iteration.
CurrListItem = WorkList.begin();
}
else {
// Loops can cause us to not be able to find a WorkList item that has
// all predecessors numbered. Take the WorkList item with the lowest address
// and number it so we can proceed.
CurrListItem = WorkList.begin();
ea_t LowAddr = (*CurrListItem)->GetFirstAddr();
list<SMPBasicBlock *>::iterator SaveItem = CurrListItem;
++CurrListItem;
while (CurrListItem != WorkList.end()) {
if (LowAddr > (*CurrListItem)->GetFirstAddr()) {
SaveItem = CurrListItem;
LowAddr = (*CurrListItem)->GetFirstAddr();
}
++CurrListItem;
}
// SaveItem should now be numbered.
(*SaveItem)->SetNumber(CurrNum);
#if SMP_DEBUG_DATAFLOW
clc5q
committed
SMP_msg("Picked LowAddr %x and set RPO number %d\n", LowAddr, CurrNum);
this->RPOBlocks.push_back(*SaveItem);
++CurrNum;
// Push its unnumbered successors onto the work list.
CurrSucc = (*SaveItem)->GetFirstSucc();
while (CurrSucc != (*SaveItem)->GetLastSucc()) {
if ((*CurrSucc)->GetNumber() == SMP_BLOCKNUM_UNINIT)
WorkList.push_back(*CurrSucc);
++CurrSucc;
}
CurrListItem = WorkList.erase(SaveItem);
CurrListItem = WorkList.begin();
} // end if (change) ... else ...
} // end while work list is nonempty
// Prior to construction of hell nodes for functions with indirect jumps, there
// could still be unnumbered blocks because they appear to be unreachable
// (no predecessors from SetLinks() because they are reached only via indirect
// jumps). We need to number these and push them on the RPOBlocks vector so
// that the vector contains all the blocks.
// NOTE: Odd new gcc recursion optimization seems to use indirect calls to reach
// some blocks within a recursive function, operating somewhat like an indirect
// jump.
if (this->HasIndirectJumps() || this->HasIndirectCalls()) {
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
if (SMP_BLOCKNUM_UNINIT == CurrBlock->GetNumber()) {
clc5q
committed
SMP_msg("WARNING: Numbering indirectly reachable block at %x\n", CurrBlock->GetFirstAddr());
CurrBlock->SetNumber(CurrNum);
this->RPOBlocks.push_back(CurrBlock);
++CurrNum;
}
}
}
clc5q
committed
// If we still have unnumbered blocks, it is not because of indirect jumps or calls.
// We have some mysterious dead code.
if (this->BlockCount > this->RPOBlocks.size()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: RPONumberBlocks method: Function %s has BlockCount %d and RPOBlocks size %zu\n",
this->GetFuncName(), this->BlockCount, this->RPOBlocks.size());
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
clc5q
committed
if (SMP_BLOCKNUM_UNINIT == CurrBlock->GetNumber()) {
clc5q
committed
SMP_msg("WARNING: Numbering apparently unreachable block at %x\n", CurrBlock->GetFirstAddr());
clc5q
committed
CurrBlock->SetNumber(CurrNum);
this->RPOBlocks.push_back(CurrBlock);
++CurrNum;
}
}
}
return;
} // end of SMPFunction::RPONumberBlocks()
// Perform live variable analysis on all blocks in the function.
// See chapter 9 of Cooper/Torczon, Engineering a Compiler, for the algorithm.
void SMPFunction::LiveVariableAnalysis(void) {
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
#if SMP_DEBUG_DATAFLOW
bool DebugFlag = (0 == strcmp("uw_frame_state_for", this->GetFuncName()));
#endif
#if SMP_DEBUG_DATAFLOW_VERBOSE
clc5q
committed
SMP_msg("LiveVariableAnalysis for %s\n", this->GetFuncName());
clc5q
committed
#endif
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
// Initialize the Killed and UpwardExposed sets for each block.
CurrBlock->InitKilledExposed();
}
bool changed;
// Iterate over each block, updating LiveOut sets until no more changes are made.
// NOTE: LVA is more efficient when computed over a reverse post-order list of blocks
// from the inverted CFG. We have an RPO list from the forward CFG, so it is just as
// good to simply iterate through the blocks in layout order.
#if 1
do {
changed = false;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
changed |= CurrBlock->UpdateLiveOut();
}
} while (changed);
#else // Use reverse postorder
do {
changed = false;
for (size_t index = 0; index < this->RPOBlocks.size(); ++index) {
CurrBlock = this->RPOBlocks.at(index);
changed |= CurrBlock->UpdateLiveOut();
}
} while (changed);
#if SMP_USE_SSA_FNOP_MARKER
// Create DEFs in the marker instruction for all names in the LiveInSet
// of the first block. These are the names for the function that
// would otherwise look like USEs of uninitialized variables later.
// Note that the LiveVariableAnalysis work does not actually populate
// a LiveInSet for the first block, so we simulate it with its
// dataflow equation, UpExposed union (LiveOut minus VarKill).
set<op_t, LessOp>::iterator UpExposedIter, LiveOutIter;
list<SMPInstr *>::iterator MarkerInst = this->Instrs.begin();
SMPBasicBlock *FirstBlock = this->Blocks.front();
for (UpExposedIter = FirstBlock->GetFirstUpExposed();
UpExposedIter != FirstBlock->GetLastUpExposed();
++UpExposedIter) {
// Add DEF with SSANum of 0.
(*MarkerInst)->AddDef(*UpExposedIter, UNINIT, 0);
clc5q
committed
// Add to the VarKill and LiveIn sets.
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");
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
#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) {
clc5q
committed
SMP_msg("Failure on NewIdom in ComputeIDoms for %s\n", this->GetFuncName());
if (this->HasIndirectJumps() || this->HasIndirectCalls()) {
// Might be reachable only through indirect jumps.
NewIdom = 0; // make it dominated by entry block
clc5q
committed
SMP_msg("Assuming block %d at address %d is reachable indirectly.\n",
clc5q
committed
CurrBlock->GetNumber(), CurrBlock->GetFirstAddr());
}
else {
// Might be exception handling code, reachable only by call stack walking.
NewIdom = 0; // make it be dominated by entry block
clc5q
committed
SMP_msg("Assuming block %d at address %d is reachable by exception handling.\n",
clc5q
committed
CurrBlock->GetNumber(), CurrBlock->GetFirstAddr());
}
}
assert(NewIdom != SMP_BLOCKNUM_UNINIT);
// Loop through all predecessors of block RPONum except block NewIdom.
// 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!
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
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()));
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 && DefOp.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.
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.