Newer
Older
// 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();
// Iterate until no more changes: set types in DEF and USE lists based on RTL
// operators and the instruction category, SSA DEF-USE chains, etc.
#if SMP_ANALYZE_INFER_TYPES_TIME
if (DebugFlag2)
++IterationCount;
#endif
clc5q
committed
#if 0
do {
clc5q
committed
#endif
changed = false;
#if SMP_ANALYZE_INFER_TYPES_TIME
if (DebugFlag2)
NewChangeCount = 0;
#endif
// Step one: Infer types within instructions, context free.
// Step two, propagating DEF types to all USEs, happens within step one
// whenever a DEF type is set for the first time.
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
CurrInst = (*InstIter);
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
if (DebugFlag) SMP_msg("Inferring types for %s\n", CurrInst->GetDisasm());
clc5q
committed
#endif
NewChange = CurrInst->InferTypes();
changed = (changed || NewChange);
#if SMP_ANALYZE_INFER_TYPES_TIME
clc5q
committed
if (DebugFlag2 && NewChange) {
ea_t InstAddr = CurrInst->GetAddr();
clc5q
committed
}
#endif
}
#if SMP_ANALYZE_INFER_TYPES_TIME
if (DebugFlag2) {
clc5q
committed
SMP_msg(" InferTypes iteration: %ld NewChangeCount: %ld \n", IterationCount, NewChangeCount);
}
clc5q
committed
#if 0
} while (changed);
clc5q
committed
#endif
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
if (DebugFlag) SMP_msg("Finished type inference steps 1 and 2.\n");
clc5q
committed
#endif
// Step three: If all USEs of an SSA name have the same type, but the DEF has no
// type, then infer that the DEF must have the same type.
this->TypedDefs = 0;
this->UntypedDefs = 0;
clc5q
committed
this->TypedPhiDefs = 0;
this->UntypedPhiDefs = 0;
clc5q
committed
// This step of the type inference might converge faster if we used a reverse iterator
// to go through the instructions, because we could infer a DEF, propagate it to
// the right hand side by making SMPInstr::InferOperatorType() public and calling it
// on the SMP_ASSIGN operator after we set the type of the left hand side (DEF). Any
// additional DEF inferences would be triggered mostly in the upwards direction by
// setting the type of one or more USEs in the current instruction. How much time gain
// could be achieved by doing this sequence is questionable. !!!!****!!!!****
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
CurrInst = (*InstIter);
// Find any DEF that still has type UNINIT.
CurrDef = CurrInst->GetFirstDef();
while (CurrDef != CurrInst->GetLastDef()) {
// Set erase() and insert() are needed to change types of DEFs, so
// get hold of the next iterator value now.
NextDef = CurrDef;
++NextDef;
NewChange = false;
if (UNINIT != CurrDef->GetType()) {
++(this->TypedDefs);
}
else {
bool MemDef = (DefOp.type != o_reg);
bool AliasedMemWrite = (MemDef && CurrDef->HasIndirectWrite());
++(this->UntypedDefs);
if (MDIsIndirectMemoryOpnd(DefOp, this->UseFP) // relax this?
#if 0
#endif
|| AliasedMemWrite) {
// Don't want to infer along DEF-USE chains for indirect
// memory accesses until we have alias analysis.
++CurrDef;
continue;
}
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
clc5q
committed
if (DebugFlag) SMP_msg("Finished type inference step 3.\n");
clc5q
committed
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
clc5q
committed
changed |= CurrBlock->InferAllPhiDefTypes();
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
clc5q
committed
if (DebugFlag) SMP_msg("Finished unconditional phi type inference.\n");
clc5q
committed
#endif
#if SMP_CONDITIONAL_TYPE_PROPAGATION
if (!changed) { // Try conditional type propagation
changed |= this->ConditionalTypePropagation();
clc5q
committed
#if SMP_DEBUG_TYPE_INFERENCE
if (DebugFlag) {
clc5q
committed
SMP_msg("changed = %d after conditional type propagation.\n", changed);
clc5q
committed
}
#endif
}
#endif
// With type inference finished, infer signedness from the types, e.g.
// POINTER and CODEPOINTER types must be UNSIGNED.
if (FirstIter) { // Don't want profiler-dependent signedness in the system yet.
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
(*InstIter)->InferSignednessFromSMPTypes(this->UsesFramePointer());
}
}
// Record the meet of all register types that reach RETURN instructions.
this->MDFindReturnTypes();
return;
} // end of SMPFunction::InferTypes()
// determine signedness and width info for all operands
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();
}
}
#if STARS_AGGRESSIVE_SIGNEDNESS_PROPAGATION
if (!changed) {
changed = this->PropagateSignedness();
}
#endif
} 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());
clc5q
committed
SMP_msg("Found instruction information for %x\n", CurrInst->GetAddr());
if (ii && ii->isNumeric()) {
#if SMP_DEBUG_PROFILED_TYPE_INFERENCE
clc5q
committed
SMP_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()));
clc5q
committed
SMP_msg("InferGlobalDefType for SSANum %d of ", SSANum);
clc5q
committed
SMP_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
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
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
SMP_msg("WARNING: Differing ptr types in global chain:");
SMP_msg(" Prev: %d Current: %d %s\n", PtrType, UseType,
clc5q
committed
CurrInst->GetDisasm());
clc5q
committed
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
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);
clc5q
committed
if (DebugFlag) SMP_msg("Inferring global DEF of type %d\n", UseType);
clc5q
committed
#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.
bool SMPFunction::ConditionalTypePropagation(void) {
bool changed = false;
SMPBasicBlock *CurrBlock;
vector<SMPBasicBlock *>::iterator CurrRPO;
set<SMPPhiFunction, LessPhi>::iterator CurrPhi;
for (CurrRPO = this->RPOBlocks.begin(); CurrRPO != this->RPOBlocks.end(); ++CurrRPO) {
CurrBlock = *CurrRPO;
SMPOperandType MeetType;
for (CurrPhi = CurrBlock->GetFirstPhi(); CurrPhi != CurrBlock->GetLastPhi(); ++CurrPhi) {
MeetType = CurrPhi->ConditionalMeetType();
// Here we use a straight equality test, not our macros,
// because we consider it a change if the MeetType is
// profiler derived and the DEFType is not.
if (MeetType == CurrPhi->GetDefType())
continue;
// Change the DEF type to the MeetType and propagate.
op_t DefOp = CurrPhi->GetAnyOp();
bool IsMemOp = (o_reg != DefOp.type);
CurrPhi = CurrBlock->SetPhiDefType(DefOp, MeetType);
changed = true;
this->ResetProcessedBlocks();
changed |= CurrBlock->PropagateGlobalDefType(DefOp,
MeetType, CurrPhi->GetDefSSANum(), IsMemOp);
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
} // end for all phi functions in the current block
} // end for all blocks
return changed;
} // end of SMPFunction::ConditionalTypePropagation()
#else // not SMP_SIMPLE_CONDITIONAL_TYPE_PROPAGATION
// Apply the SCC (Sparse Conditional Constant) propagation algorithm to
// propagate types starting from unresolved Phi DEFs.
bool SMPFunction::ConditionalTypePropagation(void) {
bool changed = false;
// Collections of Phi functions and instructions that have a DEF
// with type UNINIT for the current global name.
map<int, set<SMPPhiFunction, LessPhi>::iterator> UninitDEFPhis;
vector<list<SMPInstr>::iterator> UninitDEFInsts;
// Work lists of Phi functions and instructions that need to be processed
// according to the SCC algorithm.
list<map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator> PhiWorkList;
list<vector<list<SMPInstr>::iterator>::iterator> InstWorkList;
// Iterate through all global names that are either (1) registers
// or (2) stack locations in SAFE functions.
set<op_t, LessOp>::iterator CurrGlob;
for (CurrGlob = this->GetFirstGlobalName(); CurrGlob != this->GetLastGlobalName(); ++CurrGlob) {
op_t GlobalOp = *CurrGlob;
list<SMPBasicBlock>::iterator CurrBlock;
vector<list<SMPBasicBlock>::iterator>::iterator CurrRPO;
if (MDIsIndirectMemoryOpnd(GlobalOp, this->UseFP))
continue; // need alias analysis to process indirect accesses
if ((GlobalOp.type != o_reg)
&& (!((this->GetReturnAddressStatus() == FUNC_SAFE) && MDIsStackAccessOpnd(GlobalOp, this->UseFP))))
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
continue; // not register, not safe stack access
// Set up a map (indexed by SSANum) of iterators to Phi functions
// for the current global name that have UNINIT as the Phi DEF type.
UninitDEFPhis.clear();
UninitDEFInsts.clear();
for (CurrRPO = this->RPOBlocks.begin(); CurrRPO != this->RPOBlocks.end(); ++CurrRPO) {
CurrBlock = *CurrRPO;
set<SMPPhiFunction, LessPhi>::iterator CurrPhi;
CurrPhi = CurrBlock->FindPhi(GlobalOp);
if (CurrPhi != CurrBlock->GetLastPhi()) {
// Found Phi function for current global name.
if (IsEqType(CurrPhi->GetDefType(), UNINIT)) {
// Phi DEF is UNINIT; add Phi to the map.
pair<int, set<SMPPhiFunction, LessPhi>::iterator> TempPair(CurrPhi->GetDefSSANum(), CurrPhi);
bool Inserted = false;
map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator WhereIns;
pair<map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator, bool> Result(WhereIns, Inserted);
Result = UninitDEFPhis.insert(TempPair);
assert(Result.second == true);
}
}
} // end for all blocks
// If any Phi DEF had UNINIT as its type, set up a vector of
// iterators to instructions that have UNINIT as the DEF type
// for the current global name.
if (UninitDEFPhis.empty())
continue;
list<SMPInstr *>::iterator InstIter;
for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
set<DefOrUse, LessDefUse>::iterator CurrDef = CurrInst->FindDef(GlobalOp);
if (CurrDef != CurrInst->GetLastDef()) {
// Found DEF of current global name.
if (IsEqType(UNINIT, CurrDef->GetType())) {
UninitDEFInsts.push_back(CurrInst);
}
}
} // end for all instructions
// Put all UNINIT Phi DEFs that have at least one USE
// that is not UNINIT onto the PhiWorkList.
map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator CurrUnPhi;
for (CurrUnPhi = UninitDEFPhis.begin(); CurrUnPhi != UninitDEFPhis.end(); ++CurrUnPhi) {
pair<int, set<SMPPhiFunction, LessPhi>::iterator> PhiDefPair(*CurrUnPhi);
if (PhiDefPair.second->HasTypedUses()) {
PhiWorkList.push_back(CurrUnPhi);
}
}
// Iterate until both work lists are empty:
while (!(PhiWorkList.empty() && InstWorkList.empty())) {
// Process Phi items first.
while (!PhiWorkList.empty()) {
// If applying the meet operator over the Phi USE types
// would produce a new DEF type, change the DEF type and
// propagate it, adding Phi functions and instructions that
// received the propagated type to their respective work lists.
map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator MapIter;
MapIter = PhiWorkList.front();
PhiWorkList.pop_front(); // remove from work list
pair<int, set<SMPPhiFunction, LessPhi>::iterator> PhiDefPair;
PhiDefPair.first = MapIter->first;
PhiDefPair.second = MapIter->second;
set<SMPPhiFunction, LessPhi>::iterator CurrPhi = PhiDefPair.second;
SMPOperandType MeetType = CurrPhi->ConditionalMeetType();
// Here we use a straight equality test, not our macros,
// because we consider it a change if the MeetType is
// profiler derived and the DEFType is not.
if (MeetType == CurrPhi->GetDefType())
continue;
// At this point, we need to set the DEFType to the MeetType
// and propagate the change. We have a map of all the
// critical Phi functions for this global name, as well
// as a vector of the relevant instructions for this name.
CurrPhi->SetDefType(MeetType);
changed = true;
int DefSSANum = CurrPhi->GetDefSSANum();
map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator PhiIter;
vector<list<SMPInstr>::iterator>::iterator InstIter;
// Propagate to Phi functions first.
for (PhiIter = UninitDEFPhis.begin(); PhiIter != UninitDEFPhis.end(); ++PhiIter) {
if (DefSSANum == PhiIter->first)
continue; // Skip the Phi that we just changed
for (size_t index = 0; index < PhiIter->second->GetPhiListSize(); ++index) {
if (DefSSANum == PhiIter->second->GetUseSSANum(index)) {
// Matched SSA # to USE. Propagate new type.
PhiIter->second->SetRefType(index, MeetType);
// Add this phi function to the work list.
PhiWorkList.push_back(PhiIter);
}
}
}
#define SMP_COND_TYPE_PROP_TO_INSTS 0
#if SMP_COND_TYPE_PROP_TO_INSTS
// Propagate to instructions with uninit DEFs of global name.
// The idea is that the instructions that hold up type propagation
// are the ones that USE and then DEF the same global name.
// For example, "increment EAX" has to know the type of
// the USE of EAX in order to set the type of the DEF.
#endif
} // end while the PhiWorkList is not empty
#if SMP_COND_TYPE_PROP_TO_INSTS
// The PhiWorkList is empty at this point, so process
// instructions on the InstWorkList.
#endif
} // end while both work lists are not empty
} // end for all global names
return changed;
} // end of SMPFunction::ConditionalTypePropagation()
#endif // end if SMP_SIMPLE_CONDITIONAL_TYPE_PROPAGATION else ...
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
// Propagate signedness FG info from DEFs to USEs whenever there is no USE sign info.
bool SMPFunction::PropagateSignedness(void) {
bool changed = false;
#if STARS_AGGRESSIVE_SIGNEDNESS_PROPAGATION
map<int, struct FineGrainedInfo>::iterator UseFGIter, DefFGIter;
list<SMPBasicBlock *>::iterator BlockIter;
for (UseFGIter = this->GlobalUseFGInfoBySSA.begin(); UseFGIter != this->GlobalUseFGInfoBySSA.end(); ++UseFGIter) {
struct FineGrainedInfo UseFG = UseFGIter->second;
if (0 == (UseFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) {
// No signedness info. Propagate any signedness info from DEF.
int UseHashValue = UseFGIter->first;
unsigned short DefSignMask = this->GetDefSignMiscInfo(UseHashValue);
DefSignMask &= FG_MASK_SIGNEDNESS_BITS;
if (0 != DefSignMask) {
// DEF has signedness info.
UseFGIter->second.SignMiscInfo |= DefSignMask;
changed = true;
}
}
}
// See if we have DEF signedness info for DEFs with no corresponding USE map entries.
for (DefFGIter = this->GlobalDefFGInfoBySSA.begin(); DefFGIter != this->GlobalDefFGInfoBySSA.end(); ++DefFGIter) {
struct FineGrainedInfo DefFG = DefFGIter->second;
unsigned short DefSignMask = (DefFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
if (0 != DefSignMask) {
// Has signedness info. See if USE has no entry.
int DefHashValue = DefFGIter->first;
UseFGIter = this->GlobalUseFGInfoBySSA.find(DefHashValue);
if (UseFGIter == this->GlobalUseFGInfoBySSA.end()) {
this->UpdateUseSignMiscInfo(DefHashValue, DefSignMask);
changed = true;
}
}
}
// Do the same processsing for block-local registers.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
bool NewChange = (*BlockIter)->PropagateDEFSignedness();
changed = changed || NewChange;
}
#endif
return changed;
} // end of SMPFunction::PropagateSignedness()
// Emit all annotations for the function, including all per-instruction
// annotations.
void SMPFunction::EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile) {
// Emit annotation for the function as a whole.
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
bool FuncHasProblems = ((!this->AnalyzedSP) || (!this->HasGoodRTLs()) || (this->HasUnresolvedIndirectCalls())
|| (this->HasUnresolvedIndirectJumps()) || (this->HasSharedChunks()));
if (this->StaticFunc) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6zu FUNC LOCAL %s ", this->FuncInfo.startEA,
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6zu FUNC GLOBAL %s ", this->FuncInfo.startEA,
switch (this->GetReturnAddressStatus())
{
case FUNC_UNKNOWN:
{
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_UNKNOWN ");
break;
}
case FUNC_SAFE:
{
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_SAFE ");
break;
}
case FUNC_UNSAFE:
{
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_UNSAFE ");
break;
}
default:
assert(0);
}
clc5q
committed
SMP_fprintf(AnnotFile, "USEFP ");
clc5q
committed
SMP_fprintf(AnnotFile, "NOFP ");
}
if (this->FuncInfo.does_return()) {
clc5q
committed
SMP_fprintf(AnnotFile, "RET ");
clc5q
committed
SMP_fprintf(AnnotFile, "NORET ");
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_LEAF ");
clc5q
committed
SMP_fprintf(AnnotFile,"%10x ", this->FuncInfo.endEA - 1);
clc5q
committed
SMP_fprintf(AnnotFile, "LIBRARY ");
SMP_fprintf(AnnotFile, "\n");
// Emit annotations about how to restore register values
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d FUNC FRAMERESTORE ", this->FuncInfo.startEA, 0);
clc5q
committed
for(int i = R_ax; i <= R_di; i++)
clc5q
committed
SMP_fprintf(AnnotFile, "%d %d %d ", i, this->SavedRegLoc[i], this->ReturnRegTypes[i]);
clc5q
committed
SMP_fprintf(AnnotFile, "ZZ\n");
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d FUNC MMSAFENESS ", this->FuncInfo.startEA, 0);
clc5q
committed
SMP_fprintf(AnnotFile, "UNSAFE\n");
clc5q
committed
SMP_fprintf(AnnotFile, "SPECSAFE\n");
clc5q
committed
SMP_fprintf(AnnotFile, "SAFE\n");
// If function has problems that limited our analyses, emit an information annotation so that
// other tools can be aware of which analyses will be sound.
if (FuncHasProblems) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "%10x %6zu FUNC PROBLEM %s ", this->FuncInfo.startEA,
if (!this->AnalyzedSP) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "STACKANALYSIS ");
}
if (this->HasSharedChunks()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "CHUNKS ");
}
if (this->HasUnresolvedIndirectJumps()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "JUMPUNRESOLVED ");
}
if (this->HasUnresolvedIndirectCalls()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "CALLUNRESOLVED ");
}
if (!this->HasGoodRTLs()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "BADRTLS ");
clc5q
committed
SMP_fprintf(InfoAnnotFile, "\n");
// Loop through all instructions in the function.
// Output optimization annotations for those
// instructions that do not require full computation
// of their memory metadata by the Memory Monitor SDT.
list<SMPInstr *>::iterator InstIter = Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
++InstIter; // skip marker instruction
#endif
bool AllocSeen = false; // Reached LocalVarsAllocInstr yet?
bool DeallocTrigger = false;
for ( ; InstIter != Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
ea_t addr = CurrInst->GetAddr();
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR BELONGTO %x \n", addr, 0, GetStartAddr());
if (this->LocalVarsAllocInstr == addr) {
AllocSeen = true;
clc5q
committed
this->EmitStackFrameAnnotations(AnnotFile, CurrInst);
clc5q
committed
int OptType = CurrInst->GetOptType();
if (5 == OptType) { // ADD or SUB
// Prevent mmStrata from extending the caller's stack frame
// to include the new allocation.
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL SafeFrameAlloc %s \n",
clc5q
committed
addr, -1, CurrInst->GetDisasm());
}
else if (CurrInst->MDIsPushInstr()) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
clc5q
committed
addr, -3, CurrInst->GetDisasm());
}
clc5q
committed
// mmStrata ignores the DATAREF annotations anyway, so even though
// they are not needed, emit them for use by Strata and other tools
// in other projects besides MEDS.
this->EmitStackFrameAnnotations(AnnotFile, CurrInst);
}
// If this is the instruction which deallocated space
// for local variables, we set a flag to remind us to
// emit an annotation on the next instruction.
// mmStrata wants the instruction AFTER the
// deallocating instruction, so that it processes
// the deallocation after it happens. It inserts
// instrumentation before an instruction, not
// after, so it will insert the deallocating
// instrumentation before the first POP of callee-saved regs,
// if there are any, or before the return, otherwise.
if (addr == this->LocalVarsDeallocInstr) {
DeallocTrigger = true;
}
else if (DeallocTrigger) { // Time for annotation
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d DEALLOC STACK esp - %d %s\n", addr,
this->LocalVarsSize, this->LocalVarsSize, CurrInst->GetDisasm());
DeallocTrigger = false;
}
#ifndef SMP_REDUCED_ANALYSIS
if (this->StackPtrAnalysisSucceeded() && this->HasGoodRTLs() && !this->HasUnresolvedIndirectJumps() && !this->HasSharedChunks()) {
CurrInst->EmitTypeAnnotations(this->UseFP, AllocSeen, this->NeedsStackReferent, AnnotFile, InfoAnnotFile);
CurrInst->EmitIntegerErrorAnnotations(InfoAnnotFile);
else
#endif
CurrInst->EmitAnnotations(this->UseFP, AllocSeen, this->NeedsStackReferent, AnnotFile, InfoAnnotFile);
if (CurrInst->MDIsReturnInstr() && this->GetReturnAddressStatus() == FUNC_SAFE)
CurrInst->EmitSafeReturn(AnnotFile);
} // end for all instructions
// Loop through all basic blocks and emit profiling request annotations
// for those blocks that have unsafe memory writes in them.
this->SafeBlocks = 0;
this->UnsafeBlocks = 0;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
if (CurrBlock->MaybeAliasedWrite()) {
++(this->UnsafeBlocks);
clc5q
committed
#if SMP_OPTIMIZE_BLOCK_PROFILING
list<SMPInstr *>::iterator CurrInst;
CurrInst = CurrBlock->GetFirstInstr();
ea_t addr = (*CurrInst)->GetAddr();
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d BLOCK PROFILECOUNT %s\n", addr,
(*CurrInst)->GetCmd().size, (*CurrInst)->GetDisasm());
clc5q
committed
#endif
}
else {
++(this->SafeBlocks);
}
}
return;
} // end of SMPFunction::EmitAnnotations()
// Debug output dump.
void SMPFunction::Dump(void) {
list<SMPBasicBlock *>::iterator CurrBlock;
clc5q
committed
SMP_msg("Debug dump for function: %s\n", this->GetFuncName());
SMP_msg("UseFP: %d LocalVarsAllocInstr: %x\n", this->UseFP,
this->LocalVarsAllocInstr);
for (size_t index = 0; index < this->IDom.size(); ++index) {
clc5q
committed
SMP_msg("IDOM for %zu: %d\n", index, this->IDom.at(index));
for (size_t index = 0; index < this->DomTree.size(); ++index) {
clc5q
committed
SMP_msg("DomTree for %zu: ", index);
list<int>::iterator DomIter;
for (DomIter = this->DomTree.at(index).second.begin();
DomIter != this->DomTree.at(index).second.end();
++DomIter) {
clc5q
committed
SMP_msg("%d ", *DomIter);
clc5q
committed
SMP_msg("\n");
clc5q
committed
SMP_msg("Global names: \n");
set<op_t, LessOp>::iterator NameIter;
for (NameIter = this->GlobalNames.begin(); NameIter != this->GlobalNames.end(); ++NameIter) {
clc5q
committed
SMP_msg("index: %d ", ExtractGlobalIndex(*NameIter));
PrintListOperand(*NameIter);
clc5q
committed
SMP_msg("\n");
clc5q
committed
SMP_msg("Blocks each name is defined in: \n");
for (size_t index = 0; index < this->BlocksDefinedIn.size(); ++index) {
clc5q
committed
SMP_msg("Name index: %zu Blocks: ", index);
list<int>::iterator BlockIter;
for (BlockIter = this->BlocksDefinedIn.at(index).begin();
BlockIter != this->BlocksDefinedIn.at(index).end();
++BlockIter) {
clc5q
committed
SMP_msg("%d ", *BlockIter);
clc5q
committed
SMP_msg("\n");
}
for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
// Dump out the function number and data flow sets before the instructions.
clc5q
committed
SMP_msg("End of debug dump for function: %s\n", this->GetFuncName());
return;
} // end of SMPFunction::Dump()
// Analyzes the function to see if the return address can be marked as safe
void SMPFunction::MarkFunctionSafe() {
clc5q
committed
SMP_msg(" Analyzing function %s and isLeaf = %d \n ", this->GetFuncName(), this->IsLeaf());
bool HasCallTargets = false;
clc5q
committed
bool HasStackPointerCopy = false;
bool HasStackPointerPush = false;
bool HasIndirectGlobalWrite = false;
bool WritesAboveLocalFrame = false; // Direct writes above local frame
bool WritesAboveLocalFrameIndirect = false; // Indirect writes above local frame
clc5q
committed
bool HasIndexedStackWrite = false;
bool HasIndirectWrite = false;
bool HasBranchToFarChunk = false; // tail call jump, or perhaps shared chunks in function
bool IsIndirectCallTarget = false; // could be called indirectly
bool IsTailCallTarget = false; // could be called by jump instruction used as tail call
bool HasNoCallers = this->AllCallSources.empty();
clc5q
committed
this->ReturnAddrStatus = FUNC_SAFE;
this->SafeFunc = true;
if (!this->AllCallTargets.empty()) {
HasCallTargets = true;
#if SMP_USE_SWITCH_TABLE_INFO
if (this->UnresolvedIndirectJumps) {
#else
clc5q
committed
SMP_msg("Function %s marked as unsafe due to indirect jumps\n", this->GetFuncName());
#if SMP_DECLARE_INDIRECT_TARGETS_UNSAFE
ea_t FirstAddr = this->FirstEA;
SMP_xref_t xrefs;
for (bool ok = xrefs.SMP_first_to(FirstAddr, XREF_ALL); ok; ok = xrefs.SMP_next_to()) {
ea_t FromAddr = xrefs.GetFrom();
if (FromAddr != 0) {
if (!xrefs.GetIscode()) { // found data xref
IsIndirectCallTarget = true; // addr of func appears in data; assume indirect calls to func
}
else { // found code xref; see if it is a jump used as a tail call
// These tail calls could be a problem for fast returns if they go from unsafe to safe functions.
insn_t TempCmd;
ulong TempFeatures;
bool CmdOK = SMPGetCmd(FromAddr, TempCmd, TempFeatures);
if (!CmdOK) {
// Better be conservative and assume it could be a tail call.
IsTailCallTarget = true;
SMP_msg("ERROR: Could not decode instruction at %x from within MarkFunctionSafe(); assuming tail call\n", FromAddr);
}
else if (TempCmd.itype != MD_CALL_INSTRUCTION) { // not a call instruction; must be jump of some sort
IsTailCallTarget = true;
}
}
}
}
this->PossibleIndirectCallTarget = IsIndirectCallTarget;
this->PossibleTailCallTarget = IsTailCallTarget;
#endif
list<SMPInstr *>::iterator Instructions = Instrs.begin();
SMPInstr *CurrInst;
#if SMP_USE_SSA_FNOP_MARKER
++Instructions; // skip marker instruction
#endif
// While processing the stack pointer writes, the prologue code for
clc5q
committed
// saving the frame register and allocating local variables needs to be
// handled.
bool SaveEBP = false;
bool XferESPtoEBP = false;
for ( ; Instructions != Instrs.end(); ++Instructions) {
CurrInst = (*Instructions);
clc5q
committed
SMP_msg(" Total number of defs for this instruction %d\n", CurrInst->NumDefs());
if (CurrInst->IsBranchToFarChunk()) {
HasBranchToFarChunk = true;
}
if (!SaveEBP) { // still looking for "push ebp"
if (CurrInst->MDIsPushInstr() && CurrInst->GetCmd().Operands[0].is_reg(R_bp)) {
SaveEBP = true;
continue;
}
}
else if (!XferESPtoEBP) { // found "push ebp", looking for "mov ebp,esp"
insn_t CurrCmd = CurrInst->GetCmd();
if ((CurrCmd.itype == NN_mov)
&& (CurrInst->GetFirstDef()->GetOp().is_reg(R_bp))
&& (CurrInst->GetFirstUse()->GetOp().is_reg(R_sp))) {
XferESPtoEBP = true;
continue;
}
}
ea_t address = CurrInst->GetAddr();
if (address == this->LocalVarsAllocInstr ||
address == this->LocalVarsDeallocInstr)
continue;
if (CurrInst->MDIsStackPointerCopy(this->UseFP)) {
clc5q
committed
HasStackPointerCopy = true;
if (NN_lea == CurrInst->GetCmd().itype) {
// If an lea instruction loads an address above
// the stack frame, we must assume that writes
// above the stack frame could occur.
op_t TempOp = CurrInst->GetLeaMemUseOp();
if (this->WritesAboveLocalFrame(TempOp, CurrInst->AreUsesNormalized()))
WritesAboveLocalFrameIndirect = true;