diff --git a/SMPBasicBlock.cpp b/SMPBasicBlock.cpp index 73ba27d01b0ff5d69186fa493de37fde25f7b4dc..e5b52e3ad9ea48448c255f4be0ed6b3db14a4920 100644 --- a/SMPBasicBlock.cpp +++ b/SMPBasicBlock.cpp @@ -220,6 +220,11 @@ void SMPBasicBlock::Dump(void) { msg("DEF-USE chains for block-local names: \n"); this->LocalDUChains.Dump(); +#if SMP_FULL_LIVENESS_ANALYSIS + msg("DEF-USE chains for block-local use of global names: \n"); + this->GlobalDUChains.Dump(); +#endif + if (this->IndirectJump) msg("Has indirect jump. "); if (this->Returns) @@ -532,6 +537,105 @@ void SMPBasicBlock::SetLocalNames(void) { return; } // end of SMPBasicBlock::SetLocalNames() +#if SMP_FULL_LIVENESS_ANALYSIS +// Create local def-use chains for all global names +// Important to remember that a chain can start without a def because the variable is Live-In +// Variant on SSALocalRenumber +void SMPBasicBlock::CreateGlobalChains() { + bool DebugFlag = (0 == strcmp(".init_proc", this->MyFunc->GetFuncName())); +#if 0 + DebugFlag |= true; +#endif + size_t NumGlobals = this->MyFunc->NumGlobalNames(); + //msg("%d Global Names\n", NumGlobals); + size_t LocalIndex; + vector<int> LocalUseIndex; + // Initialize LocalUseIndex and DUChain values for each local name. + set<op_t, LessOp>::iterator NameIter; + if (NumGlobals < 1) + return; + this->GlobalDUChains.ChainsByName.clear(); + this->GlobalDUChains.ChainsByName.reserve(NumGlobals); + op_t TempOp; + TempOp.type = o_void; + SMPDUChainArray Temp(TempOp); + if (DebugFlag) + msg("Initializing GlobalChainsByName.\n"); + this->GlobalDUChains.ChainsByName.assign(NumGlobals, Temp); + for (NameIter = this->MyFunc->GetFirstGlobalName(); NameIter != this->MyFunc->GetLastGlobalName(); ++NameIter) { + LocalIndex = (size_t) ExtractGlobalIndex(*NameIter); + LocalUseIndex.push_back(-1); // init LocalUse indices to -1; first DEF will make it 0 + // msg("LocalUse Push"); + // Set the local name for each DU chain array. + if (LocalIndex > this->GlobalDUChains.ChainsByName.size()) + msg("LocalIndex %d out of bounds in CreateGlobalChains.\n", LocalIndex); + if (DebugFlag) + msg("Setting name for LocalIndex = %d\n", LocalIndex); + this->GlobalDUChains.ChainsByName.at(LocalIndex).SetName(*NameIter); + } + + // Iterate through all instructions in the block. For each DEF of a global name, + // set a new LocalUse index and start a new DU chain. For each USE of a global name, + // set the current LocalUse index for that name and add the instruction to the DU + // chain. + list<list<SMPInstr>::iterator>::iterator InstIter; + for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) { + // msg("Beginning to look for USE of global names.\n"); + size_t NameIndex; + // USEs get referenced logically before DEFs, so start with them. + set<DefOrUse, LessDefUse>::iterator CurrUse = (*InstIter)->GetFirstUse(); + while (CurrUse != (*InstIter)->GetLastUse()) { + op_t UseOp = CurrUse->GetOp(); + set<op_t, LessOp>::iterator UseNameIter = this->MyFunc->FindGlobalName(UseOp); + if (UseNameIter != this->MyFunc->GetLastGlobalName()) { + // Found USE of a global name + NameIndex = ExtractGlobalIndex(*UseNameIter); + if (NameIndex > LocalUseIndex.size()) + msg("NameIndex %d out of range in CreateGlobalChains.\n", NameIndex); + int LocalUseNum = LocalUseIndex.at(NameIndex); + if(LocalUseNum == -1) { // LiveIn, use before def + LocalUseIndex.at(NameIndex)++; + LocalUseNum++; + SMPDefUseChain TempDefChain(UseOp, (*InstIter)->GetAddr()); + this->GlobalDUChains.ChainsByName.at(NameIndex).DUChains.push_back(TempDefChain); + } + else { + // Push address of USE instruction onto the DEF-USE chain for this LocalUseNum. + this->GlobalDUChains.ChainsByName.at(NameIndex).DUChains.at(LocalUseNum).PushUse((*InstIter)->GetAddr()); + } + } + ++CurrUse; + } // end for all USEs in the instruction. + // Now do the DEFs. + set<DefOrUse, LessDefUse>::iterator CurrDef = (*InstIter)->GetFirstDef(); + while (CurrDef != (*InstIter)->GetLastDef()) { + size_t NameIndex; + op_t DefOp = CurrDef->GetOp(); + set<op_t, LessOp>::iterator DefNameIter = this->MyFunc->FindGlobalName(DefOp); + if (DefNameIter != this->MyFunc->GetLastGlobalName()) { + // Found DEF of a global name. + NameIndex = ExtractGlobalIndex(*DefNameIter); + if (NameIndex > LocalUseIndex.size()) + msg("DEF NameIndex %d out of range in CreateGlobalChains.\n", NameIndex); + ++LocalUseIndex[NameIndex]; // move up to next LocalUse subscript number + int LocalUseNum = LocalUseIndex.at(NameIndex); + // Before the push_back() call, we should have # chains equal to new LocalUseNum + //assert(LocalUseNum == this->GlobalDUChains.ChainsByName.at(NameIndex).DUChains.size()); + // Set up a new DU chain and push it onto the vector of DU chains for this + // local name. Push the DEF onto the list (it will be the first reference + // on the list, because the list was newly created). + SMPDefUseChain TempDefChain(DefOp, (*InstIter)->GetAddr()); + this->GlobalDUChains.ChainsByName.at(NameIndex).DUChains.push_back(TempDefChain); + } + ++CurrDef; + } // end for all DEFs in the instruction + } // end for all instructions in the block + if (DebugFlag) + msg("Exiting CreateGlobalChains()\n"); + return; +} // end of SMPBasicBlock::CreateGlobalChains() +#endif + // Create local DEF-USE chains and renumber all references to all names in LocalNames. void SMPBasicBlock::SSALocalRenumber(void) { bool DebugFlag = (0 == strcmp(".init_proc", this->MyFunc->GetFuncName())); @@ -1001,6 +1105,100 @@ set<SMPPhiFunction, LessPhi>::iterator SMPBasicBlock::InferPhiDefType(set<SMPPhi return ReturnPhi; } // end of SMPBasicBlock::InferPhiDefType() +#if SMP_FULL_LIVENESS_ANALYSIS +// Extension of IsRegDead for Global names. Check and see if it overlaps with a DEF-USE chain +bool SMPBasicBlock::IsGlobalRegDead(ea_t InstAddr, op_t Operand, unsigned int RegIndex) const { + bool FoundInLiveInSet = (LiveInSet.end() != LiveInSet.find(Operand)); + bool FoundInLiveOutSet = (LiveOutSet.end() != LiveOutSet.find(Operand)); + bool FoundInUpExposedSet = (UpExposedSet.end() != UpExposedSet.find(Operand)); + bool FoundInKillSet = (KillSet.end() != KillSet.find(Operand)); + bool HasLocalChains = (0 < this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.size()); + bool DebugFlag = (0x8048347 == InstAddr); + + if (DebugFlag) { + msg("IsGlobalRegDead for %x : ", InstAddr); + PrintOperand(Operand); + msg("\nLiveIn: %d LiveOut: %d UpExposed: %d VarKilled: %d\n", FoundInLiveInSet, + FoundInLiveOutSet, FoundInUpExposedSet, FoundInKillSet); + } + + size_t LocalUseIndex; + size_t LocalUseMax = this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.size() - 1; + if (DebugFlag) msg("A"); + + // If there are no local chains for this global name, then it is either the pass-through + // case (LiveIn, LiveOut, !UpExposed, !VarKilled) or it must be dead. + if (!HasLocalChains) + return (!FoundInLiveInSet); + + if (DebugFlag) msg("A1"); + + // If it is Live-In and Live-Out and not in the kill set, + // it is live the whole time + if (FoundInLiveInSet && FoundInLiveOutSet && !FoundInKillSet) + return false; + + if (DebugFlag) msg("B"); + // If it is not Live-In and not in the Kill set it is dead the whole time + if (!FoundInLiveInSet && !FoundInKillSet) + return true; + + if (DebugFlag) msg("C"); + // If it is not in the UpExposed set and is in the Kill set, it is dead + // before the first def + if (!FoundInUpExposedSet && FoundInKillSet) { + ea_t StartAddr = this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.at(0).GetDef(); + if ((BADADDR != StartAddr) && (InstAddr <= StartAddr)) + return true; + } + + if (DebugFlag) msg("D"); + // If it is in the UpExposedSet, it is live until the last use of the first chain + if (FoundInUpExposedSet) { + ea_t LastAddr = this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.at(0).GetLastUse(); + if ((BADADDR != LastAddr) && (InstAddr <= LastAddr)) + return false; + } + + if (DebugFlag) msg("E"); + // If it is not Live-Out, then it is dead after the last use + if (!FoundInLiveOutSet) { + ea_t LastAddr = this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.at(LocalUseMax).GetLastUse(); + if ((BADADDR != LastAddr) && (InstAddr > LastAddr)) + return true; + } + + if (DebugFlag) msg("F"); + //If it is LiveOut and it is in the Kill Set, it will be live after the last definition + if (FoundInLiveOutSet && FoundInKillSet) { + ea_t LastAddr = this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.at(LocalUseMax).GetDef(); + if ((BADADDR != LastAddr) && (LastAddr <= InstAddr)) // **!!** <= or < ? + return false; + } + + if (DebugFlag) msg("G"); + // See if any DEF-USE chains overlap InstAddr's USEs. + for (LocalUseIndex = 0; LocalUseIndex <= LocalUseMax; ++LocalUseIndex) { + // Need to check here to not break if this block does not have a def for this (LiveIn) + // Skip this check if it is UpExposed and this is the first chain + if (!FoundInUpExposedSet || LocalUseIndex > 0) { + ea_t StartAddr = this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.at(LocalUseIndex).GetDef(); + if (StartAddr >= InstAddr) + continue; // cannot overlap USE if DEF is after InstAddr + } + ea_t LastAddr = this->GlobalDUChains.ChainsByName.at(RegIndex).DUChains.at(LocalUseIndex).GetLastUse(); + if (DebugFlag) msg(" LastAddr: %x\n", LastAddr); + if ((BADADDR != LastAddr) && (LastAddr >= InstAddr)) { + if (DebugFlag) msg("Ga"); + return false; + } + } + + if (DebugFlag) msg("H"); + return true; // no DEF-USE chains overlapped the instrumentation point +} // end of SMPBasicBlock::IsGlobalRegDead() +#endif + // If no DEF-USE chains overlap the instrumentation point for InstAddr (which logically // falls between the USEs of the instruction at InstAddr and its DEFs), for register RegIndex, // then it is safe for the instrumentation to use that register without saving and @@ -1008,12 +1206,13 @@ set<SMPPhiFunction, LessPhi>::iterator SMPBasicBlock::InferPhiDefType(set<SMPPhi bool SMPBasicBlock::IsRegDead(ea_t InstAddr, unsigned int RegIndex) const { size_t SSAIndex; // See if any DEF-USE chains overlap InstAddr's USEs. + assert(RegIndex < this->LocalDUChains.ChainsByName.size()); for (SSAIndex = 0; SSAIndex < this->LocalDUChains.ChainsByName.at(RegIndex).DUChains.size(); ++SSAIndex) { ea_t StartAddr = this->LocalDUChains.ChainsByName.at(RegIndex).DUChains.at(SSAIndex).GetDef(); if (StartAddr >= InstAddr) continue; // cannot overlap USE if DEF is after InstAddr ea_t LastAddr = this->LocalDUChains.ChainsByName.at(RegIndex).DUChains.at(SSAIndex).GetLastUse(); - if (LastAddr >= InstAddr) + if ((BADADDR != LastAddr) && (LastAddr >= InstAddr)) return false; } return true; // no DEF-USE chains overlapped the instrumentation point @@ -1040,6 +1239,7 @@ void SMPBasicBlock::MarkDeadRegs(void) { DebugFlag |= true; #endif set<op_t, LessOp>::iterator NameIter; + set<op_t, LessOp>::iterator FlagNameIter; list<list<SMPInstr>::iterator>::iterator InstIter; op_t FlagsOp; FlagsOp.type = o_reg; @@ -1050,19 +1250,44 @@ void SMPBasicBlock::MarkDeadRegs(void) { this->FlagsDeadAfterLastUse = (this->LiveOutSet.find(FlagsOp) == this->LiveOutSet.end()); this->FlagsDeadBeforeFirstKill = ((this->UpExposedSet.find(FlagsOp) == this->UpExposedSet.end()) && (this->KillSet.find(FlagsOp) != this->KillSet.end())); + FlagNameIter = this->MyFunc->FindGlobalName(FlagsOp); + } + else { + FlagNameIter = this->LocalNames.find(FlagsOp); } for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) { DeadString[0] = '\0'; // First, put EFLAGS at beginning of string if it is dead. - NameIter = this->LocalNames.find(FlagsOp); - if (NameIter != this->LocalNames.end()) { - // EFLAGS is in the LocalNames - unsigned int RegIndex = ExtractGlobalIndex(*NameIter); - if (this->IsRegDead((*InstIter)->GetAddr(), RegIndex)) { + if (!GlobalFlags) { + if (FlagNameIter != this->LocalNames.end()) { + // EFLAGS is in the LocalNames + unsigned int RegIndex = ExtractGlobalIndex(*FlagNameIter); + if (this->IsRegDead((*InstIter)->GetAddr(), RegIndex)) { + qstrncat(DeadString, " EFLAGS", sizeof(DeadString) - 1); + } + } + else { // EFLAGS are not locally used, but not global either; they are dead here qstrncat(DeadString, " EFLAGS", sizeof(DeadString) - 1); } } - else if (GlobalFlags) { + else { +#if SMP_FULL_LIVENESS_ANALYSIS + assert(FlagNameIter != this->MyFunc->GetLastGlobalName()); + unsigned int RegIndex = ExtractGlobalIndex(*FlagNameIter); + bool newCatch, oldCatch; + newCatch = this->IsGlobalRegDead((*InstIter)->GetAddr(), FlagsOp, RegIndex); + oldCatch = this->AreGlobalFlagsDead((*InstIter)->GetAddr(), FlagsOp); + if (newCatch || oldCatch) + qstrncat(DeadString, " EFLAGS", sizeof(DeadString) - 1); + if (newCatch && !oldCatch) + msg("We caught a new Flags!\n"); + if (!newCatch && oldCatch) + msg("How did that slip by?\n"); +#if 0 + if (newCatch && oldCatch) + msg("Not a new success.\n"); +#endif +#else if (this->AreGlobalFlagsDead((*InstIter)->GetAddr(), FlagsOp)) { qstrncat(DeadString, " EFLAGS", sizeof(DeadString) - 1); } @@ -1072,9 +1297,7 @@ void SMPBasicBlock::MarkDeadRegs(void) { msg("Global EFLAGS in %s\n", this->MyFunc->GetFuncName()); #endif } - } - else { // EFLAGS are not locally used, but not global either; they are dead here - qstrncat(DeadString, " EFLAGS", sizeof(DeadString) - 1); +#endif // end if SMP_FULL_LIVENESS_ANALYSIS ... else ... } // Now, process all other local regs and skip EFLAGS. @@ -1100,6 +1323,49 @@ void SMPBasicBlock::MarkDeadRegs(void) { qstrncat(DeadString, RegNames[RegNum], sizeof(DeadString) - 1); } } // end for all local names + +#if SMP_FULL_LIVENESS_ANALYSIS + // Now, process all other global regs and skip EFLAGS. + //msg(" Done. Analyzing global regs..."); + size_t NumGlobals = this->MyFunc->NumGlobalNames(); + if (NumGlobals > 0) { + for (NameIter = this->MyFunc->GetFirstGlobalName(); NameIter != this->MyFunc->GetLastGlobalName(); ++NameIter) { + op_t RegOp; + RegOp.type = o_reg; + //msg(" i "); + + //msg("%d", NameIter->type); + if (NameIter->type != o_reg) + continue; + //msg(" j "); + // We never want to consider ESP to be available for instrumentation. + if (NameIter->is_reg(R_sp)) + continue; + //msg(" k "); + // Until we analyze interprocedural register use, it is safest to not + // use EBP for instrumentation. This could change with more analysis. + if (NameIter->is_reg(R_bp)) + continue; + + //msg(" l "); + unsigned int RegIndex = ExtractGlobalIndex(*NameIter); + int RegNum = NameIter->reg; + if (RegNum == X86_FLAGS_REG) { + // We moved EFLAGS to the beginning, per annotations spec + continue; + } + //msg(" m "); + RegOp.reg = NameIter->reg; + //msg("%i", RegOp.reg); + if (this->IsGlobalRegDead((*InstIter)->GetAddr(), RegOp, RegIndex)) { + qstrncat(DeadString, " ", sizeof(DeadString) - 1); + qstrncat(DeadString, RegNames[RegNum], sizeof(DeadString) - 1); + } + } // end for all global names + } +#endif + //msg("Done. Next instruction.\n"); + if (strlen(DeadString) > 1) { (*InstIter)->SetDeadRegs(DeadString); } diff --git a/SMPBasicBlock.h b/SMPBasicBlock.h index 4e0da4cca72f2cf9bc3e46c9485954ce141ed126..b711e15c63127cfd0989e4ed8824a1e44ee1ba37 100644 --- a/SMPBasicBlock.h +++ b/SMPBasicBlock.h @@ -19,6 +19,9 @@ using namespace std; +// Do Full Liveness Analysis? Experimental by KBinswanger +#define SMP_FULL_LIVENESS_ANALYSIS 1 + // Value for a block number before it is initialized. #define SMP_BLOCKNUM_UNINIT (-1) @@ -107,6 +110,10 @@ public: void AddToDomFrontier(int); // Add RPO block number to DomFrontier set. void SetLocalNames(void); // Fille the LocalNames member set void SSALocalRenumber(void); // Renumber references to local names +#if SMP_FULL_LIVENESS_ANALYSIS + void CreateGlobalChains(void); // Create DEF-USE chains for global names used here + bool IsGlobalRegDead(ea_t InstAddr, op_t Operand, unsigned int RegIndex) const; // Is global reg dead at InstAddr? +#endif bool IsRegDead(ea_t InstAddr, unsigned int RegIndex) const; // Is local reg dead at InstAddr? void MarkDeadRegs(void); // Find dead registers for each mmStrata-instrumented instruction bool PropagateLocalDefType(op_t DefOp, SMPOperandType DefType, ea_t DefAddr); // to all uses @@ -132,6 +139,9 @@ private: set<SMPPhiFunction, LessPhi> PhiFunctions; // SSA incoming edge phi functions set<op_t, LessOp> LocalNames; // non-global names referenced in this block SMPCompleteDUChains LocalDUChains; // def-use chains for local names +#if SMP_FULL_LIVENESS_ANALYSIS + SMPCompleteDUChains GlobalDUChains; // def-use chains for global names +#endif // cached query results bool IndirectJump; // contains an indirect jump instruction bool Returns; // contains a return instruction diff --git a/SMPDataFlowAnalysis.h b/SMPDataFlowAnalysis.h index 490fa3b6969b758d513b22bf317726b6ce020199..ce0609878842bf428ac30f448707c1cc4242a0f7 100644 --- a/SMPDataFlowAnalysis.h +++ b/SMPDataFlowAnalysis.h @@ -271,7 +271,12 @@ public: inline op_t GetName(void) const { return SSAName; }; inline ea_t GetDef(void) const { return RefInstrs.at(0); }; inline ea_t GetUse(size_t index) const { return RefInstrs.at(index + 1); }; - inline ea_t GetLastUse(void) const { return RefInstrs.back(); }; + inline ea_t GetLastUse(void) const { + if (RefInstrs.size() > 1) + return RefInstrs.back(); + else + return BADADDR; + }; // Set methods void SetName(op_t Name); void SetDef(ea_t Def); diff --git a/SMPFunction.cpp b/SMPFunction.cpp index fc76b5c989a28c1d5dd064d70bf4790da6f3a5ac..19a5028023a4d560f884d6bf7f5ed5ff14df42ab 100644 --- a/SMPFunction.cpp +++ b/SMPFunction.cpp @@ -76,6 +76,7 @@ SMPFunction::SMPFunction(func_t *Info) { this->CallsAlloca = false; this->BuiltRTLs = false; this->OutgoingArgsSize = 0; + this->BlockCount = 0; this->LocalVarTable.clear(); this->StackFrameMap.clear(); this->DirectCallTargets.clear(); @@ -1309,13 +1310,16 @@ void SMPFunction::Analyze(void) { // Compute SSA form data structures across the function. void SMPFunction::ComputeSSA(void) { + bool DumpFlag = false; #if SMP_DEBUG_DATAFLOW - bool DumpFlag = (0 == strcmp("main", this->GetFuncName())); - DumpFlag |= (0 == strcmp("dohanoi", this->GetFuncName())); + DumpFlag |= (0 == strcmp("main", this->GetFuncName())); + DumpFlag |= (0 == strcmp("call_gmon_start", this->GetFuncName())); DumpFlag |= (0 == strcmp("_init_proc", this->GetFuncName())); #endif + bool DebugFlag = (0 == strcmp("call_gmon_start", this->GetFuncName())); -#if 0 +#if 1 + DumpFlag |= (0 == strcmp("_nl_find_msg", this->GetFuncName())); if (DumpFlag) this->Dump(); #endif @@ -1331,6 +1335,11 @@ void SMPFunction::ComputeSSA(void) { for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) { CurrBlock->SetLocalNames(); CurrBlock->SSALocalRenumber(); + if (DebugFlag) CurrBlock->Dump(); + +#if SMP_FULL_LIVENESS_ANALYSIS + CurrBlock->CreateGlobalChains(); +#endif #if 1 CurrBlock->MarkDeadRegs(); #endif diff --git a/SMPFunction.h b/SMPFunction.h index 0e784ac070856034ae0f27682688b39ce865a5a6..ca4eefed0ae4adcd238cc7f2779489c5794129a5 100644 --- a/SMPFunction.h +++ b/SMPFunction.h @@ -51,6 +51,10 @@ public: inline const char *GetFuncName(void) const { return FuncName; }; inline long GetTypedDefs(void) const { return TypedDefs; }; inline long GetUntypedDefs(void) const { return UntypedDefs; }; + inline set<op_t, LessOp>::iterator GetFirstGlobalName(void) { return GlobalNames.begin(); }; + inline set<op_t, LessOp>::iterator GetLastGlobalName(void) { return GlobalNames.end(); }; + inline size_t NumGlobalNames(void) { return GlobalNames.size(); }; + inline set<op_t, LessOp>::iterator FindGlobalName(op_t SearchOp) { return GlobalNames.find(SearchOp); }; // Set methods // Query methods inline bool HasIndirectCalls(void) const { return IndirectCalls; };