Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • opensrc/SMPStaticAnalyzer
1 result
Show changes
Commits on Source (26)
Showing
with 3789 additions and 403 deletions
......@@ -360,6 +360,8 @@ public:
inline bool IsSelfLoop(void) const { return (IsLoopHeaderBlock() && IsLoopTailBlock() && (GetCondNonFallThroughSuccBlockNum() == GetNumber())); };
inline bool IsReadyToTranslate(void) const { return (GetSPARKTranslationCount() < GetSPARKTranslationLimit()); };
bool IsBlockPred(int BlockNum) const; // Is BlockNum a predecessor block of this block
bool IsShortCircuitHead(void) const;
bool IsShortCircuitNonHead(void) const;
bool HasLoopHeadAsSuccessor(int &HeadBlockNum) const; // block has HeadBlockNum as successor, which is a loop header
bool HasLoopHeadWithInvertedExitAsSuccessor(void) const; // block has loop head successor that ends with INVERTED_LOOP_EXIT
bool HasInvertedLoopBack(void) const; // COND_BRANCH falls through to loop header of innermost loop containing this block
......@@ -387,6 +389,7 @@ public:
bool IsAddrInBlock(const STARS_ea_t InstAddr) const;
bool IsAnyStackOpKilled(void) const; // does VarKill set have any stack operands?
bool HasConditionalBranch(void) const; // true if (last) instruction is conditional branch
bool HasBranchToOtherFunc(void) const; // Last inst is conditional branch outside current function
bool HasMemoryWrite(void) const; // Writes to stack or has indirect write
bool IsInArgPointerCopy(const STARSOpndTypePtr &CurrOp, int SSANum) const; // found in local InArgPointerCopies?
bool IsOpDestTruncatedWrite(const STARSOpndTypePtr &DefOp, int DefSSANum, STARS_ea_t DefAddr); // Does DefOp get written out in truncated form (lower bits only)?
......@@ -780,10 +783,12 @@ public:
inline bool IsSelfLoop(void) const { return GetOriginalBlock()->IsSelfLoop(); };
inline bool IsUnreachableBlock(void) const { return GetOriginalBlock()->IsUnreachableBlock(); };
inline bool IsReadyToTranslate(void) const { return GetOriginalBlock()->IsReadyToTranslate(); };
inline bool HasBranchToOtherFunc(void) const { return GetOriginalBlock()->HasBranchToOtherFunc(); };
bool IsBlockNumPred(const int BlockNum) const; // Is BlockNum a predecessor block of this block
bool IsBlockPred(const STARSTransCFGBlock *TCFGBlock) const; // Is TCFGBlock a predecessor block of this block
bool IsBlockSucc(const STARSTransCFGBlock *TCFGBlock) const; // Is TCFGBlock a successor block of this block
bool IsBlockInLoop(std::size_t LoopNum) const;
inline bool IsBlockInDomFrontier(const int TCFGBlockNum) const { return (this->DomFrontier.find(TCFGBlockNum) != this->DomFrontier.cend()); };
// Auditing methods.
bool HasPred(const STARSTransCFGBlock *TestPred) const;
......@@ -796,6 +801,9 @@ public:
int FindParentCondBranchTCFGBlockNum(void); // Search upward for block ending in a COND_BRANCH
int FindChildLoopHeaderTCFGBlockNum(void); // Search downward for first loop header block that current TCFG block dominates
// NOTE: Call SMPFunction::ResetTCFGVisitedBlocks() before calling STARSTransCFGBlock::isBlockReachableWithoutBackEdges().
bool IsBlockReachableWithoutBackEdges(const int DestTCFGBlockNum, bool &HitDeadEnd) const; // path without back edges?
private:
SMPFunction *MyFunc;
int TCFGBlockNum; // new block number; might be cloned, or might match OriginalBockNum.
......
......@@ -576,16 +576,17 @@ public:
bool IsLoopInductionVarForAnySSANum(std::size_t LoopIndex, const STARSOpndTypePtr &CurrOp, STARSInductionVarFamilyIter &ListIter, std::size_t &FamilyIndex); // Relax the requirement to match SSA number to IV
bool IsLoopNestInductionVar(const STARSOpndTypePtr &CurrOp, SMPInstr *UseInst, STARSInductionVarFamilyIter &ListIter, std::size_t &FamilyIndex, int &LoopIndex); // For CurrOp in loop nest including UseInst, return iterator and position in family if true
inline bool AltersSPARKMemory(void) const { return AltersMemory; };
inline bool HasCloningOccurred(void) const { return (TCFGBlocks.size() > RPOBlocks.size()); };
inline bool HasSPARKUnstructuredMsgBeenPrinted(void) const { return PrintedSPARKUnstructuredMsg; };
inline bool UsesInArgsForLoopMemWrites(void) const { return HasLoopInArgMemWrites; };
inline bool CalleeUsesInArgsForLoopMemWrites(void) const { return CalleeHasLoopInArgMemWrites; };
inline bool IsCriticalInArg(std::size_t ArgPos) const { return (0 != (TaintInArgPosBits & (1 << ArgPos))); };
inline bool DoesLoopHaveArgs(int LoopNum) const { return LoopMemRangeInArgRegsBitmap[(size_t) LoopNum].any(); };
bool DoesLoopHaveMultipleExitTargets(const size_t LoopNum) const;
bool DoesLoopHaveMultipleExitTargets(const std::size_t LoopNum) const;
inline bool IsNonExitingLoopBackBranch(const STARS_ea_t BranchAddr) const { return LoopBackNonExitingBranches.find(BranchAddr) != LoopBackNonExitingBranches.cend(); };
// Printing methods
void Dump(const bool SkeletonDump = false); // debug dump
void Dump(const bool SkeletonDump); // debug dump
void DumpDotCFG(void); // Dump CFG representation for processing by "dot" program.
inline void DumpFuncNameAndAddr(void) const { SMP_msg("in %s at %llx\n", this->GetFuncName(), (uint64_t) this->GetFirstFuncAddr()); };
......@@ -1056,7 +1057,7 @@ private:
bool DoesBlockExitLoop(std::size_t LoopNumber, SMPBasicBlock *LoopBlock, int &FollowBlockNum); // return true if block can exit the loop.
bool DetectMultiLevelLoopBreak(const int LoopBlockNum, const int ExitTargetBlockNum) const; // Is ExitTargetBlockNum more than 1 loop nesting level away from LoopBlockNum?
void ComputeLoopFollowNodesReachability(const std::size_t LoopNum); // populate entry in LoopExitTargetsReachabilitySets
void MarkReachableBlocks(const int BlockNum, const int LoopNum, const int HeadBlockNum, const bool TestDominance, const int LimitBlockNum, STARSBitSet &ReachableSet); // Set bits of current BlockNum and its descendants in CFG (that are dominated by HeadBlockNum, if TestDominance)
void MarkReachableBlocks(const int BlockNum, const int LoopNum, const int HeadBlockNum, const bool TestDominance, const int LimitBlockNum, STARSBitSet &ReachableSet, const int StopBlockNum = SMP_BLOCKNUM_UNINIT); // Set bits of current BlockNum and its descendants in CFG (that are dominated by HeadBlockNum, if TestDominance)
uint32_t GetReachableSourcesCount(const std::size_t TCFGBlockNum, const std::size_t LoopNum) const; // How many of the multiple exit targets from LoopNum reach BlockNum?
bool CanBlockBypassBlock(const int BlockNum, const int SentinelBlockNum, const int LimitBlockNum, const STARSBitSet &SentinelReachableBlocks) const; // Downward path from BlockNum to Sentinel-reachable-block without hitting SentinelBlockNum?
void DetectLoopInvariantDEFs(void); // Collect a set of loop-invariant DEFs with the inst IDs of the DEFs.
......@@ -1110,6 +1111,7 @@ private:
int FindConditionalFollowNode4(const int HeadBlockNum, bool &IfThenCase, bool &OddIfThenCase, bool &IfThenElseCase, bool &ShortCircuit); // Find candidate block # for if-else follow node for HeadBlockNum; return -1 otherwise
bool SolveConditionalDomFrontierProblemViaCloning(const int HeadBlockNum, const int FTBlockNum, const int NFTBlockNum, const int FTDomFrontierBlockNum, const int NFTDomFrontierBlockNum, int &FollowBlockNum); // return true if cloning blocks would make DomFrontiers converge
bool IsCloningSafe(const int StartTCFGBlockNum, const int LimitTCFGBlockNum, std::set<int> &BlockNumsToClone) const; // Is it safe to clone path from StartBlockNum, stopping when LimitBlockNum is reached?
bool IsDoubleCloningSafe(const int StartTCFGBlockNum1, const int StartTCFGBlockNum2); // Is it safe to double clone paths from StartBlockNum1 & 2, without either path running into the other start block?
void MarkBlocksAndClone(const int StartingBlockNum, const int UnlinkBlockNum, const int LimitBlockNum, const int InnermostLoopNum, bool FirstIter); // Clone blocks on path from StartingBlockNum to <LimitBlockNum within InnermostLoopNum; unlink cloned StartingBlockNum from pred UnlinkBlockNum
bool UpdateAfterCloning(void); // Update data structures, set pred & succ links, etc. after cloning
void UpdateCFGExprBlockNums(STARSCondExpr *CurrExpr); // Update left, right, FT and NFT block nums in CurrExpr; recurse into subexprs.
......@@ -1141,7 +1143,7 @@ private:
void EmitSPARKLoopProcGlobals(FILE *BodyFile, FILE *HeaderFile, bool MemoryInput, bool MemoryOutput, const std::bitset<1 + MD_LAST_REG_NO> &InputRegs, const std::bitset<1 + MD_LAST_REG_NO> &OutputRegs, const std::bitset<1 + MD_LAST_REG_NO> &CalleePreservedRegs); // emit Input, Output, In_Out flow annotations
void EmitSPARKAdaForBlock(int CurrTCFGBlockNum, const int DomTCFGBlockNum, const int FollowTCFGBlockNum, FILE *SPARKBodyFile, const bool ReadytoEmitSwitchDefault, const bool LoopToProc, const uint32_t ReachableSourcesCount = 0); // recursive descent translation to SPARK Ada starting with CurrBlock, stop before Follow Block
void EmitSPARKAdaForLoop(int HeaderTCFGBlockNum, int FollowTCFGBlockNum, FILE *SPARKBodyFile); // recursive descent translation of loop to SPARK Ada starting with header CurrBlock, stop before Follow Block
void EmitSPARKAdaForMultipleLoopExitTargets(FILE *SPARKBodyFile, std::size_t LoopNum); // translate multiple exit targets & their reachable region
void EmitSPARKAdaForMultipleLoopExitTargets(FILE *SPARKBodyFile, const std::size_t LoopNum, const int HeaderTCFGBlockNum); // translate multiple exit targets & their reachable region
void EmitSPARKAdaForSwitch(int HeaderTCFGBlockNum, int FollowTCFGBlockNum, FILE *SPARKBodyFile); // recursive descent translation of switch statement starting with INDIR_JUMP block, stop before Follow Block
void EmitSPARKAdaForConditional(int HeaderTCFGBlockNum, int FollowTCFGBlockNum, FILE *SPARKBodyFile); // recursive descent translation of if-else statement starting with COND_BRANCH block, stop before Follow Block
bool EmitSPARKAdaLoopCall(STARS_ea_t LoopAddr, std::size_t LoopIndex, FILE *SPARKBodyFile); // emit call to loop proc that will be created later starting at LoopAddr
......
......@@ -87,6 +87,7 @@
// By using STARS_BADADDR, which matches the IDA Pro BADADDR constant, we can automatically adjust for 32/64-bit systems.
#define STARS_SSA_MARKER_PSEUDO_ID ((STARS_ea_t) STARS_BADADDR - 1)
#define STARS_LIVEIN_PSEUDO_ID ((STARS_ea_t) STARS_BADADDR - 2)
#define STARS_EXTERNAL_FUNC_ADDR STARS_LIVEIN_PSEUDO_ID
// All actual instructions should be on addresses below STARS_PSEUDO_ID_MIN
// Between STARS_PSEUDO_ID_MIN and STARS_PSEUDO_BLOCKNUM_MAX can be basic block numbers as fake addresses
#define STARS_BLOCKNUM_MASK 0xffff
......@@ -95,6 +96,7 @@
#define STARS_IsNotPseudoInstID(addr) (STARS_PSEUDO_ID_MIN > addr)
#define STARS_IsLiveInPseudoID(addr) (STARS_LIVEIN_PSEUDO_ID == ((STARS_ea_t) addr))
#define STARS_IsExternalFunc(addr) (STARS_EXTERNAL_FUNC_ADDR == ((STARS_ea_t) addr))
#define STARS_IsSSAMarkerPseudoID(addr) (STARS_SSA_MARKER_PSEUDO_ID == ((STARS_ea_t) addr))
#define STARS_IsBlockNumPseudoID(addr) ((STARS_PSEUDO_ID_MIN <= ((STARS_ea_t) addr)) && (STARS_PSEUDO_BLOCKNUM_MAX >= ((STARS_ea_t) addr)))
#define STARS_GetBlockNumFromPseudoID(addr) (((STARS_ea_t) addr) & STARS_BLOCKNUM_MASK)
......
......@@ -150,10 +150,18 @@ struct SwitchTableInfo { // info about a switch table
#define STARS_dt_bitfild 12 // bit field (mc680x0)
#define STARS_dt_string 13 // pointer to asciiz string
#define STARS_dt_unicode 14 // pointer to unicode string
#if (IDA_SDK_VERSION < 700)
#define STARS_dt_3byte 15 // 3-byte data
#define STARS_dt_ldbl 16 // long double (which may be different from tbyte)
#define STARS_dt_byte32 17 // 256 bit
#define STARS_dt_byte64 18 // 512 bit
#else
#define STARS_dt_ldbl 15 // long double (which may be different from tbyte)
#define STARS_dt_byte32 16 // 256 bit
#define STARS_dt_byte64 17 // 512 bit
#define STARS_dt_half 18 // 2-byte floating point
#endif
// Part of our solution to the dense encoding of x86-64 is to record some instruction
// prefix and auxprefix info in each operand, so we can continue to do data flow analysis
......@@ -162,7 +170,7 @@ struct SwitchTableInfo { // info about a switch table
// while analyzing an inst, and is too big to pass around with all operands in Phi DEFs,
// LiveIn and LiveOut sets, SSA numbering and operand comparisons, etc. So, we record
// the insnpref byte (a.k.a. cmd.rex) into each operand in the specflag4 field, then we
// record the following two bits of info into unused bits in specflag4.
// record the following two bits of info (VEXPR and VSIB) into unused bits in specflag4.
// These first five constants imitate IDA Pro header <intel.hpp> constants.
const int STARS_REX_W = 8; // 64-bit operand size
const int STARS_REX_R = 4; // modrm reg field extension
......@@ -408,7 +416,7 @@ enum STARS_RegNo
STARS_x86_R_k6 = 171,
STARS_x86_R_k7 = 172,
STARS_x86_R_last,
STARS_x86_R_last, // 173
};
typedef STARS_RegNo STARS_regnum_t;
......@@ -2475,6 +2483,22 @@ enum
STARS_NN_xresldtrk, // Resume Tracking Load Addresses
STARS_NN_xsusldtrk, // Suspend Tracking Load Addresses
// Intel Affine Transformation instructions
STARS_NN_gf2p8mulb, // Galois Field Multiply Bytes
STARS_NN_gf2p8affineqb, // Computes Affine Transformation
STARS_NN_gf2p8affineinvqb, // Computes Inverse Affine Transformation
// VEX versions
STARS_NN_vgf2p8mulb, // Galois Field Multiply Bytes
STARS_NN_vgf2p8affineqb, // Computes Affine Transformation
STARS_NN_vgf2p8affineinvqb, // Computes Inverse Affine Transformation
// Intrinsics for Saving and Restoring the Extended Processor States (64-bits)
STARS_NN_fxsave64, // Fast save FP context (64-bits)
STARS_NN_fxrstor64, // Fast restore FP context (64-bits)
STARS_NN_last,
......
#ifndef STARS_IDA_Function_h
#define STARS_IDA_Function_h
#if __GCC__ >= 8
#if __GNUC__ >= 8
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
......@@ -9,7 +9,7 @@
#include <funcs.hpp>
#include <frame.hpp>
#if __GCC__ >= 8
#if __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif
......
Subproject commit 45a8a215b746ac7b189e4c6ccbab669635abcf67
Subproject commit 5e41e26b88d415f3c7d3eb47f9f0d781cc519459
......@@ -641,7 +641,10 @@ void SMPBasicBlock::EmitSPARKAdaForFallThroughInsts(FILE *BodyFile) {
bool ControlFlowTerminator = ((InstAddr == LastID) && CurrInst->IsBasicBlockTerminator());
bool Untranslatable = CurrInst->IsMarkerInst() || (!CurrInst->IsAnalyzeable());
if (Untranslatable) {
// Set junk instructions to translated.
// Set junk instructions to translated; emit only DisAsm text.
if (CurrInst->IsNop()) {
CurrInst->EmitSPARKAda(BodyFile, true);
}
CurrInst->SetSPARKTranslated(true);
}
else if (!ControlFlowTerminator) {
......@@ -1114,6 +1117,12 @@ list<SMPBasicBlock *>::const_iterator SMPBasicBlock::GetFallThroughSucc(void) co
// instrumentation to trample the flags (but, perhaps that does not matter?)
// We choose to make the block have a fall-through successor that is the
// same as the branch-taken successor.
// The other possibility is a conditional tail call, in which case the target
// of the COND_BRANCH is outside the current function. In that case,
// SMPFunction::SetLinks() will not link to the outside function, and there
// will be only one successor, the fall-through block within this function.
// The code below will never find the branch TargetAddr in that lone successor,
// so it will work correctly.
bool LoneSuccessorCase = (this->GetNumSuccessors() == 1);
bool MergeSuccessors = LoneSuccessorCase;
if (MergeSuccessors) {
......@@ -1123,7 +1132,8 @@ list<SMPBasicBlock *>::const_iterator SMPBasicBlock::GetFallThroughSucc(void) co
MergeSuccessors = (NextAddr == NonFallThroughAddr);
#endif
if (MergeSuccessors) {
SMP_msg("INFO: Fallthrough and branch taken addresses are equal at %llx\n", (uint64_t)LastInst->GetAddr());
SMP_msg("INFO: Fallthrough and branch taken addresses are equal at %llx ", (uint64_t)LastInst->GetAddr());
this->GetFunc()->DumpFuncNameAndAddr();
}
}
for (list<SMPBasicBlock *>::const_iterator SuccIter = this->GetFirstConstSucc(); SuccIter != this->GetLastConstSucc(); ++SuccIter) {
......@@ -1233,7 +1243,34 @@ bool SMPBasicBlock::IsBlockPred(int BlockNum) const {
}
}
return FoundPred;
}
} // end of SMPBasicBlock::IsBlockPred()
// Is the corresponding ShadowCFG block the head of a short circuit expr?
bool SMPBasicBlock::IsShortCircuitHead(void) const {
int BlockNum = this->GetNumber();
bool CloningHasOccurred = this->GetFunc()->HasCloningOccurred();
int NewBlockNum = CloningHasOccurred ? this->GetFunc()->FindAnyTCFGBlockNumMatchingOrigBlockNum(BlockNum) : BlockNum;
STARSCFGBlock *ShadowBlock = this->GetFunc()->GetClonedCFGBlockByNum((size_t)NewBlockNum);
bool ShortCircuitHead = false;
if (nullptr != ShadowBlock) {
ShortCircuitHead = ShadowBlock->IsExprHeadBlock();
}
return ShortCircuitHead;
} // end of SMPBasicBlock::IsShortCircuitHead()
bool SMPBasicBlock::IsShortCircuitNonHead(void) const {
int BlockNum = this->GetNumber();
bool CloningHasOccurred = this->GetFunc()->HasCloningOccurred();
int NewBlockNum = CloningHasOccurred ? this->GetFunc()->FindAnyTCFGBlockNumMatchingOrigBlockNum(BlockNum) : BlockNum;
STARSCFGBlock *ShadowBlock = this->GetFunc()->GetClonedCFGBlockByNum((size_t)NewBlockNum);
bool ShortCircuitNonHead = false;
if (nullptr != ShadowBlock) {
ShortCircuitNonHead = ShadowBlock->IsCoalesced();
}
return ShortCircuitNonHead;
} // end of SMPBasicBlock::IsShortCircuitNonHead()
// Get the enum ControlFlowType for the last inst
ControlFlowType SMPBasicBlock::GetLastInstCFType(void) const {
......@@ -1876,7 +1913,7 @@ STARS_ea_t SMPBasicBlock::GetDefAddrFromUseAddr(const STARSOpndTypePtr &UseOp, S
// Global DEF for this SSANum must be in the Phi functions or within a block.
DefAddr = this->MyFunc->GetGlobalDefAddr(UseOp, SSANum); // only works on registers and stack locations
if (DefAddr == STARS_BADADDR) { // Could not find it anywhere.
this->GetFunc()->Dump();
this->GetFunc()->Dump(false);
SMP_msg("ERROR: Failure in GetDefAddrFromUseAddr(): InstAddr %lx SSANum %d\n",
(unsigned long) InstAddr, SSANum);
SMP_msg(" LocalName: %d UseOp.reg: %d\n", LocalName, UseOp->GetReg());
......@@ -6155,6 +6192,14 @@ bool SMPBasicBlock::HasConditionalBranch(void) const {
return HasCondBranch;
} // end of SMPBasicBlock::HasConditionalBranch()
bool SMPBasicBlock::HasBranchToOtherFunc(void) const {
vector<SMPInstr *>::const_reverse_iterator InstIter = this->InstVec.crbegin();
SMPInstr *LastInst = (*InstIter);
bool HasBranchOutsideFunc = LastInst->IsBranchToOtherFunc();
return HasBranchOutsideFunc;
} // end of SMPBasicBlock::HasBranchToOtherFunc()
// Writes to stack or has indirect write
bool SMPBasicBlock::HasMemoryWrite(void) const {
bool HasMemWrite = this->HasIndirectMemWrite();
......@@ -8159,7 +8204,7 @@ bool SMPBasicBlock::IsNextDownwardUseNotByExternalCallInst(const STARSOpndTypePt
// We want to accept their USE of a register as precise, but not
// the pseudo-USEs by external (linker-resolved) calls.
STARS_ea_t CallTargetAddr = CurrInst->GetCallTarget();
FoundCallUse = (STARS_BADADDR != CallTargetAddr);
FoundCallUse = (STARS_BADADDR != CallTargetAddr) && (!STARS_IsExternalFunc(CallTargetAddr));
if (FoundCallUse) {
SMPFunction *TargetFunc = this->GetFunc()->GetProg()->FindFunction(CallTargetAddr);
FoundCallUse = ((nullptr != TargetFunc) && TargetFunc->IsLinkerStub());
......@@ -8583,7 +8628,13 @@ list<STARSTransCFGBlock *>::const_iterator STARSTransCFGBlock::GetFallThroughSuc
bool MergeSuccessors = LoneSuccessorCase;
if (MergeSuccessors) {
if (MergeSuccessors) {
SMP_msg("INFO: Fallthrough and branch taken addresses are equal at %llx\n", (uint64_t)LastInst->GetAddr());
SMP_msg("INFO: Fallthrough and branch taken addresses are equal at %llx ", (uint64_t)LastInst->GetAddr());
if (nullptr != this->GetFunc()) {
this->GetFunc()->DumpFuncNameAndAddr();
}
else {
SMP_msg("\n");
}
}
}
for (list<STARSTransCFGBlock *>::const_iterator SuccIter = this->GetFirstConstSucc(); SuccIter != this->GetLastConstSucc(); ++SuccIter) {
......@@ -9130,3 +9181,56 @@ int STARSTransCFGBlock::FindChildLoopHeaderHelper(const int BlockNumThatDominate
}
return ChildLoopHeaderBlockNum;
} // end of STARSTransCFGBlock::FindChildLoopHeaderHelper()
// NOTE: Call SMPFunction::ResetTCFGVisitedBlocks() before calling STARSTransCFGBlock::isBlockReachableWithoutBackEdges().
// Mark as processed, recurse into successors depth-first, do not follow back edges.
bool STARSTransCFGBlock::IsBlockReachableWithoutBackEdges(const int DestTCFGBlockNum, bool &HitDeadEnd) const {
bool Found = false;
list<STARSTransCFGBlock *>::const_iterator CurrSucc;
int CurrBlockNum = this->GetNumber();
if (CurrBlockNum == DestTCFGBlockNum) {
Found = true;
return Found;
}
// See if we can get lucky by finding the block in the DomFrontier.
// This search is more breadth-first; combining breadth-first checks
// into the depth-first search can speed up the search in a deep CFG.
for (int DomFrontierBlockNum : this->DomFrontier) {
if (DomFrontierBlockNum == DestTCFGBlockNum) {
Found = true;
break;
}
} // end for all DomFrontier blocks
if (0 == this->GetNumSuccessors()) {
HitDeadEnd = true;
}
else {
for (CurrSucc = this->GetFirstConstSucc(); !Found && (CurrSucc != this->GetLastConstSucc()); ++CurrSucc) {
STARSTransCFGBlock *SuccBlock = (*CurrSucc);
int SuccBlockNum = SuccBlock->GetNumber();
if (SuccBlockNum > CurrBlockNum) { // not back edge
if (SuccBlockNum == DestTCFGBlockNum) {
Found = true;
SuccBlock->SetVisited(true);
}
else if (SuccBlock->IsVisited()) { // already hit this block on our search
break; // return false
}
else if (SuccBlockNum > DestTCFGBlockNum) {
// RPO ordering means we can no longer reach DestBlockNum without a back edge.
SuccBlock->SetVisited(true);
break; // return false
}
else {
SuccBlock->SetVisited(true);
Found = SuccBlock->IsBlockReachableWithoutBackEdges(DestTCFGBlockNum, HitDeadEnd); // recurse, depth-first
}
}
} // end for all successor blocks
}
return Found;
} // end of STARSTransCFGBlock::IsBlockReachableWithoutBackEdges()
......@@ -329,15 +329,22 @@ size_t GetOpDataSize(const STARSOpndTypePtr &DataOp) {
case STARS_dt_fword:
DataSize = 6;
break;
#if (IDA_SDK_VERSION < 700)
case STARS_dt_3byte:
DataSize = 3;
break;
#endif
case STARS_dt_byte32:
DataSize = 32;
break;
case STARS_dt_byte64:
DataSize = 64;
break;
#if (IDA_SDK_VERSION >= 700)
case STARS_dt_half: // 2-byte floating point
DataSize = 16;
break;
#endif
default:
SMP_msg("ERROR: unexpected data type %d in GetOpDataSize() :", OpDtyp);
PrintOperand(DataOp);
......@@ -1397,7 +1404,12 @@ void StringPrintOperand(const STARSOpndTypePtr &Opnd, string &OutStream, bool Us
if (SignedOffset > 0) { // print plus sign
(void) SMP_strncat(OutString, "+", STARS_MAXSTR - 1);
}
#if 0
(void) SMP_snprintf(DummyBuf, STARS_MAXSTR - 1, "%lld", (int64_t) Opnd->GetImmedValue());
#else
(void)SMP_snprintf(DummyBuf, STARS_MAXSTR - 1, "%lld", (int64_t)SignedOffset);
SMP_msg("INFO: StringPrintOperand case reached: MemDisplacement with SIB byte.\n");
#endif
(void) SMP_strncat(OutString, DummyBuf, STARS_MAXSTR - 1);
(void) SMP_strncat(OutString, "]", STARS_MAXSTR - 1);
}
......
......@@ -630,7 +630,7 @@ bool SMPFunction::ComputeInOutRegs(bool InheritPass, bool &WritesMem, bool &Call
size_t NumCallees = this->GetNumCallTargets();
for (size_t CalleeIndex = 0; CalleeIndex < NumCallees; ++CalleeIndex) {
STARS_ea_t CalleeAddr = this->GetCallTargetAddr(CalleeIndex);
if (STARS_BADADDR != CalleeAddr) {
if ((STARS_BADADDR != CalleeAddr) && (!STARS_IsExternalFunc(CalleeAddr))) {
SMPFunction *CalleeFunc = this->GetProg()->FindFunction(CalleeAddr);
if (nullptr != CalleeFunc) {
this->InputRegs |= CalleeFunc->GetInputRegs();
......@@ -732,7 +732,7 @@ bool SMPFunction::ComputeInOutRegs(bool InheritPass, bool &WritesMem, bool &Call
SMPitype FlowType = CurrInst->GetDataFlowType();
if ((CALL == FlowType) || (INDIR_CALL == FlowType) || ((RETURN == FlowType) && CurrInst->IsTailCall())) {
STARS_ea_t CalleeAddr = CurrInst->GetCallTarget();
if (STARS_BADADDR != CalleeAddr) {
if ((STARS_BADADDR != CalleeAddr) && (!STARS_IsExternalFunc(CalleeAddr))) {
SMPFunction *CalleeFunc = this->GetProg()->FindFunction(CalleeAddr);
if ((nullptr != CalleeFunc) && CalleeFunc->StackPtrAnalysisSucceeded() && CalleeFunc->HasStructuredControlFlow()) {
if (VerboseOutput) {
......@@ -2346,7 +2346,7 @@ bool SMPFunction::AnalyzeStackPointerDeltas(void) {
(long)DeltaIncrement, CurrBlock->GetNumber(), (uint64_t) CurrBlock->GetFirstAddr());
#if SMP_VERBOSE_DEBUG_FUNC
if ((8 >= DeltaIncrement) && (0 <= DeltaIncrement))
this->Dump();
this->Dump(false);
#endif
}
continue; // Make the loop come around and process this block again, using
......@@ -4150,10 +4150,19 @@ bool SMPFunction::MDGetStackOffsetAndSize(SMPInstr *Instr, const STARSOpndTypePt
Unsigned = (opcode == STARS_NN_movzx);
Signed = (opcode == STARS_NN_movsx);
if ((0 > SignedOffset) && (!Indexed) && (BaseValue == this->MinStackAccessOffset) && (!this->DoesStackFrameExtendPastStackTop())) {
// Consider asserting here.
SMP_msg("ERROR: Negative offset in MDGetStackOffsetAndSize at %llx for inst dump: ", (uint64_t) Instr->GetAddr());
this->DumpFuncNameAndAddr();
Instr->Dump();
if (this->GoodLocalVarTable) { // No phase ordering problem; should not happen.
// Consider asserting here.
SMP_msg("ERROR: Negative offset in MDGetStackOffsetAndSize at %llx for inst dump: ", (uint64_t)Instr->GetAddr());
this->DumpFuncNameAndAddr();
Instr->Dump();
}
else {
// BuildStackAccessTables() calls UpdateMinMaxStackOffsets() which calls
// the current method, and also calls the current method directly.
// DoesStackFrameExtendPastStackTop() will be false until that phase completes, so not
// an error. We can set it as soon as we see it is needed.
this->SetStackFrameExtendsPastStackTop();
}
}
return true;
}
......@@ -4678,14 +4687,14 @@ bool SMPFunction::WritesAboveLocalFrame(const STARSOpndTypePtr &DestOp, bool OpN
 
MDExtractAddressFields(DestOp, BaseReg, IndexReg, ScaleFactor, offset);
SignedOffset = (long) offset;
bool IndexedWrite = (((IndexReg != STARS_x86_R_none) && (BaseReg != STARS_x86_R_none))
|| (0 < ScaleFactor));
bool ESPrelative = (BaseReg == MD_STACK_POINTER_REG) || (IndexReg == MD_STACK_POINTER_REG);
bool EBPrelative = this->UseFP && ((BaseReg == MD_FRAME_POINTER_REG) || (IndexReg == MD_FRAME_POINTER_REG));
bool EBPrelative = this->UseFP && (0 != offset) && (!IndexedWrite) && ((BaseReg == MD_FRAME_POINTER_REG) || (IndexReg == MD_FRAME_POINTER_REG));
assert(!EBPrelative || !OpNormalized); // stack operands should be normalized by now
if (!(ESPrelative || EBPrelative))
return false;
if (((IndexReg != STARS_x86_R_none) && (BaseReg != STARS_x86_R_none))
|| (0 < ScaleFactor)) {
if (IndexedWrite) {
SMP_msg("WARNING: WritesAboveLocalFrame called with indexed write.");
PrintOperand(DestOp);
return false;
......@@ -4718,14 +4727,14 @@ bool SMPFunction::AccessAboveLocalFrame(const STARSOpndTypePtr &StackOp, bool Op
 
MDExtractAddressFields(StackOp, BaseReg, IndexReg, ScaleFactor, offset);
SignedOffset = (long) offset;
bool IndexedWrite = (((IndexReg != STARS_x86_R_none) && (BaseReg != STARS_x86_R_none))
|| (0 < ScaleFactor));
bool ESPrelative = (BaseReg == MD_STACK_POINTER_REG) || (IndexReg == MD_STACK_POINTER_REG);
bool EBPrelative = this->UseFP && ((BaseReg == MD_FRAME_POINTER_REG) || (IndexReg == MD_FRAME_POINTER_REG));
bool EBPrelative = this->UseFP && (0 != offset) && (!IndexedWrite) && ((BaseReg == MD_FRAME_POINTER_REG) || (IndexReg == MD_FRAME_POINTER_REG));
assert(!EBPrelative || !OpNormalized); // stack operands should be normalized by now
if (!(ESPrelative || EBPrelative))
return false;
if (((IndexReg != STARS_x86_R_none) && (BaseReg != STARS_x86_R_none))
|| (0 < ScaleFactor)) {
if (IndexedWrite) {
SMP_msg("WARNING: AccessAboveLocalFrame called with indexed operand.");
PrintOperand(StackOp);
return false;
......@@ -4983,7 +4992,7 @@ void SMPFunction::EmitStackFrameAnnotations(FILE *AnnotFile, SMPInstr *Instr) {
(unsigned long) this->GetLocalVarsSize(), (unsigned long)TempRegionBytes, (unsigned long)TempOutArgsSize, (uint64_t)addr);
this->DumpFuncNameAndAddr();
#if 1
this->Dump();
this->Dump(false);
this->DumpDotCFG();
#endif
}
......@@ -5984,7 +5993,7 @@ void SMPFunction::AnalyzeMetadataLiveness(void) {
this->DumpDotCFG();
this->Dump(false);
}
assert(CurrUse != CurrInst->GetLastUse());
assert(CurrUse != CurrInst->GetLastUse()); // could be kablooey! if FATAL ERROR above
if (0 != ScaleFactor) {
; // mmStrata knows scaled reg is NUMERIC
// ... its metadata is not fetched
......@@ -6823,7 +6832,7 @@ void SMPFunction::ComputeSSA(void) {
 
#if 1
if (DumpFlag)
this->Dump();
this->Dump(false);
#endif
if (DebugFlag) SMP_msg("Computing global names.\n");
this->ComputeGlobalNames();
......@@ -6932,7 +6941,7 @@ void SMPFunction::ComputeSSA(void) {
 
#if SMP_DEBUG_DATAFLOW
if (DumpFlag)
this->Dump();
this->Dump(false);
#endif
 
// Compute the loop nests.
......@@ -7612,10 +7621,10 @@ void SMPFunction::ComputeLoopFollowNodesReachability(const std::size_t LoopNum)
this->DumpFuncNameAndAddr();
this->PrintedSPARKUnstructuredMsg = true;
}
this->SetHasUnstructuredCFG();
this->SetHasUnstructuredCFG(); // loop head does not dominate exit target
break;
}
}
} // end for all ExitTargetBlocks.
 
if (!Unstructured) {
// Find out where the multiple follow nodes converge, if they do. If they all hit separate return blocks,
......@@ -7643,10 +7652,32 @@ void SMPFunction::ComputeLoopFollowNodesReachability(const std::size_t LoopNum)
ReachableIntersection = STARSBitSetIntersection(ReachableIntersection, this->LoopExitTargetsReachabilitySets[LoopNum][(size_t)ExitTargetBlockNum]);
}
}
if (ReachableIntersection.IsAnyBitSet()) {
if (ReachableIntersection.IsAnyBitSet()) { // case 1; convergence
int FollowBlockNum = ReachableIntersection.FindLowestBitSet();
this->MultiLoopExitTargetsConvergenceMap[LoopNum].clear();
this->MultiLoopExitTargetsConvergenceMap[LoopNum].insert(FollowBlockNum);
// Now, trim the paths we followed by redoing MarkReachableBlocks() with a StopBlockNum == FollowBlockNum.
// Paths that go through the FollowBlockNum and continue downward are not useful in SPARK translation
// because we stop emitting SPARK code in the loop procedure when we see the FollowBlock in this convergent case.
// We can eliminate some error condition checks that were already performed above.
for (int ExitTargetBlockNum : this->LoopExitTargets[LoopNum]) {
STARSBitSet Reachable;
Reachable.AllocateBits(2 * this->GetNumBlocks()); // allow room for cloning
this->DomSoFar.ResetAllBits(); // Prepare for DomTree search, memoize dominated blocks seen so far.
int LimitBlockNum = (int)(1 + (2 * this->GetNumBlocks()));
bool ExitTargetIsFollowBlock = (ExitTargetBlockNum == FollowBlockNum);
this->MarkReachableBlocks(ExitTargetBlockNum, (int)LoopNum, LoopHeadBlockNum, true, LimitBlockNum, Reachable, FollowBlockNum);
assert(Reachable.IsAnyBitSet() || ExitTargetIsFollowBlock);
int OldHighestBit = this->LoopExitTargetsReachabilitySets[LoopNum][ExitTargetBlockNum].FindHighestBitSet();
int OldLowestBit = this->LoopExitTargetsReachabilitySets[LoopNum][ExitTargetBlockNum].FindLowestBitSet();
assert(ExitTargetIsFollowBlock || (Reachable.FindLowestBitSet() >= OldLowestBit)); // No diffs before OldLowestBit
for (int BitNum = OldLowestBit + 1; BitNum <= OldHighestBit; ++BitNum) {
if (!Reachable.GetBit((size_t)BitNum)) {
// Reset any bit not set in Reachable with StopBlockNum trace. (Might not be set anyway.)
this->LoopExitTargetsReachabilitySets[LoopNum][ExitTargetBlockNum].ResetBit((size_t)BitNum);
}
}
} // end for all ExitTargetBlocks.
}
else if (1 < this->MultiLoopExitTargetsConvergenceMap[LoopNum].size()) { // case 2c
if (!this->PrintedSPARKUnstructuredMsg) {
......@@ -7702,12 +7733,15 @@ void SMPFunction::ComputeLoopFollowNodesReachability(const std::size_t LoopNum)
return;
} // end of SMPFunction::ComputeLoopFollowNodesReachability()
 
// Set bits of current BlockNum and its descendants in CFG that are dominated by HeadBlockNum
// Set bits of current BlockNum and its descendants in CFG that are dominated by HeadBlockNum. Stop tracing if StopBlockNum is seen.
// NOTE: HeadBlockNum can be any dominating block num, with LoopNum < 0 indicating we are not in a loop.
void SMPFunction::MarkReachableBlocks(const int BlockNum, const int LoopNum, const int HeadBlockNum, const bool TestDominance, const int LimitBlockNum, STARSBitSet &ReachableSet) {
void SMPFunction::MarkReachableBlocks(const int BlockNum, const int LoopNum, const int HeadBlockNum, const bool TestDominance, const int LimitBlockNum, STARSBitSet &ReachableSet, const int StopBlockNum) {
if (ReachableSet.GetBit((size_t)BlockNum))
return; // avoid looping and duplication of work
 
if (BlockNum == StopBlockNum)
return; // Don't trace through StopBlockNum.
bool ProperDominance = true;
bool UseLimitBlock = false;
if (TestDominance) {
......@@ -7728,8 +7762,8 @@ void SMPFunction::MarkReachableBlocks(const int BlockNum, const int LoopNum, con
ReachableSet.SetBit((size_t)BlockNum);
for (SMPBasicBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
int SuccBlockNum = SuccBlock->GetNumber();
if (SuccBlockNum > BlockNum) { // filter out back edges
this->MarkReachableBlocks(SuccBlockNum, LoopNum, HeadBlockNum, TestDominance, LimitBlockNum, ReachableSet);
if ((SuccBlockNum > BlockNum) && (SuccBlockNum != StopBlockNum)) { // filter out back edges, avoid StopBlockNum.
this->MarkReachableBlocks(SuccBlockNum, LoopNum, HeadBlockNum, TestDominance, LimitBlockNum, ReachableSet, StopBlockNum);
}
}
return;
......@@ -7748,8 +7782,8 @@ void SMPFunction::MarkReachableBlocks(const int BlockNum, const int LoopNum, con
 
for (SMPBasicBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
int SuccBlockNum = SuccBlock->GetNumber();
// Weed out back edges
if (SuccBlockNum > BlockNum) {
// Weed out back edges and StopBlock.
if ((SuccBlockNum > BlockNum) && (SuccBlockNum != StopBlockNum)) {
// It is OK to exit an inner loop into multiple blocks that are part of an enclosing
// outer loop, but as we trace downwards from each such block, we cannot exit the outer
// loop. In the decompilation process, we will only translate blocks within the outer loop
......@@ -7835,7 +7869,7 @@ void SMPFunction::MarkReachableBlocks(const int BlockNum, const int LoopNum, con
LocalDominanceComputed = true;
}
if (LocalDominance) {
this->MarkReachableBlocks(SuccBlockNum, LoopNum, HeadBlockNum, TestDominance, LimitBlockNum, ReachableSet);
this->MarkReachableBlocks(SuccBlockNum, LoopNum, HeadBlockNum, TestDominance, LimitBlockNum, ReachableSet, StopBlockNum);
}
else {
// Terminating because we are escaping the region dominated by the loop head block.
......@@ -7844,7 +7878,7 @@ void SMPFunction::MarkReachableBlocks(const int BlockNum, const int LoopNum, con
// reachable blocks.
// NOTE: If the ExitTargetBlock (BlockNum) is not dominated by LoopHeadBlockNum,
// then we should not be looking at its successors in the first place.
if (0 <= LoopNum) {
if ((0 <= LoopNum) && (0 > StopBlockNum)) { // Loop, but not second pass
if (this->DoesBlockDominateBlock(HeadBlockNum, BlockNum)) {
this->MultiLoopExitTargetsConvergenceMap[(size_t)LoopNum].insert(SuccBlockNum);
}
......@@ -7852,7 +7886,7 @@ void SMPFunction::MarkReachableBlocks(const int BlockNum, const int LoopNum, con
}
}
}
}
} // end for all successors
}
 
return;
......@@ -8373,7 +8407,7 @@ void SMPFunction::DetectLoopInductionVars(void) {
DumpInductionVar(CurrentFamily.BasicInductionVar);
SMP_msg("\n");
if (VerboseOutput) {
this->Dump();
this->Dump(false);
this->DumpDotCFG();
}
break;
......@@ -8864,7 +8898,7 @@ void SMPFunction::DetectLoopInductionVars2(void) {
DumpInductionVar(CurrentFamily.BasicInductionVar);
SMP_msg("\n");
if (VerboseOutput && (!AlreadyDumped)) {
this->Dump();
this->Dump(false);
this->DumpDotCFG();
AlreadyDumped = true;
}
......@@ -12379,12 +12413,26 @@ bool SMPFunction::AnalyzeCompoundConditionalStatements(void) {
STARSTransCFGBlock *UnlinkBlock = this->GetTCFGBlockByNum((size_t)UnlinkBlockNum);
bool UnlinkNotHeadBlock = (UnlinkBlockNum != CloningHeadTCFGBlockNum);
int OriginalUnlinkBlockNum = UnlinkBlock->GetOriginalBlockNum();
#if 0
int InnermostLoopNum = UnlinkNotHeadBlock ? -1 : this->GetInnermostLoopNum(OriginalUnlinkBlockNum);
#else
int InnermostLoopNum = this->GetInnermostLoopNum(OriginalUnlinkBlockNum);
#endif
this->ResetTCFGVisitedBlocks();
this->MarkBlocksAndClone(StartBlockNum, UnlinkBlockNum, LimitBlockNum, InnermostLoopNum, true);
bool SaneAfterCloning = this->AuditTCFG();
// Pred/succ links are not complete until UpdateAfterCloning() executes when we clone more than 1 block.
// assert(SaneAfterCloning || (1 < this->CloningMap.size()));
#if 0 // Problems will be fixed by UpdateAfterCloning(), or not. We can assert later if not fixed.
if (1 == this->CloningMap.size()) {
// Pred/succ links are not complete until UpdateAfterCloning() executes when we clone more than 1 block or exit the loop.
bool SaneAfterCloning = this->AuditTCFG();
if (!SaneAfterCloning) {
this->DumpDotCFG();
SMP_msg("FATAL ERROR: TCFG: AuditTCFG failed early in AnalyzeCompoundConditionalStatements() ");
this->DumpFuncNameAndAddr();
this->Dump(true);
}
assert(SaneAfterCloning);
}
#endif
} // end for all items in SPARKCloningWorkList
 
if (this->TCFGBlocks.size() > this->TCFGDomSoFar.GetNumBits()) {
......@@ -12394,6 +12442,12 @@ bool SMPFunction::AnalyzeCompoundConditionalStatements(void) {
 
this->UpdateAfterCloning();
bool SaneAfterCloningUpdate = this->AuditTCFG();
if (!SaneAfterCloningUpdate) {
this->DumpDotCFG();
SMP_msg("FATAL ERROR: TCFG: AuditTCFG failed in AnalyzeCompoundConditionalStatements() ");
this->DumpFuncNameAndAddr();
this->Dump(true);
}
assert(SaneAfterCloningUpdate);
}
this->SPARKCloningWorkList.clear();
......@@ -12412,7 +12466,7 @@ bool SMPFunction::AnalyzeCompoundConditionalStatements(void) {
return Structured;
} // end of SMPFunction::AnalyzeCompoundConditionalStatements()
 
// Analyze if-then-else starting at COND_BRANCH at end of CurrBlock; return false if not well-structured
// Analyze if-then-else starting at COND_BRANCH at end of applicable blocks; return false if not well-structured
bool SMPFunction::AnalyzeConditionalStatements(void) {
 
// First, mark the short-circuit compound conditionals.
......@@ -12471,6 +12525,12 @@ bool SMPFunction::AnalyzeConditionalStatements(void) {
}
}
}
else if (1 == CurrTCFGBlock->GetNumSuccessors()) {
// Stupid code like "jz $+2" that jumps to the fall-through instruction,
// so a block with a COND_BRANCH only has one successor. We don't need
// to find a conditional follow node.
continue;
}
int HeadTCFGBlockNum = CurrTCFGBlockNum;
bool BitsetIfThenCase = false;
bool BitsetOddIfThenCase = false;
......@@ -12698,12 +12758,26 @@ bool SMPFunction::AnalyzeConditionalStatements(void) {
STARSTransCFGBlock *UnlinkBlock = this->GetTCFGBlockByNum((size_t)UnlinkBlockNum);
bool UnlinkNotHeadBlock = (UnlinkBlockNum != CloningHeadTCFGBlockNum);
int OriginalUnlinkBlockNum = UnlinkBlock->GetOriginalBlockNum();
#if 0
int InnermostLoopNum = UnlinkNotHeadBlock ? -1 : this->GetInnermostLoopNum(OriginalUnlinkBlockNum);
#else
int InnermostLoopNum = this->GetInnermostLoopNum(OriginalUnlinkBlockNum);
#endif
this->ResetTCFGVisitedBlocks();
this->MarkBlocksAndClone(StartBlockNum, UnlinkBlockNum, LimitBlockNum, InnermostLoopNum, true);
bool SaneAfterCloning = this->AuditTCFG();
// Pred/succ links are not complete until UpdateAfterCloning() executes when we clone more than 1 block or exit the loop.
// assert(SaneAfterCloning || (1 < this->CloningMap.size()));
#if 0 // Problems will be fixed by UpdateAfterCloning(), or not. We can assert later if not fixed.
if (1 == this->CloningMap.size()) {
// Pred/succ links are not complete until UpdateAfterCloning() executes when we clone more than 1 block or exit the loop.
bool SaneAfterCloning = this->AuditTCFG();
if (!SaneAfterCloning) {
this->DumpDotCFG();
SMP_msg("FATAL ERROR: TCFG: AuditTCFG failed early in AnalyzeConditionalStatements() ");
this->DumpFuncNameAndAddr();
this->Dump(true);
}
assert(SaneAfterCloning);
}
#endif
}
if (this->TCFGBlocks.size() > this->TCFGDomSoFar.GetNumBits()) {
StructuredConditional = false;
......@@ -12712,6 +12786,12 @@ bool SMPFunction::AnalyzeConditionalStatements(void) {
 
this->UpdateAfterCloning();
bool SaneAfterCloningUpdate = this->AuditTCFG();
if (!SaneAfterCloningUpdate) {
this->DumpDotCFG();
SMP_msg("FATAL ERROR: TCFG: AuditTCFG failed in AnalyzeConditionalStatements() ");
this->DumpFuncNameAndAddr();
this->Dump(true);
}
assert(SaneAfterCloningUpdate);
this->SPARKCloningWorkList.clear();
}
......@@ -12938,7 +13018,7 @@ int SMPFunction::FindConditionalFollowNode2(int HeadBlockNum) {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // error signal
this->DumpDotCFG();
if (VerboseOutput)
this->Dump();
this->Dump(false);
return FollowBlockNum;
}
}
......@@ -13661,7 +13741,7 @@ int SMPFunction::FindConditionalFollowNode4(const int HeadBlockNum, bool &IfThen
// can have itself, or a smaller RPO-numbered block, in its dominance frontier due to a loop back.
//
// A dominance frontier can be the empty set if every path from the block continues on to dead ends
// (e.g. return statements) without intersection another path starting at a different dominating block.
// (e.g. return statements) without intersecting another path starting at a different dominating block.
// Given that we need to find intersection points to analyze conditionals (see logic of FindConditionalFollowNode3()),
// the DomFrontier gives us a much quicker analysis of intersection points.
//
......@@ -13701,7 +13781,8 @@ int SMPFunction::FindConditionalFollowNode4(const int HeadBlockNum, bool &IfThen
// If either DomFrontier set has multiple forward successor blocks, or otherwise does not fit
// the above patterns (e.g. DomFrontier blocks are not the same), we have an unstructured conditional.
// Either we are bypassing the natural ENDIF point, or some path is branching into a THEN or ELSE clause.
// We use the SMP_BLOCKNUM_UNINIT (== -1) code for this result.
// We use the SMP_BLOCKNUM_UNINIT (== -1) code for this result. EXCEPTION: If we can structure the
// unstructured code by cloning, we need not return the error code.
//
 
STARS_ea_t HeadLastAddr = HeadBlock->GetLastAddr();
......@@ -13748,10 +13829,10 @@ int SMPFunction::FindConditionalFollowNode4(const int HeadBlockNum, bool &IfThen
// by HeadBlock.
bool FTNotDominated = (1 != FTBlock->GetNumPredsMinusBackEdges());
bool NFTNotDominated = (1 != NFTBlock->GetNumPredsMinusBackEdges());
this->TCFGDomSoFar.ResetAllBits(); // Prepare for TCFGDomTree search, memoize dominated blocks seen so far.
// In the short-circuit case, multiple edges from short-circuit tests flow to
// each of FTBlock and NFTBlock, so the pred count code above is not sufficient.
if (ShortCircuit) {
this->TCFGDomSoFar.ResetAllBits(); // Prepare for TCFGDomTree search, memoize dominated blocks seen so far.
FTNotDominated = (!this->DoesTCFGBlockDominateTCFGBlock(HeadBlockNum, FTBlockNum));
NFTNotDominated = (!this->DoesTCFGBlockDominateTCFGBlock(HeadBlockNum, NFTBlockNum));
}
......@@ -13807,222 +13888,397 @@ int SMPFunction::FindConditionalFollowNode4(const int HeadBlockNum, bool &IfThen
}
}
 
if ((FTForwardCount == 1) && (NFTForwardCount == 1) && (!NonConvergence)) {
FollowBlockNum = FTDomFrontierBlockNum;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
else if (TwoDeadEnds) {
assert(SMP_BLOCKNUM_COMMON_RETURN == FTDomFrontierBlockNum);
assert(SMP_BLOCKNUM_COMMON_RETURN == NFTDomFrontierBlockNum);
FollowBlockNum = FTDomFrontierBlockNum;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
else if (FTDomFrontierBlockNum == NFTBlockNum) {
FollowBlockNum = FTDomFrontierBlockNum;
IfThenCase = true;
OddIfThenCase = false;
IfThenElseCase = false;
}
else if (NFTDomFrontierBlockNum == FTBlockNum) {
FollowBlockNum = NFTDomFrontierBlockNum;
IfThenCase = false;
OddIfThenCase = true;
IfThenElseCase = false;
}
else if (OneDeadEnd) {
FollowBlockNum = SMP_BLOCKNUM_COMMON_RETURN;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
else if (TooMany || NonConvergence) {
FollowBlockNum = SMP_BLOCKNUM_UNINIT;
// Find the simple unstructured case in which a side entry into the THEN clause or ELSE clause
// does not enter at the FTBlock or NFTBlock, but a little later:
//
// B1 [ends with COND_BRANCH]
// |----+--------|
// | |
// | FTB
// | |
// | B2 ------+ [side entry here from up above B1]
// | |
// | |
// +-----+-------+
// |
// NFTB
//
// The DomFrontiers are not convergent, because the FTBlock has B2 as its DomFrontier.
// However, the fact that B2 has NFTB as its DomFrontier reveals the shape of the CFG;
// if we clone B2 through NFTB, we can eliminate the side entry and have a simple if-then statement.
// Note that FTB and B2 must have smaller RPO numbers than NFTB in this CFG; FTB is dominated
// by B1 but NFTB is not dominated by B1.
//
// Detect this pattern before getting into other cloning attempts.
// We can swap the FT and NFT labels without loss of generality.
//
bool DominanceIssue = (FTNotDominated || NFTNotDominated);
bool SimpleProblem = (NonConvergence && NoDeadEnds && (!TooMany));
if (SimpleProblem) {
// See if we can get convergence by looking at the DomFrontier for the smaller RPO
// successor and then looking at the DomFrontier for the DomFrontier block.
bool FTFirst = (FTBlockNum < NFTBlockNum);
int SmallerRPOBlock = FTFirst ? FTBlockNum : NFTBlockNum;
int LargerRPOBlock = FTFirst ? NFTBlockNum : FTBlockNum;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = false;
if (NonConvergence && (0 < FTDomFrontierBlockNum) && (0 < NFTDomFrontierBlockNum)) {
bool CloningCure = this->SolveConditionalDomFrontierProblemViaCloning(HeadBlockNum, FTBlockNum, NFTBlockNum, FTDomFrontierBlockNum, NFTDomFrontierBlockNum, FollowBlockNum);
if (CloningCure) {
IfThenElseCase = true;
if (FTFirst && (FTDomFrontierBlockNum < NFTBlockNum) && HeadBlock->IsBlockInDomFrontier(FTDomFrontierBlockNum)) {
// We have the shape we are looking for IF FTDomFrontierBlockNum (B2 in drawing above) has NFTBlockNum
// as its sole DomFrontier set entry.
STARSTransCFGBlock *FTDomFrontierBlock = this->GetTCFGBlockByNum((size_t)FTDomFrontierBlockNum);
assert(nullptr != FTDomFrontierBlock);
uint16_t LoopBackCount, ForwardCount;
int FTDomDomBlockNum = FTDomFrontierBlock->GetSingleDomFrontierBlockNumInsideLoop(InnermostLoopNum, LoopBackCount, ForwardCount);
if (FTDomDomBlockNum == NFTBlockNum) { // bingo!
set<int> BlockNumsToClone;
if (this->IsCloningSafe(FTDomFrontierBlockNum, NFTBlockNum, BlockNumsToClone)) {
// regular if-then case if we clone from FTDomFrontierBlockNum to a limit of NFTBlockNum.
SMP_msg("INFO: SPARK: if-then DomDom cloning opportunity for HeadBlock %d from %d to %d ",
HeadBlockNum, FTDomFrontierBlockNum, NFTBlockNum);
this->DumpFuncNameAndAddr();
FollowBlockNum = NFTBlockNum;
// The block to unlink from is more complicated than in other cloning cases. It is the predecessor
// of FTDomFrontierBlockNum on the path from FTBlock to FTDomFrontierBlock, so it will be
// dominated by HeadBlockNum. The side entry path is not dominated by HeadBlockNum.
// If more than one predecessor of FTDomFrontierBlock is dominated by the HeadBlock,
// we need more expensive analysis. Do that only when we encounter an example CFG.
bool FoundUnlinkPred = false;
int UnlinkBlockNum = SMP_BLOCKNUM_UNINIT;
for (STARSTransCFGBlock *PredBlock : FTDomFrontierBlock->GetConstPredList()) {
int PredTCFGBlockNum = PredBlock->GetNumber();
if ((PredTCFGBlockNum >= FTBlockNum) && (PredTCFGBlockNum < FTDomFrontierBlockNum) && this->DoesTCFGBlockDominateTCFGBlock(HeadBlockNum, PredTCFGBlockNum)) {
// Candidate. Is it the only candidate?
if (FoundUnlinkPred) { // previously found another candidate
SMP_msg("ERROR: SPARK: DomDom cloning foiled by >1 candidates for UnlinkBlockNum: %d and %d ",
UnlinkBlockNum, PredTCFGBlockNum);
this->DumpFuncNameAndAddr();
UnlinkBlockNum = SMP_BLOCKNUM_UNINIT;
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
break;
}
else {
UnlinkBlockNum = PredTCFGBlockNum;
FoundUnlinkPred = true;
}
}
} // end for all Preds of FTDomFrontierBlock
if (0 < UnlinkBlockNum) {
if (DominanceIssue) {
#if 0
SMP_msg("INFO: SPARK: DomDom cloning foiled by DominanceIssue at HeadBlock %d ", HeadBlockNum);
this->DumpFuncNameAndAddr();
}
else {
#else
SMP_msg("INFO: SPARK: DomDom cloning continuing despite DominanceIssue at HeadBlock %d ", HeadBlockNum);
this->DumpFuncNameAndAddr();
}
if (true) {
#endif
pair<int, int> UnlinkLimitPair(UnlinkBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(FTDomFrontierBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 11: Cloning from %d to %d would solve nonconvergent DomFrontiers for HeadBlock %d ",
FTDomFrontierBlockNum, FollowBlockNum, HeadBlockNum);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
IfThenCase = true;
}
}
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // not cloning
}
}
}
else if (!FTFirst && (NFTDomFrontierBlockNum < FTBlockNum) && HeadBlock->IsBlockInDomFrontier(NFTDomFrontierBlockNum)) {
// We have the odd-if-then shape we are looking for IF NFTDomFrontierBlockNum (B2 in drawing above) has FTBlockNum
// as its sole DomFrontier set entry.
STARSTransCFGBlock *NFTDomFrontierBlock = this->GetTCFGBlockByNum((size_t)NFTDomFrontierBlockNum);
assert(nullptr != NFTDomFrontierBlock);
uint16_t LoopBackCount, ForwardCount;
int NFTDomDomBlockNum = NFTDomFrontierBlock->GetSingleDomFrontierBlockNumInsideLoop(InnermostLoopNum, LoopBackCount, ForwardCount);
if (NFTDomDomBlockNum == FTBlockNum) { // bingo!
set<int> BlockNumsToClone;
if (this->IsCloningSafe(NFTDomFrontierBlockNum, FTBlockNum, BlockNumsToClone)) {
// odd-if-then case if we clone from NFTDomFrontierBlockNum to a limit of FTBlockNum.
SMP_msg("INFO: SPARK: odd-if-then DomDom cloning opportunity for HeadBlock %d from %d to %d ",
HeadBlockNum, NFTDomFrontierBlockNum, FTBlockNum);
this->DumpFuncNameAndAddr();
FollowBlockNum = FTBlockNum;
// The block to unlink from is more complicated than in other cloning cases. It is the predecessor
// of NFTDomFrontierBlockNum on the path from NFTBlock to NFTDomFrontierBlock, so it will have an
// RPO number between those two block numbers, while the side entry comes from a different RPO
// numbering region in the CFG. If more than one predecessor of NFTDomFrontierBlock has an eligible
// RPO block number, we need more expensive analysis. Do that only when we encounter an example CFG.
bool FoundUnlinkPred = false;
int UnlinkBlockNum = SMP_BLOCKNUM_UNINIT;
for (STARSTransCFGBlock *PredBlock : NFTDomFrontierBlock->GetConstPredList()) {
int PredTCFGBlockNum = PredBlock->GetNumber();
if ((PredTCFGBlockNum > NFTBlockNum) && (PredTCFGBlockNum < NFTDomFrontierBlockNum)) {
// Candidate. Is it the only candidate?
if (FoundUnlinkPred) { // previously found another candidate
SMP_msg("ERROR: SPARK: DomDom cloning foiled by >1 candidates for UnlinkBlockNum: %d and %d ",
UnlinkBlockNum, PredTCFGBlockNum);
this->DumpFuncNameAndAddr();
UnlinkBlockNum = SMP_BLOCKNUM_UNINIT;
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
break;
}
else {
UnlinkBlockNum = PredTCFGBlockNum;
FoundUnlinkPred = true;
}
}
} // end for all Preds of NFTDomFrontierBlock
if (0 < UnlinkBlockNum) {
pair<int, int> UnlinkLimitPair(UnlinkBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTDomFrontierBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 12: Cloning from %d to %d would solve nonconvergent DomFrontiers for HeadBlock %d ",
NFTDomFrontierBlockNum, FollowBlockNum, HeadBlockNum);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
OddIfThenCase = true;
}
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
}
if ((SMP_BLOCKNUM_UNINIT == FollowBlockNum) && (!this->PrintedSPARKUnstructuredMsg)) {
SMP_msg("ERROR: SPARK: Unstructured due to failure in FindConditionalFollowNode4 due to non-convergent DomFrontiers in HeadBlockNum %d ", HeadBlockNum);
this->DumpFuncNameAndAddr();
this->PrintedSPARKUnstructuredMsg = true;
}
}
else if ((FTLoopBackCount > 0) || (NFTLoopBackCount > 0)) {
FollowBlockNum = SMP_BLOCKNUM_COMMON_RETURN;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
 
// Check for the dominance problem on if-then-else case, which indicates an entry to
// the top of the THEN or ELSE cases that bypassed HeadBlock. Likewise, FTBlock must
// be dominated in an if-then and NFTBlock must be dominated on an odd if-then.
bool IfThenElseError = (IfThenElseCase && (FTNotDominated || NFTNotDominated));
bool IfThenError = (IfThenCase && FTNotDominated);
bool OddIfThenError = (OddIfThenCase && NFTNotDominated);
bool DominanceError = (IfThenElseError || IfThenError || OddIfThenError);
if (DominanceError) {
// See if we can salvage any of these errors by checking for straightforward translation patterns.
if (IfThenElseError && FTDeadEnd && NFTNotDominated && (!FTNotDominated)) {
// We can put the FTDeadEnd branch inside an if-then and branch to the NFTBlock/ENDIF.
if (this->SPARKCloningWorkList.empty()) { // no special case cloning from above
if ((FTForwardCount == 1) && (NFTForwardCount == 1) && (!NonConvergence)) {
FollowBlockNum = FTDomFrontierBlockNum;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
else if (TwoDeadEnds) {
assert(SMP_BLOCKNUM_COMMON_RETURN == FTDomFrontierBlockNum);
assert(SMP_BLOCKNUM_COMMON_RETURN == NFTDomFrontierBlockNum);
FollowBlockNum = FTDomFrontierBlockNum;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
else if (FTDomFrontierBlockNum == NFTBlockNum) {
FollowBlockNum = FTDomFrontierBlockNum;
IfThenCase = true;
OddIfThenCase = false;
IfThenElseCase = false;
FollowBlockNum = NFTBlockNum;
}
else if (IfThenElseError && NFTDeadEnd && FTNotDominated && (!NFTNotDominated)) {
// We can put the NFTDeadEnd branch inside an odd if-then and fall through to the FTBlock/ENDIF.
else if (NFTDomFrontierBlockNum == FTBlockNum) {
FollowBlockNum = NFTDomFrontierBlockNum;
IfThenCase = false;
OddIfThenCase = true;
IfThenElseCase = false;
FollowBlockNum = FTBlockNum;
}
else if (IfThenElseError && (!NonConvergence) && FTNotDominated && (!NFTNotDominated)) {
// FTNotDominated is only problem; we have convergence. Clone starting at FTBlockNum.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(FTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 1: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", FTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
else if (OneDeadEnd) {
FollowBlockNum = SMP_BLOCKNUM_COMMON_RETURN;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
else if (IfThenElseError && (!NonConvergence) && NFTNotDominated && (!FTNotDominated)) {
// NFTNotDominated is only problem; we have convergence. Clone starting at NFTBlockNum.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 2: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
else if (TooMany || NonConvergence) {
FollowBlockNum = SMP_BLOCKNUM_UNINIT;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = false;
if (NonConvergence && (0 < FTDomFrontierBlockNum) && (0 < NFTDomFrontierBlockNum)) {
bool CloningCure = this->SolveConditionalDomFrontierProblemViaCloning(HeadBlockNum, FTBlockNum, NFTBlockNum, FTDomFrontierBlockNum, NFTDomFrontierBlockNum, FollowBlockNum);
if (CloningCure) {
IfThenElseCase = true;
}
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
if ((SMP_BLOCKNUM_UNINIT == FollowBlockNum) && (!this->PrintedSPARKUnstructuredMsg)) {
SMP_msg("ERROR: SPARK: Unstructured due to failure in FindConditionalFollowNode4 due to non-convergent DomFrontiers in HeadBlockNum %d ", HeadBlockNum);
this->DumpFuncNameAndAddr();
this->PrintedSPARKUnstructuredMsg = true;
}
}
else if (IfThenElseError && NFTDeadEnd && NFTNotDominated && (!FTNotDominated)) {
// NFTNotDominated is only problem; lack of convergence is because of dead end. Clone starting at NFTBlockNum through its dead end.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 9: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
else if ((FTLoopBackCount > 0) || (NFTLoopBackCount > 0)) {
FollowBlockNum = SMP_BLOCKNUM_COMMON_RETURN;
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = true;
}
// Check for the dominance problem on if-then-else case, which indicates an entry to
// the top of the THEN or ELSE cases that bypassed HeadBlock. Likewise, FTBlock must
// be dominated in an if-then and NFTBlock must be dominated on an odd if-then.
bool IfThenElseError = (IfThenElseCase && DominanceIssue);
bool IfThenError = (IfThenCase && FTNotDominated);
bool OddIfThenError = (OddIfThenCase && NFTNotDominated);
bool DominanceError = (IfThenElseError || IfThenError || OddIfThenError);
if (DominanceError) {
// See if we can salvage any of these errors by checking for straightforward translation patterns.
if (IfThenElseError && FTDeadEnd && NFTNotDominated && (!FTNotDominated)) {
// We can put the FTDeadEnd branch inside an if-then and branch to the NFTBlock/ENDIF.
IfThenCase = true;
IfThenElseCase = false;
FollowBlockNum = NFTBlockNum;
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
else if (IfThenElseError && NFTDeadEnd && FTNotDominated && (!NFTNotDominated)) {
// We can put the NFTDeadEnd branch inside an odd if-then and fall through to the FTBlock/ENDIF.
OddIfThenCase = true;
IfThenElseCase = false;
FollowBlockNum = FTBlockNum;
}
}
else if (IfThenElseError && FTDeadEnd && FTNotDominated && (!NFTNotDominated)) {
// FTNotDominated is only problem; lack of convergence is because of dead end. Clone starting at FTBlockNum through its dead end.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(FTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 10: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d ", FTBlockNum, FollowBlockNum, HeadBlockNum);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
else if (IfThenElseError && (!NonConvergence) && FTNotDominated && (!NFTNotDominated)) {
// FTNotDominated is only problem; we have convergence. Clone starting at FTBlockNum.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(FTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 1: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", FTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
else if (IfThenElseError && (!NonConvergence) && NFTNotDominated && (!FTNotDominated)) {
// NFTNotDominated is only problem; we have convergence. Clone starting at NFTBlockNum.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 2: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
}
else if (IfThenElseError && FTNotDominated && NFTNotDominated && (FTDomFrontierBlockNum == NFTDomFrontierBlockNum)) {
// Side entrances into both FTBlock and NFTBlock. Cloning can structure it.
// The FTBlock and NFTBlock already have convergence at their DomFrontiers, just have dominance problem.
// We can relax the NoDeadEnds requirement and clone through dead ends later.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
set<int> BlockNumsToClone2;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) { // see if second cloning will also be safe.
else if (IfThenElseError && NFTDeadEnd && NFTNotDominated && (!FTNotDominated)) {
// NFTNotDominated is only problem; lack of convergence is because of dead end. Clone starting at NFTBlockNum through its dead end.
this->ResetTCFGVisitedBlocks();
SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone2);
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
pair<int, int> UnlinkLimitPair2(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem2(FTBlockNum, UnlinkLimitPair2);
this->SPARKCloningWorkList.push_back(CloningWorkListItem2);
SMP_msg("INFO: SPARK: CLONING 6: Cloning doubly from %d and %d to %d would solve DomFrontier non-convergence for HeadBlock %d NoDeadEnds %d ShortCircuitFlag %d ", FTBlockNum, NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds, ShortCircuit);
SMP_msg("INFO: SPARK: CLONING 9: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
if (!SafeCloning) {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
else if (IfThenElseError && FTDeadEnd && FTNotDominated && (!NFTNotDominated)) {
// FTNotDominated is only problem; lack of convergence is because of dead end. Clone starting at FTBlockNum through its dead end.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(FTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 10: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d ", FTBlockNum, FollowBlockNum, HeadBlockNum);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
}
else if (OddIfThenError) { // NFTNotDominated is the problem; clone starting at NFT
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 7: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
else if (IfThenElseError && FTNotDominated && NFTNotDominated && (FTDomFrontierBlockNum == NFTDomFrontierBlockNum)) {
// Side entrances into both FTBlock and NFTBlock. Cloning can structure it.
// The FTBlock and NFTBlock already have convergence at their DomFrontiers, just have dominance problem.
// We can relax the NoDeadEnds requirement and clone through dead ends later.
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
set<int> BlockNumsToClone2;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) { // see if second cloning will also be safe.
this->ResetTCFGVisitedBlocks();
SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone2);
if (SafeCloning) {
SafeCloning = this->IsDoubleCloningSafe(FTBlockNum, NFTBlockNum);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
pair<int, int> UnlinkLimitPair2(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem2(FTBlockNum, UnlinkLimitPair2);
this->SPARKCloningWorkList.push_back(CloningWorkListItem2);
SMP_msg("INFO: SPARK: CLONING 6: Cloning doubly from %d and %d to %d would solve DomFrontier non-convergence for HeadBlock %d NoDeadEnds %d ShortCircuitFlag %d ", FTBlockNum, NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds, ShortCircuit);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
SMP_msg("INFO: SPARK: Cloning doubly from %d and %d to %d unsafe due to reachability for HeadBlock %d NoDeadEnds %d ShortCircuitFlag %d ", FTBlockNum, NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds, ShortCircuit);
}
}
}
if (!SafeCloning) {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
else if (OddIfThenError) { // NFTNotDominated is the problem; clone starting at NFT
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(NFTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(NFTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 7: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", NFTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
}
else if (IfThenError) { // FTNotDominated is the problem; clone starting at FT
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(FTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 8: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", FTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
else if (IfThenError) { // FTNotDominated is the problem; clone starting at FT
this->ResetTCFGVisitedBlocks();
set<int> BlockNumsToClone;
bool SafeCloning = this->IsCloningSafe(FTBlockNum, FollowBlockNum, BlockNumsToClone);
if (SafeCloning) {
pair<int, int> UnlinkLimitPair(HeadBlockNum, FollowBlockNum);
pair<int, pair<int, int> > CloningWorkListItem(FTBlockNum, UnlinkLimitPair);
this->SPARKCloningWorkList.push_back(CloningWorkListItem);
SMP_msg("INFO: SPARK: CLONING 8: Cloning from %d to %d would solve DominanceProblem for HeadBlock %d NoDeadEnds %d ", FTBlockNum, FollowBlockNum, HeadBlockNum, NoDeadEnds);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
else {
FollowBlockNum = SMP_BLOCKNUM_UNINIT; // Not cloning
}
}
else {
if (!this->PrintedSPARKUnstructuredMsg) {
SMP_msg("ERROR: SPARK: Unstructured due to Dominance error in FindConditionalFollowNode4 at HeadBlockNum %d IfThenCase: %d OddIfThenCase: %d IfThenElseCase: %d ", HeadBlockNum, IfThenCase, OddIfThenCase, IfThenElseCase);
this->DumpFuncNameAndAddr();
this->PrintedSPARKUnstructuredMsg = true;
if (!this->PrintedSPARKUnstructuredMsg) {
SMP_msg("ERROR: SPARK: Unstructured due to Dominance error in FindConditionalFollowNode4 at HeadBlockNum %d IfThenCase: %d OddIfThenCase: %d IfThenElseCase: %d ", HeadBlockNum, IfThenCase, OddIfThenCase, IfThenElseCase);
this->DumpFuncNameAndAddr();
this->PrintedSPARKUnstructuredMsg = true;
}
this->DumpDotCFG();
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = false;
FollowBlockNum = SMP_BLOCKNUM_UNINIT;
}
this->DumpDotCFG();
IfThenCase = false;
OddIfThenCase = false;
IfThenElseCase = false;
FollowBlockNum = SMP_BLOCKNUM_UNINIT;
}
}
 
......@@ -14181,11 +14437,19 @@ bool SMPFunction::IsCloningSafe(const int StartTCFGBlockNum, const int LimitTCFG
bool TooBig = (this->TCFGBlocks.size() >= (3 * this->RPOBlocks.size())); // limit cloning explosion
bool Convergence = (0 < LimitTCFGBlockNum);
bool DeadEnd = (SMP_BLOCKNUM_COMMON_RETURN == LimitTCFGBlockNum);
bool LoopProblem = CurrTCFGBlock->IsLoopHeaderBlock();
bool SwitchProblem = CurrTCFGBlock->HasIndirectJump();
#if 0
bool Safe = ((StartTCFGBlockNum < LimitTCFGBlockNum) && (!CurrTCFGBlock->IsLoopHeaderBlock()) && (!CurrTCFGBlock->HasIndirectJump()) && (!TooBig));
#else
bool Safe = (Convergence || DeadEnd) && ((StartTCFGBlockNum != LimitTCFGBlockNum) && (!CurrTCFGBlock->IsLoopHeaderBlock()) && (!CurrTCFGBlock->HasIndirectJump()) && (!TooBig));
bool Safe = (Convergence || DeadEnd) && ((StartTCFGBlockNum != LimitTCFGBlockNum) && (!LoopProblem) && (!SwitchProblem) && (!TooBig));
#endif
if (!Safe) {
SMP_msg("ERROR: SPARK: IsCloningSafe() fails for StartBlock %d LimitBlock %d LoopProblem %d SwitchProblem %d TooBig %d ",
StartTCFGBlockNum, LimitTCFGBlockNum, LoopProblem, SwitchProblem, TooBig);
this->DumpFuncNameAndAddr();
}
if (Safe && (!CurrTCFGBlock->IsVisited())) {
BlockNumsToClone.insert(StartTCFGBlockNum);
CurrTCFGBlock->SetVisited(true);
......@@ -14208,15 +14472,40 @@ bool SMPFunction::IsCloningSafe(const int StartTCFGBlockNum, const int LimitTCFG
TooBig = (this->TCFGDomSoFar.GetNumBits() < (BlockNumsToClone.size() + this->TCFGBlocks.size()));
if (TooBig) {
Safe = false;
SMP_msg("ERROR: SPARK: TooBig2: IsCloningSafe() fails for StartBlock %d LimitBlock %d ", StartTCFGBlockNum, LimitTCFGBlockNum);
this->DumpFuncNameAndAddr();
}
 
if (!Safe) {
BlockNumsToClone.clear();
SMP_msg("ERROR: SPARK: IsCloningSafe() fails for StartBlock %d LimitBlock %d ", StartTCFGBlockNum, LimitTCFGBlockNum);
this->DumpFuncNameAndAddr();
}
 
return Safe;
} // end of SMPFunction::IsCloningSafe()
 
// Is it safe to double clone paths from StartBlockNum1 & 2, without either path running into the other start block?
bool SMPFunction::IsDoubleCloningSafe(const int StartTCFGBlockNum1, const int StartTCFGBlockNum2) {
// We only need to test from the lesser RPO number to the greater RPO number.
bool Reachable = true; // in case block nums are passed in equal
if ((0 < StartTCFGBlockNum1) && (0 < StartTCFGBlockNum2)) {
bool HitDeadEnd = false; // don't care; argument placeholder
if (StartTCFGBlockNum1 < StartTCFGBlockNum2) {
STARSTransCFGBlock *TCFGBlock1 = this->GetTCFGBlockByNum((size_t)StartTCFGBlockNum1);
this->ResetTCFGVisitedBlocks();
Reachable = TCFGBlock1->IsBlockReachableWithoutBackEdges(StartTCFGBlockNum2, HitDeadEnd);
}
else if (StartTCFGBlockNum2 < StartTCFGBlockNum1) {
STARSTransCFGBlock *TCFGBlock2 = this->GetTCFGBlockByNum((size_t)StartTCFGBlockNum2);
this->ResetTCFGVisitedBlocks();
Reachable = TCFGBlock2->IsBlockReachableWithoutBackEdges(StartTCFGBlockNum1, HitDeadEnd);
}
}
return (!Reachable);
} // end of SMPFunction::IsDoubleCloningSafe()
// Clone blocks on path from StartingBlockNum to <LimitBlockNum within InnermostLoopNum; unlink cloned StartingBlockNum from pred UnlinkBlockNum.
// Uses SCCPVisited flags to avoid redundant visits of blocks.
// Push cloned blocks onto end of TCFGBlocks.
......@@ -14728,18 +15017,21 @@ bool SMPFunction::AuditTCFG(void) const {
 
if ((0 > CurrBlockNum) || (CurrBlockNum > BlockNumLimit)) {
Sane = false;
SMP_msg("ERROR: TCFG: Block %d has out-of-range number.\n", CurrBlockNum);
SMP_msg("ERROR: TCFG: Block %d has out-of-range number ", CurrBlockNum);
this->DumpFuncNameAndAddr();
}
 
for (const STARSTransCFGBlock *PredBlock : TCFGBlock->GetConstPredList()) {
int PredBlockNum = PredBlock->GetNumber();
if (!PredBlock->HasSucc(TCFGBlock)) {
Sane = false;
SMP_msg("ERROR: TCFG: Block %d has non-reciprocal PredBlock %d \n", CurrBlockNum, PredBlockNum);
SMP_msg("ERROR: TCFG: Block %d has non-reciprocal PredBlock %d ", CurrBlockNum, PredBlockNum);
this->DumpFuncNameAndAddr();
}
if ((0 > PredBlockNum) || (PredBlockNum > BlockNumLimit)) {
Sane = false;
SMP_msg("ERROR: TCFG: Block %d has out-of-range PredBlockNum %d \n", CurrBlockNum, PredBlockNum);
SMP_msg("ERROR: TCFG: Block %d has out-of-range PredBlockNum %d ", CurrBlockNum, PredBlockNum);
this->DumpFuncNameAndAddr();
}
} // end for all predecessors
 
......@@ -14747,18 +15039,21 @@ bool SMPFunction::AuditTCFG(void) const {
int SuccBlockNum = SuccBlock->GetNumber();
if (!SuccBlock->HasPred(TCFGBlock)) {
Sane = false;
SMP_msg("ERROR: TCFG: Block %d has non-reciprocal SuccBlock %d \n", CurrBlockNum, SuccBlockNum);
SMP_msg("ERROR: TCFG: Block %d has non-reciprocal SuccBlock %d ", CurrBlockNum, SuccBlockNum);
this->DumpFuncNameAndAddr();
}
if ((0 > SuccBlockNum) || (SuccBlockNum > BlockNumLimit)) {
Sane = false;
SMP_msg("ERROR: TCFG: Block %d has out-of-range SuccBlockNum %d \n", CurrBlockNum, SuccBlockNum);
SMP_msg("ERROR: TCFG: Block %d has out-of-range SuccBlockNum %d ", CurrBlockNum, SuccBlockNum);
this->DumpFuncNameAndAddr();
}
} // end for all successors
} // end for all TCFGBlocks
 
if (this->TCFGBlocks.size() > this->TCFGDomSoFar.GetNumBits()) {
Sane = false;
SMP_msg("ERROR: TCFG: Block count %zu has grown larger than TCFGDomSoFar size %zu \n", this->TCFGBlocks.size(), this->TCFGDomSoFar.GetNumBits());
SMP_msg("ERROR: TCFG: Block count %zu has grown larger than TCFGDomSoFar size %zu ", this->TCFGBlocks.size(), this->TCFGDomSoFar.GetNumBits());
this->DumpFuncNameAndAddr();
}
 
// Audit the JumpFollowNodesMap.
......@@ -14775,7 +15070,8 @@ bool SMPFunction::AuditTCFG(void) const {
STARSTransCFGBlock *TargetBlock = this->GetTCFGBlockByNum((size_t)TargetBlockNum);
if (!TargetBlock->IsLoopHeaderBlock()) {
Sane = false;
SMP_msg("ERROR: TCFG: Bad JumpFollowNodesMap entry %d , %d \n", SourceBlockNum, TargetBlockNum);
SMP_msg("ERROR: TCFG: Bad JumpFollowNodesMap entry %d , %d ", SourceBlockNum, TargetBlockNum);
this->DumpFuncNameAndAddr();
}
}
}
......@@ -15161,6 +15457,8 @@ bool SMPFunction::FindMultiLoopContinue(const int BranchTCFGBlockNum) {
assert(0 <= BranchTCFGBlockNum);
bool Unstructured = false;
int OrigBlockNum = this->GetOrigBlockNumFromTCFGBlockNum(BranchTCFGBlockNum);
SMP_msg("INFO: SPARK: FindMultiLoopContinue() called with BranchTCFGBlockNum %d OrigBlockNum %d ", BranchTCFGBlockNum, OrigBlockNum);
this->DumpFuncNameAndAddr();
if (!this->IsBlockInAnyLoop(OrigBlockNum))
return Unstructured;
 
......@@ -15194,6 +15492,12 @@ bool SMPFunction::FindMultiLoopContinue(const int BranchTCFGBlockNum) {
for (STARSTransCFGBlock *SuccBlock : BranchTCFGBlock->GetConstSuccList()) {
int SuccBlockNum = SuccBlock->GetNumber();
int OrigSuccBlockNum = this->GetOrigBlockNumFromTCFGBlockNum(SuccBlockNum);
if (SuccBlock->IsOnlyInternalDirectJump()) {
// Follow the jump to the real successor.
SuccBlock = (*(SuccBlock->GetFirstConstSucc()));
SuccBlockNum = SuccBlock->GetNumber();
OrigSuccBlockNum = this->GetOrigBlockNumFromTCFGBlockNum(SuccBlockNum);
}
if (!this->IsTCFGBlockInLoop(SuccBlockNum, (size_t)InnermostLoopNum)) {
// Failed category A test.
if (!this->IsBlockLoopExitTarget((size_t)InnermostLoopNum, OrigSuccBlockNum)) {
......@@ -15483,6 +15787,7 @@ bool SMPFunction::ConditionalReachabilityLoopErrorHelper(const int CondHeadBlock
// Find guarded loops and fill the GuardToLoopMap and LoopToGuardMap
void SMPFunction::FindGuardedLoops(void) {
assert(this->HasStructuredControlFlow());
bool CloningHasOccurred = (this->TCFGBlocks.size() > this->RPOBlocks.size());
// We look for the following code structure:
// if (cond) then
// [straight-line code]
......@@ -15582,10 +15887,10 @@ void SMPFunction::FindGuardedLoops(void) {
pair<map<STARS_ea_t, STARS_ea_t>::iterator, bool> InsertResult;
pair<STARS_ea_t, STARS_ea_t> LoopToGuardValue(LoopAddr, LastInstAddr);
InsertResult = this->GuardToLoopMap.insert(GuardToLoopValue);
assert(InsertResult.second); // should never visit COND_BRANCH or loop address twice
assert(InsertResult.second || CloningHasOccurred); // should never visit COND_BRANCH or loop address twice w/o cloning
InsertResult = this->LoopToGuardMap.insert(LoopToGuardValue);
assert(InsertResult.second); // should never visit COND_BRANCH or loop address twice
SMP_msg("INFO: SPARK: Found guarded loop at %llx with guard at %llx\n", (uint64_t) LoopAddr, (uint64_t) LastInstAddr);
assert(InsertResult.second || CloningHasOccurred); // should never visit COND_BRANCH or loop address twice w/o cloning
SMP_msg("INFO: SPARK: Found guarded loop at %llx TCFGBlockIndex %zu with guard at %llx\n", (uint64_t) LoopAddr, BlockIndex, (uint64_t) LastInstAddr);
}
}
} // end if block has conditional branch
......@@ -15721,7 +16026,7 @@ void SMPFunction::ChainAliasHelper(size_t BlockNum) {
SMP_msg("Operand: ");
PrintOperand(LiveInOp);
SMP_msg("\n");
this->Dump();
this->Dump(false);
assert(STARS_BADADDR != LiveInDefAddr); // kablooey!
}
if (!AlreadyMarkedMaybeAliased) {
......@@ -16136,10 +16441,9 @@ void SMPFunction::RemoveCallingBlocks(void) const {
// Link basic blocks to their predecessors and successors.
void SMPFunction::SetLinks(void) {
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
list<SMPBasicBlock *> UnresolvedBranchWorkList;
STARS_ea_t InstAddr;
bool DebugFlag = (0x28f3a0 == this->GetFirstFuncAddr());
bool DebugFlag = (0x318000 == this->GetFirstFuncAddr());
#if SMP_DEBUG_DATAFLOW_VERBOSE
SMP_msg("SetLinks called for %s\n", this->GetFuncName());
#endif
......@@ -16149,8 +16453,7 @@ void SMPFunction::SetLinks(void) {
#endif
// 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);
for (SMPBasicBlock *CurrBlock : this->Blocks) {
vector<SMPInstr *>::iterator InstIter = (--(CurrBlock->GetLastInst()));
SMPInstr *CurrInst = (*InstIter);
InstAddr = CurrInst->GetAddr();
......@@ -16305,7 +16608,7 @@ void SMPFunction::SetLinks(void) {
changed = false;
list<SMPBasicBlock *>::iterator BlockIter = this->Blocks.begin();
while (BlockIter != this->Blocks.end()) {
CurrBlock = (*BlockIter);
SMPBasicBlock *CurrBlock = (*BlockIter);
STARS_ea_t BlockAddr = CurrBlock->GetFirstAddr();
if (CurrBlock->IsProcessed()) {
if (CurrBlock->IsUnreachableBlock()) { // has call 0 instruction, must be unreachable
......@@ -16585,7 +16888,7 @@ void SMPFunction::RPONumberBlocks(void) {
#if 0
SMP_msg("Set RPO number %d\n", CurrNum);
if (DebugFlag && (7 == CurrNum))
this->Dump();
this->Dump(false);
#endif
this->RPOBlocks.push_back(CurrBlock);
++CurrNum;
......@@ -17258,15 +17561,16 @@ void SMPFunction::ComputeTCFGDomFrontiers(void) {
// We look only at join points in the CFG, as per Cooper/Torczon chapter 9.
if (1 < CurrTCFGBlock->GetNumPreds()) { // join point; more than 1 predecessor
int runner;
int CurrTCFGBlockNum = CurrTCFGBlock->GetNumber();
assert(((size_t)CurrTCFGBlockNum) < this->TCFGIDom.size());
int CurrIDom = this->TCFGIDom[(size_t)CurrTCFGBlockNum];
for (STARSTransCFGBlock *CurrPred : CurrTCFGBlock->GetConstPredList()) {
// For each predecessor, we run up the TCFGIDom[] vector and add CurrBlock to the
// DomFrontier for all blocks that are between CurrPred and TCFGIDom[CurrTCFGBlock],
// For each predecessor, we run up the TCFGIDom[] vector and add CurrBlock (a.k.a. runner) to the
// DomFrontier for all blocks that are between CurrPred and TCFGIDom[CurrTCFGBlock] (a.k.a. CurrIDom),
// not including TCFGIDom[CurrTCFGBlock] itself.
runner = CurrPred->GetNumber();
assert(((size_t)runner) < this->TCFGBlocks.size());
int CurrTCFGBlockNum = CurrTCFGBlock->GetNumber();
assert(((size_t)CurrTCFGBlockNum) < this->TCFGIDom.size());
while (runner != this->TCFGIDom[(size_t)CurrTCFGBlockNum]) {
while (runner != CurrIDom) {
// Cooper/Harvey/Kennedy paper does not quite agree with the later
// text by Cooper/Torczon. Text (1st ed.) says that the start node has no IDom
// in the example on pages 462-463, but it shows an IDOM for the
......@@ -17276,7 +17580,7 @@ void SMPFunction::ComputeTCFGDomFrontiers(void) {
if (SMP_TOP_BLOCK == runner)
break;
RunnerBlock = this->TCFGBlocks[(size_t)runner];
RunnerBlock->AddToDomFrontier(CurrTCFGBlock->GetNumber());
RunnerBlock->AddToDomFrontier(CurrTCFGBlockNum);
runner = this->TCFGIDom[(size_t)runner];
}
} // end for all predecessors
......@@ -18194,8 +18498,11 @@ void SMPFunction::AnalyzeLoopIterations(void) {
this->RelationalUpperBoundExprs.resize(this->LoopCount + 1);
this->RelationalMemWriteWidths.resize(this->LoopCount + 1);
 
if (!this->HasStructuredControlFlow())
if (!this->HasStructuredControlFlow()) {
SMP_msg("INFO: LOOP: AnalyzeLoopIterations() terminating early due to unstructured control flow ");
this->DumpFuncNameAndAddr();
return; // just allocate data structures above to avoid crashes, then exit.
}
 
// Prepare for limited interprocedural constant propagation
// by finding constant InArg values.
......@@ -19214,7 +19521,7 @@ void SMPFunction::SSARenumber(void) {
// Recurse through the dominator tree starting with node 0.
this->SSARename(0);
if (DumpFlag)
this->Dump();
this->Dump(false);
SMP_msg("INFO: Max SSANum used for global names: %d\n", this->GetMaxStackSSANum());
return;
} // end of SMPFunction::SSARenumber()
......@@ -19385,7 +19692,7 @@ void SMPFunction::InferTypes(bool FirstIter) {
 
#if SMP_DEBUG_TYPE_INFERENCE
if (DebugFlag) {
this->Dump();
this->Dump(false);
}
#endif
// One time only: Set the types of immediate values, flags register, stack and frame
......@@ -19610,7 +19917,7 @@ bool SMPFunction::InferInterproceduralTypes(void) {
// See if we are calling a function with critical InArgs.
STARS_ea_t CalleeAddr = CurrInst->GetCallTarget();
SMPFunction *CalleeFunc = nullptr;
if (STARS_BADADDR != CalleeAddr) {
if ((STARS_BADADDR != CalleeAddr) && (!STARS_IsExternalFunc(CalleeAddr))) {
CalleeFunc = this->GetProg()->FindFunction(CalleeAddr);
}
if (nullptr != CalleeFunc) {
......@@ -20312,6 +20619,16 @@ void SMPFunction::UpdateLoopFollowBlockNum(int LoopHeadBlockNum, int FollowBlock
// in ClassifyLoop() and we don't want to clear the exit targets we have found.
this->LoopExitTargets[LoopNum].clear();
}
SMPBasicBlock *FollowBlock = this->GetBlockByNum((size_t)FollowBlockNum);
if (FollowBlock->IsOnlyInternalDirectJump()) {
// Skip forward to target of the direct jump. Jump is only for code layout reasons,
// not higher-level structuring.
SMPBasicBlock *FollowTargetBlock = (*(FollowBlock->GetFirstConstSucc()));
int NewFollowBlockNum = FollowTargetBlock->GetNumber();
SMP_msg("INFO: SPARK: Replacing JumpOnly loop follow block %d with target block %d", FollowBlockNum, NewFollowBlockNum);
this->DumpFuncNameAndAddr();
FollowBlockNum = NewFollowBlockNum;
}
this->LoopExitTargets[LoopNum].insert(FollowBlockNum);
}
else if (OldFollowNum != FollowBlockNum) {
......@@ -20368,7 +20685,7 @@ void SMPFunction::UpdateLoopFollowBlockNum(int LoopHeadBlockNum, int FollowBlock
this->HasGoodLoopFollowBlocks = false; // Conflicting loop follow blocks
#endif
if (VerboseOutput)
this->Dump();
this->Dump(false);
this->DumpDotCFG();
}
}
......@@ -20580,6 +20897,7 @@ void SMPFunction::MarkSpecialNumericErrorCases(void) {
bool StartupFunc = IsStartupFuncName(FuncName);
bool DeepLoopAnalysesRequested = global_STARS_program->ShouldSTARSPerformDeepLoopAnalyses();
bool SPARKTranslationRequested = global_STARS_program->ShouldSTARSTranslateToSPARKAda();
bool SPARKVerboseMode = global_stars_interface->VerboseSPARKMode();
 
set<int> NonEscapingRegisterHashes; // memoization optimization: set of register/SSA# hashes that do not reach end of block
 
......@@ -20633,7 +20951,7 @@ void SMPFunction::MarkSpecialNumericErrorCases(void) {
this->PrintedSPARKUnstructuredMsg = true;
}
}
break; // no point in continuing if we cannot translate to SPARK Ada
break; // no point in continuing if we cannot analyze loop nor translate to SPARK Ada
}
 
// Find all conditional and unconditional jumps within the function.
......@@ -20804,8 +21122,13 @@ void SMPFunction::MarkSpecialNumericErrorCases(void) {
SMP_msg("ERROR: SPARK: Unstructured due to unstructured switch statements ");
this->DumpFuncNameAndAddr();
this->PrintedSPARKUnstructuredMsg = true;
if (SPARKTranslationRequested) {
this->DumpDotCFG();
if (SPARKVerboseMode) {
this->Dump(true); // skeleton dump to analyze CFG
}
}
}
this->Dump(true); // skeleton dump to analyze CFG
break; // give up as soon as CFG is unstructured
}
}
......@@ -20814,7 +21137,7 @@ void SMPFunction::MarkSpecialNumericErrorCases(void) {
 
// Now we have identified all switch, loop-back and loop-exit jumps. The remaining jumps
// must be part of if-then, if-then-else, and if-then-elsif ... constructs.
if (this->HasStructuredControlFlow()) {
if (this->HasStructuredControlFlow() && SPARKTranslationRequested) {
bool StructuredConditionals = this->AnalyzeConditionalStatements();
if (!StructuredConditionals) {
this->SetHasUnstructuredCFG(); // Unstructured conditionals
......@@ -20827,7 +21150,7 @@ void SMPFunction::MarkSpecialNumericErrorCases(void) {
}
this->DumpFuncNameAndAddr();
#if 0
this->Dump();
this->Dump(false);
#endif
}
else if (this->HasStructuredControlFlow()) {
......@@ -22520,8 +22843,13 @@ int SMPFunction::FindInArgNumFromCopyAddr(STARS_ea_t CopyInstAddr) {
void SMPFunction::Dump(const bool SkeletonDump) {
list<SMPBasicBlock *>::iterator CurrBlock;
SMP_msg("Debug dump for function: %s\n", this->GetFuncName());
SMP_msg("UseFP: %d LocalVarsAllocInstr: %llx Block: %d\n", this->UseFP,
(uint64_t) this->LocalVarsAllocInstr, this->GetBlockFromInstAddr(this->LocalVarsAllocInstr)->GetNumber());
if (STARS_BADADDR != this->LocalVarsAllocInstr) {
SMP_msg("UseFP: %d LocalVarsAllocInstr: %llx Block: %d\n", this->UseFP,
(uint64_t) this->LocalVarsAllocInstr, this->GetBlockFromInstAddr(this->LocalVarsAllocInstr)->GetNumber());
}
else {
SMP_msg("UseFP: %d\n", this->UseFP);
}
if (!this->ReturnTargets.empty()) {
SMP_msg("Return targets: ");
for (STARS_ea_t RetTargetAddr : this->ReturnTargets) {
......@@ -22687,7 +23015,9 @@ void SMPFunction::Dump(const bool SkeletonDump) {
// Dump CFG representation for processing by "dot" program.
void SMPFunction::DumpDotCFG(void) {
if (!this->PrintedCFG) { // avoid redundant work
this->PrintedCFG = true;
#if 0 // Permit redundancy because STARST file changes as cloning occurs.
this->PrintedCFG = true;
#endif
string DotFileName(global_STARS_program->GetRootFileName());
DotFileName += ".STARS.";
char FuncBuf[20] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
......@@ -22707,16 +23037,71 @@ void SMPFunction::DumpDotCFG(void) {
SMP_fprintf(DotFile, "digraph %s {\n", FuncName.c_str());
 
for (SMPBasicBlock *CurrBlock : this->RPOBlocks) {
if (CurrBlock->GetNumSuccessors() > 0) {
size_t NumSuccs = CurrBlock->GetNumSuccessors();
if (NumSuccs > 0) {
int CurrBlockNum = CurrBlock->GetNumber();
for (SMPBasicBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
SMP_fprintf(DotFile, " %d -> %d\n", CurrBlockNum, SuccBlock->GetNumber());
bool CondBranch = CurrBlock->HasConditionalBranch();
bool JumpBlock = CurrBlock->HasDirectJump();
bool IndirJumpBlock = CurrBlock->HasIndirectJump();
bool UnoptimizedBranch = ((1 == NumSuccs) && CondBranch); // e.g. jz $+2, branches to fall-through.
bool ShortCircuitHead = (CondBranch && CurrBlock->IsShortCircuitHead());
bool ShortCircuitNonHead = CurrBlock->IsShortCircuitNonHead();
if (UnoptimizedBranch) {
int SuccBlockNum = (*(CurrBlock->GetFirstConstSucc()))->GetNumber();
// Two possibilities for a CondBranch with only one successor. One is
// the UnoptimizedBranch case, and the other is the conditional tail
// call or other cases of a branch to another function. We mark the former
// with a red edge, the latter with an orange edge.
if (CurrBlock->HasBranchToOtherFunc()) {
SMP_fprintf(DotFile, " %d -> %d [color=orange]\n", CurrBlockNum, SuccBlockNum);
}
else {
SMP_fprintf(DotFile, " %d -> %d [color=red]\n", CurrBlockNum, SuccBlockNum);
}
}
else if (ShortCircuitHead || ShortCircuitNonHead) {
assert(CondBranch || JumpBlock);
for (SMPBasicBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
bool SuccNonHead = SuccBlock->IsShortCircuitNonHead();
int SuccBlockNum = SuccBlock->GetNumber();
int BranchTargetBlockNum = JumpBlock ? SuccBlockNum : CurrBlock->GetCondNonFallThroughSuccBlockNum();
if (SuccNonHead) { // Show short circuit edge with green line
SMP_fprintf(DotFile, " %d -> %d [color=green]\n", CurrBlockNum, SuccBlockNum);
}
else if (SuccBlockNum == BranchTargetBlockNum) {
SMP_fprintf(DotFile, " %d -> %d [color=blue]\n", CurrBlockNum, SuccBlockNum);
}
else {
string ColorString = JumpBlock ? "purple" : "black";
SMP_fprintf(DotFile, " %d -> %d [color=%s]\n", CurrBlockNum, SuccBlockNum, ColorString.c_str());
}
}
}
else if (CondBranch || JumpBlock) { // Color the non-fall-through edge
for (SMPBasicBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
int SuccBlockNum = SuccBlock->GetNumber();
int BranchTargetBlockNum = JumpBlock ? SuccBlockNum : CurrBlock->GetCondNonFallThroughSuccBlockNum();
string ColorString = JumpBlock ? "purple" : "black";
if (SuccBlockNum == BranchTargetBlockNum) {
if (CondBranch) {
ColorString = "blue";
assert(!JumpBlock);
}
}
SMP_fprintf(DotFile, " %d -> %d [color=%s]\n", CurrBlockNum, SuccBlockNum, ColorString.c_str());
}
}
else { // No special cases
string ColorString = IndirJumpBlock ? "purple" : "black";
for (SMPBasicBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
SMP_fprintf(DotFile, " %d -> %d [color=%s]\n", CurrBlockNum, SuccBlock->GetNumber(), ColorString.c_str());
}
}
}
}
} // end for all blocks
SMP_fprintf(DotFile, "}\n");
(void)SMP_fclose(DotFile);
}
} // end for all blocks
 
if (this->TCFGBlocks.size() != this->RPOBlocks.size()) {
this->PrintedTCFG = true; // We don't check this because multiple clonings might need printing
......@@ -22739,18 +23124,33 @@ void SMPFunction::DumpDotCFG(void) {
SMP_fprintf(DotFile, "digraph %s {\n", FuncName.c_str());
 
for (STARSTransCFGBlock *CurrBlock : this->TCFGBlocks) {
if (CurrBlock->GetNumSuccessors() > 0) {
size_t NumSuccs = CurrBlock->GetNumSuccessors();
if (NumSuccs > 0) {
int CurrBlockNum = CurrBlock->GetNumber();
int CurrOrigBlockNum = CurrBlock->GetOriginalBlockNum();
bool CondBranch = CurrBlock->HasConditionalBranch();
bool JumpBlock = CurrBlock->HasDirectJump();
bool UnoptimizedBranch = ((1 == NumSuccs) && CondBranch); // e.g. jz $+2, branches to fall-through.
bool BranchOutsideFunc = UnoptimizedBranch && CurrBlock->HasBranchToOtherFunc();
string ColorString = JumpBlock ? "purple" : "black";
if (BranchOutsideFunc) {
ColorString = "orange";
}
else if (UnoptimizedBranch) {
ColorString = "red";
}
if (CurrBlockNum == CurrOrigBlockNum) {
for (STARSTransCFGBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
int SuccBlockNum = SuccBlock->GetNumber();
int SuccOrigBlockNum = SuccBlock->GetOriginalBlockNum();
if (!UnoptimizedBranch && (SuccBlockNum == CurrBlock->GetCondNonFallThroughSuccBlockNum())) {
ColorString = "blue";
}
if (SuccBlockNum == SuccOrigBlockNum) {
SMP_fprintf(DotFile, " %d -> %d\n", CurrBlockNum, SuccBlockNum);
SMP_fprintf(DotFile, " %d -> %d [color=%s]\n", CurrBlockNum, SuccBlockNum, ColorString.c_str());
}
else {
SMP_fprintf(DotFile, " %d -> %d.%d\n", CurrBlockNum, SuccBlockNum, SuccOrigBlockNum);
SMP_fprintf(DotFile, " %d -> %d.%d [color=%s]\n", CurrBlockNum, SuccBlockNum, SuccOrigBlockNum, ColorString.c_str());
}
}
}
......@@ -22758,11 +23158,14 @@ void SMPFunction::DumpDotCFG(void) {
for (STARSTransCFGBlock *SuccBlock : CurrBlock->GetConstSuccList()) {
int SuccBlockNum = SuccBlock->GetNumber();
int SuccOrigBlockNum = SuccBlock->GetOriginalBlockNum();
if (!UnoptimizedBranch && (SuccBlockNum == CurrBlock->GetCondNonFallThroughSuccBlockNum())) {
ColorString = "blue";
}
if (SuccBlockNum == SuccOrigBlockNum) {
SMP_fprintf(DotFile, " %d.%d -> %d\n", CurrBlockNum, CurrOrigBlockNum, SuccBlockNum);
SMP_fprintf(DotFile, " %d.%d -> %d [color=%s]\n", CurrBlockNum, CurrOrigBlockNum, SuccBlockNum, ColorString.c_str());
}
else {
SMP_fprintf(DotFile, " %d.%d -> %d.%d\n", CurrBlockNum, CurrOrigBlockNum, SuccBlockNum, SuccOrigBlockNum);
SMP_fprintf(DotFile, " %d.%d -> %d.%d [color=%s]\n", CurrBlockNum, CurrOrigBlockNum, SuccBlockNum, SuccOrigBlockNum, ColorString.c_str());
}
}
}
......@@ -22793,8 +23196,8 @@ void SMPFunction::DumpDotCFG(void) {
if (CurrBlock->IsExprHeadBlock()) { // just print FT and NFT blocks; coalesced expr blocks are omitted
int FTBlockNum = CurrBlock->GetExpr()->GetFallThroughBlockNum();
int NFTBlockNum = CurrBlock->GetExpr()->GetNonFallThroughBlockNum();
SMP_fprintf(DotFileC, " %d -> %d\n", CurrBlockNum, FTBlockNum);
SMP_fprintf(DotFileC, " %d -> %d\n", CurrBlockNum, NFTBlockNum);
SMP_fprintf(DotFileC, " %d -> %d [color=green]\n", CurrBlockNum, FTBlockNum);
SMP_fprintf(DotFileC, " %d -> %d [color=green]\n", CurrBlockNum, NFTBlockNum);
}
else if (!CurrBlock->IsCoalesced()) { // just print TCFG
for (STARSTransCFGBlock *SuccBlock : CurrTCFGBlock->GetConstSuccList()) {
......@@ -23222,7 +23625,7 @@ void SMPFunction::MarkFunctionSafe() {
else {
SMP_msg("FATAL ERROR: Unknown memory operand type in MarkFunctionSafe at %llx ", (uint64_t) address);
this->DumpFuncNameAndAddr();
this->Dump();
this->Dump(false);
this->DumpDotCFG();
assert(false);
}
......@@ -23423,7 +23826,8 @@ void SMPFunction::PreProcessForSPARKAdaTranslation(void) {
vector<SMPInstr *>::const_reverse_iterator LastInstIter = CurrBlock->GetRevInstCBegin();
SMPInstr *LastInst = (*LastInstIter);
if (LastInst->IsBranchToOtherFunc()) {
SMP_msg("SPARK: WARNING: Bad CFG (branch outside function at %llx) \n", (uint64_t)LastInst->GetAddr());
SMP_msg("ERROR: SPARK: Bad CFG (branch outside function at %llx in block %zu) ", (uint64_t)LastInst->GetAddr(), BlockNum);
this->DumpFuncNameAndAddr();
this->SetHasUnstructuredCFG(); // branch outside func
}
 
......@@ -23809,7 +24213,7 @@ bool SMPFunction::EmitSPARKLoopMemRangePostCondition(FILE *HeaderFile, FILE *Bod
bool HasNonRangeExprs = (!this->TempNonRangeExprWidthIters.empty());
bool HasRelationalExprs = (!this->RelationalMemWriteWidths[LoopNumPlusOne].empty());
 
// Besides memory writing contracts, nother pragma Loop_Invariant that has a corresponding post-condition is to assert
// Besides memory writing contracts, another pragma Loop_Invariant that has a corresponding post-condition is to assert
// that a register is loop-invariant if it is NOT in the OutputRegs bitset for this loop,
// and it is in the CalleePreservedRegsByLoop bitset for this loop. Find all such registers.
bool InvariantPreservedRegs = false;
......@@ -23968,7 +24372,6 @@ bool SMPFunction::EmitSPARKLoopMemRangePostCondition(FILE *HeaderFile, FILE *Bod
 
// ********** LOOP INVARIANTS ******************
// Emit similar loop invariants that mimic the post-conditions.
PrintSPARKIndentTabs(BodyFile);
OutputCount = 0; // reset for loop invariants
if (HasBIVInitialValue) { // Need loop invariant for basic induction var modulo value if increment step is not 1
// NOTE: We could have more than one BIV. Need to expand.
......@@ -23986,19 +24389,22 @@ bool SMPFunction::EmitSPARKLoopMemRangePostCondition(FILE *HeaderFile, FILE *Bod
STARSOpndTypePtr BIVDefOp = BIVIter->BasicInductionVar.InductionVar.GetOp();
SMPInstr *BIVInitInst = this->GetInstFromAddr(BIVInitAddr);
assert(nullptr != BIVInitInst);
PrintSPARKIndentTabs(BodyFile);
SMP_fprintf(BodyFile, "pragma Loop_Invariant(((");
BIVInitInst->PrintSPARKAdaOperand(BIVDefOp, BodyFile, false, UseFP, true, false, false);
SMP_fprintf(BodyFile, "- ");
BIVInitInst->PrintSPARKAdaOperand(BIVDefOp, BodyFile, false, UseFP, true, true, false);
SMP_fprintf(BodyFile, "'Loop_Entry) mod %d) = 0);\n", IncrementValue);
SMP_fprintf(BodyFile, "'Loop_Entry) mod %d) = 0); -- BIV relationship to initial and increment values\n", IncrementValue);
PrintSPARKIndentTabs(BodyFile);
// ++OutputCount; // leave count 0 for mem range exprs below (starting new loop invariants)
}
}
}
if (StackWritten) {
PrintSPARKIndentTabs(BodyFile);
SMP_fprintf(BodyFile, "pragma Loop_Invariant(for all i in Unsigned64 => (if ");
this->EmitSPARKStackMemRangePostCondition(BodyFile, LoopIndex, LoopAddr, false);
SMP_fprintf(BodyFile, " -- identify stack addresses changed; no other stack addrs change. ");
++OutputCount;
}
 
......@@ -24015,7 +24421,7 @@ bool SMPFunction::EmitSPARKLoopMemRangePostCondition(FILE *HeaderFile, FILE *Bod
FirstInst->PrintSPARKAdaOperand(RegOp, BodyFile, false, UseFP, true, false, false);
SMP_fprintf(BodyFile, "= ");
FirstInst->PrintSPARKAdaOperand(RegOp, BodyFile, false, UseFP, true, true, false);
SMP_fprintf(BodyFile, "'Loop_Entry);\n");
SMP_fprintf(BodyFile, "'Loop_Entry); -- reg unchanged by loop, or saved and restored by callees from loop.\n");
}
}
#if 0
......@@ -24537,7 +24943,7 @@ void SMPFunction::EmitIncomingLoopRegExprs(FILE *OutputFile, size_t LoopNum, boo
DefInst->PrintSPARKAdaOperand(DefOp, OutputFile, false, UseFP, true, false, false);
SMP_fprintf(OutputFile, " = (");
RegSourceExpr->EmitSPARKAda(OutputFile, true, true, false, HasArgs, true, false);
SMP_fprintf(OutputFile, "));\n");
SMP_fprintf(OutputFile, ")); -- incoming value of register.\n");
}
else { // must be a precondition
SMP_fprintf(OutputFile, " and\n");
......@@ -24567,6 +24973,9 @@ void SMPFunction::EmitSPARKLoopBIVLimits(FILE *BodyFile, STARS_ea_t LoopAddr, si
 
if (PragmaAssume) {
// Emit pragma Assume(lower_bound < upper_bound);
#if 0 // Must be sure that source was not changed after it was saved in BIVOp and before the beginning of the loop.
// Either we emit a dangerous assumption because of a source change, or we emit a worthless tautology like
// (RSP - 0x2b0 ) < (RSP - 0x100). No point in this pragma assume.
STARSExpression *UpperLimitExpr = nullptr;
if (!CountdownLoop) {
LowerLimitExpr = this->LoopIterationsInitExprs[LoopIndex];
......@@ -24609,8 +25018,14 @@ void SMPFunction::EmitSPARKLoopBIVLimits(FILE *BodyFile, STARS_ea_t LoopAddr, si
else {
UpperLimitExpr->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
}
SMP_fprintf(BodyFile, ");\n");
if (!CountdownLoop) {
SMP_fprintf(BodyFile, "); -- Counting upwards loop, BIV lower (initvalue) limit < upper limit.\n");
}
else {
SMP_fprintf(BodyFile, "); -- Counting downwards loop, BIV lower (endvalue) limit < upper limit.\n");
}
}
#endif // if 0
return; // the loop invariants will be done on a later call
} // end if (PragmaAssume)
 
......@@ -24632,42 +25047,64 @@ void SMPFunction::EmitSPARKLoopBIVLimits(FILE *BodyFile, STARS_ea_t LoopAddr, si
LowerLimitExpr = this->LoopIterationsLimitExprs[LoopIndex];
}
SPRelative = LowerLimitExpr->IsStackPtrRegUsed();
if (SPRelative) {
SMP_fprintf(BodyFile, "( ");
LowerLimitExpr->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
// Offset the stack pointer from its entry point value in the func that includes this loop.
SMP_fprintf(BodyFile, " + 16#%x# )", (0 - IncomingStackDelta));
if (!CountdownLoop) {
if (SPRelative) {
SMP_fprintf(BodyFile, "( ");
LowerLimitExpr->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
// Offset the stack pointer from its entry point value in the func that includes this loop.
SMP_fprintf(BodyFile, " + 16#%x# )", (0 - IncomingStackDelta));
}
else {
LowerLimitExpr->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
}
SMP_fprintf(BodyFile, "); -- Counting upwards loop; BIV relation to lower (initvalue) limit.\n");
}
else {
LowerLimitExpr->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
// Countdown loop; lower limit expr is relational.
assert(LowerLimitExpr->IsRelationalExpr());
if (LowerLimitExpr->HasRightSubTree()) {
SPRelative = LowerLimitExpr->GetRightTree()->IsStackPtrRegUsed();
if (SPRelative) {
SMP_fprintf(BodyFile, "( ");
LowerLimitExpr->GetRightTree()->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
// Offset the stack pointer from its entry point value in the func that includes this loop.
SMP_fprintf(BodyFile, " + 16#%x# )", (0 - IncomingStackDelta));
}
else {
LowerLimitExpr->GetRightTree()->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
}
}
else { // normal case; limit is operand
FirstInst->PrintSPARKAdaOperand(LowerLimitExpr->GetConstRightOperand(), BodyFile, false, UseFP, true, false, false);
}
SMP_fprintf(BodyFile, "); -- Counting downwards loop; BIV relation to lower (endvalue) limit.\n");
}
SMP_fprintf(BodyFile, ");\n");
 
// See if we have a non-constant limit for the BIV. If so, print its value,
// which will be found in the right hand side of the LimitExpr.
// See if we have a non-constant upper bound for the BIV. If so, print its value,
// which will be found in the right hand side of the LimitExpr for counting-up loops
// and in the InitExpr for the CountdownLoop case.
// Otherwise, use the constant limit.
assert(LoopIndex < this->LoopComparisonExprs.size());
assert(this->LoopIterationsLimitExprs[LoopIndex]->IsRelationalExpr());
STARSOpndTypePtr LimitOp = this->LoopComparisonExprs[LoopIndex].Operand2.GetOp();
assert(nullptr != LimitOp);
PrintSPARKIndentTabs(BodyFile);
SMP_fprintf(BodyFile, "pragma Loop_Invariant(");
FirstInst->PrintSPARKAdaOperand(BIVOp, BodyFile, false, UseFP, true, false, false);
if (!CountdownLoop) {
STARSOpndTypePtr LimitOp = this->LoopComparisonExprs[LoopIndex].Operand2.GetOp();
if (this->LoopExecutesWithLimitValue[LoopIndex])
SMP_fprintf(BodyFile, "<= ");
else
SMP_fprintf(BodyFile, "< ");
FirstInst->PrintSPARKAdaOperand(LimitOp, BodyFile, false, UseFP, true, false, false);
SMP_fprintf(BodyFile, "); -- Counting upwards loop; BIV relation to upper (endvalue) limit.\n");
}
else {
if (this->LoopExecutesWithLimitValue[LoopIndex])
SMP_fprintf(BodyFile, ">= ");
else
SMP_fprintf(BodyFile, "> ");
else { // CountdownLoop case has several differences
SMP_fprintf(BodyFile, "<= ");
this->LoopIterationsInitExprs[LoopIndex]->EmitSPARKAda(BodyFile, true, false, false, HasArgs, false, false);
SMP_fprintf(BodyFile, "); -- Counting downwards loop; BIV relation to upper (initvalue) limit.\n");
}
FirstInst->PrintSPARKAdaOperand(LimitOp, BodyFile, false, UseFP, true, false, false);
SMP_fprintf(BodyFile, ");\n");
 
#if 0 // Must be sure that source was not changed after it was saved in BIVOp and before the beginning of the loop.
// Now, print a version of the LimitOp that has been traced back to its source value
// if LimitOp is not a constant.
if (!LimitOp->IsImmedOp()) {
......@@ -24705,8 +25142,27 @@ void SMPFunction::EmitSPARKLoopBIVLimits(FILE *BodyFile, STARS_ea_t LoopAddr, si
// Offset the stack pointer from its entry point value in the func that includes this loop.
SMP_fprintf(BodyFile, " + 16#%x# )", (0 - IncomingStackDelta));
}
SMP_fprintf(BodyFile, ");\n");
if (!CountdownLoop) {
SMP_fprintf(BodyFile, "); -- Counting upwards loop; BIV relation to upper (endvalue) limit pre-loop source.\n");
}
else {
SMP_fprintf(BodyFile, "); -- Counting downwards loop; BIV relation to upper (initvalue) limit pre-loop source.\n");
}
} // end if (!LimitOp->IsImmedOp())
#else // Just limit the BIVOp in relation to its LoopEntry value.
PrintSPARKIndentTabs(BodyFile);
SMP_fprintf(BodyFile, "pragma Loop_Invariant(");
FirstInst->PrintSPARKAdaOperand(BIVOp, BodyFile, false, UseFP, true, false, false);
if (!CountdownLoop) {
SMP_fprintf(BodyFile, ">= ");
}
else {
SMP_fprintf(BodyFile, "<= ");
}
FirstInst->PrintSPARKAdaOperand(BIVOp, BodyFile, false, UseFP, true, true, false);
SMP_fprintf(BodyFile, "'LoopEntry); -- BIVOp relation to its LoopEntry value.\n");
#endif
return;
} // end of SMPFunction::EmitSPARKLoopBIVLimits()
 
......@@ -25568,7 +26024,7 @@ string SMPFunction::GetFuncSPARKSuffixString(void) const {
SMP_snprintf(HexAddr, 11, "_%x", this->GetFirstFuncAddr());
string FuncAddrString(HexAddr); // e.g. "_400586"
return FuncAddrString;
}
} // end of SMPFunction::GetFuncSPARKSuffixString()
 
// Generate loop exit flow-tracking boolean name, e.g. STARSExitLoop2ToBlock5
string SMPFunction::GenerateSPARKLoopExitBooleanName(const size_t LoopNum, const int ExitTargetTCFGBlockNum) const {
......@@ -26075,7 +26531,7 @@ void SMPFunction::AnalyzeLoopGlobals(int HeaderTCFGBlockNum, int FollowTCFGBlock
OutputRegs.set((size_t) MD_STACK_POINTER_REG);
// Inherit from callee. NOTE: RETURN could be tail call, INDIR_CALL could be resolved.
STARS_ea_t CalleeAddr = CurrInst->GetCallTarget();
if (STARS_BADADDR != CalleeAddr) {
if ((STARS_BADADDR != CalleeAddr) && (!STARS_IsExternalFunc(CalleeAddr))) {
SMPFunction *CalleeFunc = this->GetProg()->FindFunction(CalleeAddr);
if (nullptr != CalleeFunc) {
InputRegs |= CalleeFunc->GetInputRegs();
......@@ -26456,7 +26912,17 @@ void SMPFunction::EmitSPARKAdaForBlock(int CurrTCFGBlockNum, const int DomTCFGBl
LastInst->SetSPARKTranslated(true);
}
else if (FlowType == COND_BRANCH) {
if (LastCFType == JUMP_TO_SWITCH_INDIR_JUMP) {
if (1 == CurrTCFGBlock->GetNumSuccessors()) {
// Stupid unoptimized code like "jz $+2" that branches to the fall-through inst.
// We will just treat as a no-op.
assert(FALL_THROUGH == LastCFType);
LastInst->EmitSPARKAda(SPARKBodyFile, false);
// We don't have a true COND_BRANCH, so we don't get a conditional follow node
// in the normal way. Just grab the lone successor block num and resume
// translation there.
ResumeTCFGBlockNum = CurrTCFGBlock->GetCondNonFallThroughSuccBlockNum();
}
else if (LastCFType == JUMP_TO_SWITCH_INDIR_JUMP) {
// Should fall through to default case block. Resume translation there,
// which will cause use to emit the entire switch statement.
list<STARSTransCFGBlock *>::const_iterator FallThroughIter = CurrTCFGBlock->GetFallThroughSucc();
......@@ -26739,7 +27205,7 @@ void SMPFunction::EmitSPARKAdaForLoop(int HeaderTCFGBlockNum, int FollowTCFGBloc
SMP_msg("FATAL ERROR: COND_BRANCH of type JUMP_TO_SWITCH_INDIR_JUMP at %llx ", (uint64_t) LastAddr);
this->DumpFuncNameAndAddr();
this->DumpDotCFG();
this->Dump();
this->Dump(false);
assert(LastCFType != JUMP_TO_SWITCH_INDIR_JUMP); // kablooey!
}
else if (IsLoopExitFlow(LastCFType)) {
......@@ -26882,7 +27348,7 @@ void SMPFunction::EmitSPARKAdaForLoop(int HeaderTCFGBlockNum, int FollowTCFGBloc
this->TranslatingSPARKLoop = false;
 
if (MultipleExitTargets) {
this->EmitSPARKAdaForMultipleLoopExitTargets(SPARKBodyFile, (size_t)LoopNum);
this->EmitSPARKAdaForMultipleLoopExitTargets(SPARKBodyFile, (size_t)LoopNum, HeaderTCFGBlockNum);
}
 
#endif
......@@ -26890,7 +27356,7 @@ void SMPFunction::EmitSPARKAdaForLoop(int HeaderTCFGBlockNum, int FollowTCFGBloc
return;
} // end of SMPFunction::EmitSPARKAdaForLoop()
 
void SMPFunction::EmitSPARKAdaForMultipleLoopExitTargets(FILE *SPARKBodyFile, size_t LoopNum) {
void SMPFunction::EmitSPARKAdaForMultipleLoopExitTargets(FILE *SPARKBodyFile, const size_t LoopNum, const int HeaderTCFGBlockNum) {
// Translate blocks that are reachable from the multiple exit
// target blocks, including those exit target blocks, guarded
// by checks of the CFG Boolean flags that control access to
......@@ -26922,19 +27388,27 @@ void SMPFunction::EmitSPARKAdaForMultipleLoopExitTargets(FILE *SPARKBodyFile, si
assert(StartTCFGBlockNum < this->GetNumTCFGBlocks());
assert(EndTCFGBlockNum < this->GetNumTCFGBlocks());
 
#if 0 // MultiExitTargets could go beyond follow block with a return block. Use DomFrontier of header to limit below.
// Limit translation to stop at the follow block.
if ((((int)EndTCFGBlockNum) >= CurrLoopFollowTCFGBlockNum) && (0 < CurrLoopFollowTCFGBlockNum)) {
EndTCFGBlockNum = (size_t)(CurrLoopFollowTCFGBlockNum - 1);
}
#endif
 
STARSTransCFGBlock *HeaderTCFGBlock = this->GetTCFGBlockByNum((size_t)HeaderTCFGBlockNum);
assert(nullptr != HeaderTCFGBlock);
for (size_t TCFGBlockNum = StartTCFGBlockNum; TCFGBlockNum <= EndTCFGBlockNum; ++TCFGBlockNum) {
if (HeaderTCFGBlock->IsBlockInDomFrontier((int)TCFGBlockNum)) {
continue; // don't follow paths from exit targets beyond loop head dominance
}
STARSTransCFGBlock *CurrTCFGBlock = this->GetTCFGBlockByNum(TCFGBlockNum);
STARSCFGBlock *CurrShadowCFGBlock = this->GetClonedCFGBlockByNum(TCFGBlockNum);
bool EligibleBlock = (!CurrShadowCFGBlock->IsCoalesced()); // only generate code starting at short-circuit head blocks
if (ReachableUnion.GetBit(TCFGBlockNum) && CurrTCFGBlock->IsReadyToTranslate() && EligibleBlock) {
bool StartedGuardOutput = false;
uint32_t ReachableSourceCount = 0;
for (const pair<int, STARSBitSet> &CurrReachablePair : this->LoopExitTargetsReachabilitySets[LoopNum]) {
for (const auto &CurrReachablePair : this->LoopExitTargetsReachabilitySets[LoopNum]) {
STARSBitSet CurrBitSet;
CurrBitSet.AllocateBits(CurrReachablePair.second.GetNumBits());
CurrBitSet = CurrReachablePair.second;
......@@ -26947,7 +27421,7 @@ void SMPFunction::EmitSPARKAdaForMultipleLoopExitTargets(FILE *SPARKBodyFile, si
assert(0 <= InnerLoopNum);
bool MultipleExitTargets = this->EmitSPARKAdaLoopCall(LoopAddr, InnerLoopNum, SPARKBodyFile);
if (MultipleExitTargets) { // Recurse for reachable blocks from inner loop
this->EmitSPARKAdaForMultipleLoopExitTargets(SPARKBodyFile, InnerLoopNum);
this->EmitSPARKAdaForMultipleLoopExitTargets(SPARKBodyFile, InnerLoopNum, TCFGBlockNum);
}
int ResumeTCFGBlockNum;
(void) this->GetLoopFollowBlockNum(InnerLoopNum, ResumeTCFGBlockNum);
......@@ -26987,9 +27461,7 @@ void SMPFunction::EmitSPARKAdaForMultipleLoopExitTargets(FILE *SPARKBodyFile, si
if (StartedGuardOutput) {
SMP_fprintf(SPARKBodyFile, ") then\n");
++STARS_SPARK_IndentCount;
int LoopHeaderTCFGBlockNum = CurrTCFGBlock->FindParentLoopHeaderTCFGBlockNum();
assert(0 <= LoopHeaderTCFGBlockNum);
this->EmitSPARKAdaForBlock((int)TCFGBlockNum, LoopHeaderTCFGBlockNum, CurrLoopFollowTCFGBlockNum, SPARKBodyFile, false, false, ReachableSourceCount);
this->EmitSPARKAdaForBlock((int)TCFGBlockNum, HeaderTCFGBlockNum, CurrLoopFollowTCFGBlockNum, SPARKBodyFile, false, false, ReachableSourceCount);
--STARS_SPARK_IndentCount;
PrintSPARKIndentTabs(SPARKBodyFile);
SMP_fprintf(SPARKBodyFile, "end if;\n");
......@@ -27193,6 +27665,11 @@ void SMPFunction::EmitSPARKAdaForConditional(int HeaderTCFGBlockNum, int FollowT
int LoopFollowTCFGBlockNum = SMP_BLOCKNUM_UNINIT;
bool MultiExitLoop = this->GetLoopFollowBlockNum((size_t)LoopNum, LoopFollowTCFGBlockNum);
bool LoopFollowBlocksAreReturnBlocks = (SMP_BLOCKNUM_COMMON_RETURN == LoopFollowTCFGBlockNum);
if (MultiExitLoop && (0 < LoopFollowTCFGBlockNum)) {
// Could still be a return block, and multiexit targets could converge on it.
STARSTransCFGBlock *LoopFollowTCFGBlock = this->GetTCFGBlockByNum((size_t)LoopFollowTCFGBlockNum);
LoopFollowBlocksAreReturnBlocks = LoopFollowTCFGBlock->GetOriginalBlock()->HasReturn();
}
assert((0 < LoopFollowTCFGBlockNum) || (LoopFollowBlocksAreReturnBlocks && MultiExitLoop));
pair<int, int> BlockItem(LoopHeadTCFGBlockNum, LoopFollowTCFGBlockNum);
pair<int, pair<int, int> > WorkListItem(LoopNum, BlockItem);
......@@ -27788,7 +28265,7 @@ void SMPFunction::EmitArgShadowingAnnotations(FILE *InfoAnnotFile) {
// Case 2: Callee has critical InArg (eventually passed to critical library function).
if (!ArgSearch) {
STARS_ea_t CalleeAddr = CurrInst->GetCallTarget();
if (STARS_BADADDR != CalleeAddr) {
if ((STARS_BADADDR != CalleeAddr) && (!STARS_IsExternalFunc(CalleeAddr))) {
SMPFunction *CalleeFunc = this->GetProg()->FindFunction(CalleeAddr);
if (nullptr != CalleeFunc) {
CriticalArgPosBits = CalleeFunc->GetTaintInArgPositions();
......@@ -966,12 +966,12 @@ void SMPInstr::SPARKAdaOperandToString(const STARSOpndTypePtr &Opnd, std::string
SMP_snprintf(TempString, 20, " (%lld) ", (long long) SignedImmedValue);
}
else {
SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) SignedImmedValue);
SMP_snprintf(TempString, 20, " 16#%llx# ", (uint64_t) SignedImmedValue);
}
OutString.append(TempString);
}
else if (Opnd->IsFarPointer() || Opnd->IsNearPointer()) {
SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) Opnd->GetAddr());
SMP_snprintf(TempString, 20, " 16#%llx# ", (uint64_t) Opnd->GetAddr());
OutString.append(TempString);
}
else if (Opnd->IsVoidOp()) {
......@@ -981,11 +981,21 @@ void SMPInstr::SPARKAdaOperandToString(const STARSOpndTypePtr &Opnd, std::string
OutString.append(" ERROROP");
}
 
if (MemWrite) { // close the procedure call address arg cast parentheses
OutString.append("), "); // e.g. MemWrite32(Unsigned64(Opnd),
if (!OmitTrailingSpace) {
if (MemWrite) { // close the procedure call address arg cast parentheses
OutString.append("), "); // e.g. MemWrite32(Unsigned64(Opnd),
}
else if (MemRead) {
OutString.append(")) "); // e.g. MemRead8(Unsigned64(Opnd))
}
}
else if (MemRead) {
OutString.append(")) "); // e.g. MemRead8(Unsigned64(Opnd))
else {
if (MemWrite) { // close the procedure call address arg cast parentheses
OutString.append("),"); // e.g. MemWrite32(Unsigned64(Opnd),
}
else if (MemRead) {
OutString.append("))"); // e.g. MemRead8(Unsigned64(Opnd))
}
}
return;
} // end of SMPInstr::SPARKAdaOperandToString()
......@@ -3604,7 +3614,7 @@ bool STARSExpression::SimplifyExpr(STARSExpression *ParentExpr) {
if (RightValue == 0) {
SMP_msg("SERIOUS WARNING: Divide by zero avoided in SimplifyExpr for expr:\n");
this->Dump(0);
this->GetParentFunc()->Dump();
this->GetParentFunc()->Dump(false);
Simplified = false;
}
else {
......@@ -5080,7 +5090,7 @@ bool STARSExpression::UpdateImmedValue(STARS_uval_t OldValue, STARS_uval_t NewVa
;
}
}
assert(OldValue = (STARS_uval_t) Value);
assert(OldValue == (STARS_uval_t) Value);
this->SetLeftOperand(this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t)SignedNewValue));
}
} // end if (this->GetLeftOperand()->IsImmedOp())
......@@ -5113,7 +5123,7 @@ bool STARSExpression::UpdateImmedValue(STARS_uval_t OldValue, STARS_uval_t NewVa
;
}
}
assert(OldValue = (STARS_uval_t)Value);
assert(OldValue == (STARS_uval_t)Value);
this->SetRightOperand(this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t) SignedNewValue));
}
} // end if (this->GetRightOperand()->IsImmedOp())
......@@ -5225,7 +5235,7 @@ char *SMPInstr::GetDisasm(void) const {
bool SMPInstr::IsBasicBlockTerminator() const {
if (this->GetDataFlowType() == CALL) {
STARS_ea_t CallTarget = this->GetCallTarget();
if (STARS_BADADDR != CallTarget) {
if ((STARS_BADADDR != CallTarget) && (!STARS_IsExternalFunc(CallTarget))) {
STARS_Function_t *CalleeFunc = global_stars_interface->get_func(CallTarget);
if (nullptr != CalleeFunc) {
// Terminates basic block if it is a call to a non-returning func (e.g. abort(), exit())
......@@ -5820,6 +5830,29 @@ void SMPInstr::Dump(void) const {
else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
SMP_msg(" Xs ");
}
if (global_STARS_program->ShouldSTARSPerformConstantPropagation()) {
// Dump SCCP constant info.
if (LocalName) {
STARSSCCPMapIter ValueIter = this->GetBlock()->FindLocalConstValue(UseHashValue);
if (ValueIter != this->GetBlock()->GetLastLocalConstValueIter()) {
STARS_SCCP_Const_Struct ConstStruct = ValueIter->second;
if (ConstStruct.ConstType == STARS_CONST_HAS_VALUE) {
STARS_uval_t ConstValue = ConstStruct.ConstValue;
SMP_msg(" SCCP: %u ", ConstValue);
}
}
}
else {
STARSSCCPMapIter ValueIter = this->GetBlock()->GetFunc()->FindConstValue(UseHashValue);
if (ValueIter != this->GetBlock()->GetFunc()->GetLastConstValueIter()) {
STARS_SCCP_Const_Struct ConstStruct = ValueIter->second;
if (ConstStruct.ConstType == STARS_CONST_HAS_VALUE) {
STARS_uval_t ConstValue = ConstStruct.ConstValue;
SMP_msg(" SCCP: %u ", ConstValue);
}
}
}
}
}
SMP_msg("\n");
}
......@@ -5849,6 +5882,29 @@ void SMPInstr::Dump(void) const {
else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
SMP_msg(" Xs ");
}
if (global_STARS_program->ShouldSTARSPerformConstantPropagation()) {
// Dump SCCP constant info.
if (LocalName) {
STARSSCCPMapIter ValueIter = this->GetBlock()->FindLocalConstValue(DefHashValue);
if (ValueIter != this->GetBlock()->GetLastLocalConstValueIter()) {
STARS_SCCP_Const_Struct ConstStruct = ValueIter->second;
if (ConstStruct.ConstType == STARS_CONST_HAS_VALUE) {
STARS_uval_t ConstValue = ConstStruct.ConstValue;
SMP_msg(" SCCP: %u ", ConstValue);
}
}
}
else {
STARSSCCPMapIter ValueIter = this->GetBlock()->GetFunc()->FindConstValue(DefHashValue);
if (ValueIter != this->GetBlock()->GetFunc()->GetLastConstValueIter()) {
STARS_SCCP_Const_Struct ConstStruct = ValueIter->second;
if (ConstStruct.ConstType == STARS_CONST_HAS_VALUE) {
STARS_uval_t ConstValue = ConstStruct.ConstValue;
SMP_msg(" SCCP: %u ", ConstValue);
}
}
}
}
}
SMP_msg("\n");
}
......@@ -7012,7 +7068,7 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile, const bool DisAsmOnly) {
if (!ValidTranslation) {
// Produce files to speed up debugging.
this->GetBlock()->GetFunc()->DumpDotCFG();
this->GetBlock()->GetFunc()->Dump();
this->GetBlock()->GetFunc()->Dump(false);
SMP_msg("FATAL ERROR: EmitSPARKAda visiting inst at %llx in block %d twice ", (uint64_t) InstAddr, this->GetBlock()->GetNumber());
this->GetBlock()->GetFunc()->DumpFuncNameAndAddr();
}
......@@ -7102,7 +7158,18 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile, const bool DisAsmOnly) {
FuncControlFlowType = this->GetBlock()->GetFunc()->GetControlFlowType(InstAddr);
if (FALL_THROUGH == FuncControlFlowType) {
if (COND_BRANCH == CurrDataFlowType) {
SMP_fprintf(OutFile, "ERROR: COND_BRANCH instruction of unknown control flow.\n");
if (1 == this->GetBlock()->GetNumSuccessors()) {
// Stupid unoptimized code like "jz $+2" that branches to the fall-through inst.
// Treat it like a no-op.
// Must not be the case that it is a true COND_BRANCH with one target outside the function,
// and only one target inside the function, as SMPFunction detects that case and marks
// the entire function as unstructured, so we should never try to translate the branch.
assert(!this->IsBranchToOtherFunc());
SMP_fprintf(OutFile, "\tnull; -- COND_BRANCH to fall-through instruction elided here.\n");
}
else {
SMP_fprintf(OutFile, "ERROR: COND_BRANCH instruction of unknown control flow.\n");
}
}
else { // JUMP
PrintSPARKIndentTabs(OutFile);
......@@ -7357,7 +7424,7 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile, const bool DisAsmOnly) {
// See if we are calling a function that might call abort() or exit(), et al., somewhere
// in its call chain.
STARS_ea_t TargetAddr = this->GetCallTarget();
if (STARS_BADADDR != TargetAddr) {
if ((STARS_BADADDR != TargetAddr) && (!STARS_IsExternalFunc(TargetAddr))) {
SMPBasicBlock *CurrBlock = this->GetBlock();
SMPFunction *TargetFunc = CurrBlock->GetFunc()->GetProg()->FindFunction(TargetAddr);
if (nullptr != TargetFunc) {
......@@ -7461,13 +7528,15 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile, const bool DisAsmOnly) {
// The InArg RDI will have been saved in a Ghost variable called RDI_400788 at function entry.
STARSOpndTypePtr AddrRegOp = (*AddrRegInArgMapIter).second.first;
STARSOpndTypePtr InArgOp = (*AddrRegInArgMapIter).second.second;
PrintSPARKIndentTabs(OutFile);
SMP_fprintf(OutFile, "pragma Assert(");
this->PrintSPARKAdaOperand(AddrRegOp, OutFile, false, UseFP, true, false);
SMP_fprintf(OutFile, "=");
this->PrintSPARKAdaOperand(InArgOp, OutFile, false, UseFP, false, true);
// At this point, we have "pragma Assert(RBX = RDI" and we need the "_400788" suffix
SMP_fprintf(OutFile, "%s );\n", this->GetBlock()->GetFunc()->GetFuncSPARKSuffixString().c_str());
if (InArgOp->IsRegOp()) {
PrintSPARKIndentTabs(OutFile);
SMP_fprintf(OutFile, "pragma Assert(");
this->PrintSPARKAdaOperand(AddrRegOp, OutFile, false, UseFP, true, false);
SMP_fprintf(OutFile, "=");
this->PrintSPARKAdaOperand(InArgOp, OutFile, false, UseFP, false, true);
// At this point, we have "pragma Assert(RBX = RDI" and we need the "_400788" suffix
SMP_fprintf(OutFile, "%s );\n", this->GetBlock()->GetFunc()->GetFuncSPARKSuffixString().c_str());
}
// In addition to being a copy of the InArg, we want to assert that
// the memory write is in the safe stack region.
for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
......@@ -7724,10 +7793,10 @@ bool SMPInstr::MDIsFrameDeallocInstr(bool UseFP, STARS_asize_t LocalVarsSize) {
set<DefOrUse, LessDefUse>::iterator SecondUse = ++FirstUse;
if (SecondUse == this->Uses.GetLastRef())
return false; // no more USEs ... strange for ADD instruction
if (SecondUse->GetOp()->GetImmedValue() == ((STARS_uval_t) LocalVarsSize))
return true;
else if (SecondUse->GetOp()->IsImmedOp()) {
if (SecondUse->GetOp()->IsImmedOp()) {
intptr_t TempImm = (intptr_t) this->STARSInstPtr->GetOpnd(1)->GetImmedValue();
if (((STARS_uval_t)TempImm) == ((STARS_uval_t)LocalVarsSize))
return true;
if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc
return false;
else {
......@@ -9614,12 +9683,12 @@ void SMPInstr::MDFixFloatingPointRTL(void) {
// actually jumps within a function
void SMPInstr::AnalyzeCallInst(STARS_ea_t FirstFuncAddr) {
STARS_ea_t TargetAddr = this->GetCallTarget();
if (STARS_BADADDR != TargetAddr) {
if (this->GetCallTarget() == FirstFuncAddr) {
this->ResetDirectRecursiveCall();
if ((STARS_BADADDR != TargetAddr) && (!STARS_IsExternalFunc(TargetAddr))) {
if (TargetAddr == FirstFuncAddr) {
this->SetDirectRecursiveCall();
}
else {
this->ResetDirectRecursiveCall();
if (this->GetBlock()->GetFunc()->IsInstIDInFunc(TargetAddr)) {
this->SetCallUsedAsJump();
// Remove the call target from the sets and lists in the function.
......@@ -9702,7 +9771,7 @@ STARS_sval_t SMPInstr::AnalyzeStackPointerDelta(STARS_sval_t IncomingDelta, STAR
// would otherwise have a net stack ptr effect of 0.
#endif
STARS_ea_t CalledFuncAddr = this->GetCallTarget();
if ((STARS_BADADDR == CalledFuncAddr) || (0 == CalledFuncAddr)) {
if ((STARS_BADADDR == CalledFuncAddr) || (0 == CalledFuncAddr) || (STARS_IsExternalFunc(CalledFuncAddr))) {
if (this->IsFixedCallJump()) { // push happens previously; callee should swallow return address
InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA;
}
......@@ -10210,7 +10279,7 @@ STARSOpndTypePtr SMPInstr::GetSourceOnlyOperand(void) const {
if ((TypeGroup != 2) && (TypeGroup != 4) && (TypeGroup != 9) && (TypeGroup != 12)
&& (TypeGroup != 13)) {
SMP_msg("ERROR: Could not find source only operand at %llx in %s\n",
(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
(uint64_t) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
}
return nullptr;
} // end of SMPInstr::GetSourceOnlyOperand()
......@@ -10260,7 +10329,7 @@ void SMPInstr::MDFixupIDAProOperandList(void) {
&& (!(this->STARSInstPtr->IsUseOpnd(2)))) {
if ((nullptr != Opnd2) && (!Opnd2->IsVoidOp())) {
// We have a third operand that is neither DEF nor USE.
SMP_msg("INFO: Fixing IMUL operand list at %llx\n", (unsigned long long) this->GetAddr());
SMP_msg("INFO: Fixing IMUL operand list at %llx\n", (uint64_t) this->GetAddr());
// this->Dump();
// Two cases: Operands[0] == Operands[1], e.g. imul eax,Opnd2
// or else three-operand form: e.g. imul eax,ecx,Opnd2
......@@ -10283,6 +10352,22 @@ void SMPInstr::MDFixupIDAProOperandList(void) {
}
}
}
// Audit our SMPDefsFlags and SMPUsesFlags tables.
for (size_t OpIndex = 0; OpIndex < STARS_UA_MAXOP; ++OpIndex) {
STARSOpndTypePtr CurrOpnd = this->STARSInstPtr->GetOpnd(OpIndex);
if ((nullptr != CurrOpnd) && CurrOpnd->MatchesReg(MD_FLAGS_REG)) {
uint16_t opcode = this->GetIDAOpcode();
assert(opcode <= STARS_NN_last);
bool DefBitSet = this->STARSInstPtr->IsDefOpnd(OpIndex);
if (DefBitSet != SMPDefsFlags[opcode]) {
SMP_msg("ERROR: Flags reg at %llx not in agreement with SMPDefsFlags[] table.\n", (uint64_t)this->GetAddr());
}
bool UseBitSet = this->STARSInstPtr->IsUseOpnd(OpIndex);
if (UseBitSet != SMPUsesFlags[opcode]) {
SMP_msg("ERROR: Flags reg at %llx not in agreement with SMPUsesFlags[] table.\n", (uint64_t)this->GetAddr());
}
}
}
return;
} // SMPInstr::MDFixupIDAProOperandList()
 
......@@ -10638,7 +10723,10 @@ void SMPInstr::MDFixupDefUseLists(void) {
if ((STARS_BADADDR == CalledFuncAddr) && BranchOutsideFunc) {
CalledFuncAddr = this->GetJumpTarget();
}
SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr);
SMPFunction *CalleeFunc = nullptr;
if ((!STARS_IsExternalFunc(CalledFuncAddr))) {
CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr);
}
bool UnAnalyzedCalleeCase = ((nullptr == CalleeFunc) || (this->type == INDIR_CALL) || CalleeFunc->IsLinkerStub());
#if !STARS_CONSERVATIVE_DEADREGS
if (UnAnalyzedCalleeCase) {
......@@ -10843,7 +10931,10 @@ bool SMPInstr::MDFixupCallDefUseLists(void) {
// We want to add the caller-saved registers to the USEs and DEFs lists
if ((nullptr != this->GetBlock()) && (!this->IsInterruptCall())) {
STARS_ea_t CalledFuncAddr = this->GetCallTarget();
SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr);
SMPFunction *CalleeFunc = nullptr;
if (!STARS_IsExternalFunc(CalledFuncAddr)) {
CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr);
}
if ((nullptr != CalleeFunc) && (!CalleeFunc->IsLinkerStub())) {
// If CalleeFunc has preserved registers by saving them on entry and restoring them before
// all return points, then there is no need to conservatively consider these registers to
......@@ -14293,6 +14384,46 @@ bool SMPInstr::InferTypes(void) {
}
break;
 
case 16: // All non-flags operands are POINTER, both source and destination.
{
CurrDef = this->GetFirstDef();
while (CurrDef != this->GetLastDef()) {
DefOp = CurrDef->GetOp();
SSANum = CurrDef->GetSSANum();
if (DefOp->MatchesReg(MD_FLAGS_REG)) {
++CurrDef;
}
else {
CurrDef = this->SetDefType(DefOp, POINTER);
// Be conservative and only propagate register DEFs and SAFE stack locs. We
// can improve this in the future. **!!**
IsMemOp = (!DefOp->IsRegOp());
MemPropagate = MDIsDirectStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
;
#else
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
MemPropagate = MemPropagate && SafeFunc;
#endif
if ((DefOp->IsRegOp()) || MemPropagate) {
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, POINTER,
this->GetAddr(), SSANum, IsMemOp);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, POINTER,
SSANum, IsMemOp, false);
}
}
}
} // end while not last DEF
this->SetCategoryInferenceComplete();
changed = true;
}
break;
default:
SMP_msg("ERROR: Unknown type category for %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
this->SetCategoryInferenceComplete();
......@@ -16193,7 +16324,8 @@ bool SMPInstr::IsLastInstInOptimizedLoop(bool &DoubleTailBlock) {
// derived from the returned values should be treated as benign?
bool SMPInstr::IsNumericTrustedSystemCall(void) {
bool TrustedCall = false;
if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) {
STARS_ea_t CallTargetAddr = this->GetCallTarget();
if ((STARS_BADADDR != CallTargetAddr) && (!STARS_IsExternalFunc(CallTargetAddr)) && (!this->IsCallUsedAsJump())) {
// We have a resolved call target address, either via direct or indirect call.
string FuncName = this->GetTrimmedCalledFunctionName();
TrustedCall = global_STARS_program->IsNumericSafeSystemCall(FuncName);
......@@ -16423,9 +16555,11 @@ void SMPInstr::EmitCallReturnStatus(SMPProgram *CurrProg) {
CalleeFunc = CurrProg->FindFunction(CalleeAddr);
}
if (nullptr == CalleeFunc) {
SMP_msg("ERROR: Cannot find callee function for CALL at %llx \n", (unsigned long long) this->GetAddr());
if (!STARS_IsExternalFunc(CalleeAddr)) {
SMP_msg("ERROR: Cannot find callee function for CALL at %llx \n", (uint64_t) this->GetAddr());
}
SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR CALL RAUNSAFE %s\n",
(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
(uint64_t) this->GetAddr(), this->GetSize(), disasm);
this->EmitFastReturnStatus((unsigned short) NO_CALLERS);
}
else {
......@@ -16444,7 +16578,7 @@ void SMPInstr::EmitCallReturnStatus(SMPProgram *CurrProg) {
}
else if (INDIR_CALL == FlowType) {
STARS_ea_t CalleeAddr = this->GetCallTarget();
if ((STARS_BADADDR == CalleeAddr) || (!global_STARS_program->ShouldSTARSPerformFullAnalysis())) {
if ((STARS_BADADDR == CalleeAddr) || (STARS_IsExternalFunc(CalleeAddr)) || (!global_STARS_program->ShouldSTARSPerformFullAnalysis())) {
SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR INDIRCALL RAUNSAFE UNKNOWNTARGET %s\n",
(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
unsigned short DummyReturnStatus = INDIRECTLY_CALLED;
......@@ -16574,7 +16708,8 @@ void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE
// need to output a security alert.
// In the near future, we will output SPRI instrumentation to prevent
// the system/library call from executing.
if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) {
STARS_ea_t CallTargetAddr = this->GetCallTarget();
if ((STARS_BADADDR != CallTargetAddr) && (!STARS_IsExternalFunc(CallTargetAddr)) && (!this->IsCallUsedAsJump())) {
// We have a resolved call target address, either via direct or indirect call.
string FuncName = this->GetTrimmedCalledFunctionName();
ZST_SysCallType FuncCallType = global_STARS_program->GetCallTypeFromFuncName(FuncName);
......@@ -16877,7 +17012,8 @@ void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame,
// need to output a security alert.
// In the near future, we will output SPRI instrumentation to prevent
// the system/library call from executing.
if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) {
STARS_ea_t CallTargetAddr = this->GetCallTarget();
if ((STARS_BADADDR != CallTargetAddr) && (!STARS_IsExternalFunc(CallTargetAddr)) && (!this->IsCallUsedAsJump())) {
// We have a resolved call target address, either via direct or indirect call.
string FuncName = this->GetTrimmedCalledFunctionName();
ZST_SysCallType FuncCallType = global_STARS_program->GetCallTypeFromFuncName(FuncName);
......@@ -16967,8 +17103,9 @@ void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame,
 
case 1: // nothing for SDT to do
case 14:
case 16:
if (MemDest) {
SMP_msg("ERROR: MemDest in Type Category 1 or 14: %llx %s\n", (unsigned long long) addr, disasm);
SMP_msg("ERROR: MemDest in Type Category 1 or 14 or 16: %llx %s\n", (uint64_t) addr, disasm);
SDTInstrumentation = true;
break;
}
......@@ -17360,7 +17497,8 @@ void SMPInstr::EmitIntegerErrorAnnotations(FILE *InfoAnnotFile, list<std::size_t
bool cases4and5 = ((3 == this->GetOptType()) && this->GetMoveSource()->IsRegOp());
bool case6 = ((this->MDIsLoadEffectiveAddressInstr()) && (!(this->IsNop() || this->IsRegClearIdiom())));
bool case7 = this->MDDoublesWidth();
bool case8 = ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())); // possible memset() call
STARS_ea_t CallTargetAddr = this->GetCallTarget();
bool case8 = ((STARS_BADADDR != CallTargetAddr) && (!STARS_IsExternalFunc(CallTargetAddr)) && (!this->IsCallUsedAsJump())); // possible memset() call
 
char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
string SinkString("");
......@@ -19047,7 +19185,7 @@ string SMPInstr::GetTrimmedCalledFunctionName(void) {
}
else { // INDIR_CALL
// We might have a resolved call target for indirect calls.
if (STARS_BADADDR != FuncAddr) {
if ((STARS_BADADDR != FuncAddr) && (!STARS_IsExternalFunc(FuncAddr))) {
// We have a resolved address for the indirect call.
(void) SMP_get_func_name(FuncAddr, IDA_func_name, (std::size_t)(STARS_MAXSTR - 1));
SkipCount = strspn(IDA_func_name, "._");
......@@ -21406,6 +21544,11 @@ bool SMPInstr::BuildPackShiftRTL(SMPoperator PackOp, SMPoperator ShiftOp) {
ShiftRT->SetParentInst(this);
SMPRegTransfer *PackRT = new SMPRegTransfer;
PackRT->SetParentInst(this);
STARS_ea_t InstAddr = this->GetAddr();
#if SMP_DEBUG_BUILD_RTL
SMP_msg("DEBUG: BuildPackShiftRTL() called at address %llx\n", (uint64_t)InstAddr);
#endif
 
// RTL structure: top operator is assignment, next right operator is a reverse
// shift with the shift count as its left operand, and lowest right operator
......@@ -21414,7 +21557,26 @@ bool SMPInstr::BuildPackShiftRTL(SMPoperator PackOp, SMPoperator ShiftOp) {
STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
if (nullptr == TempOp) // finished processing operands
break;
#if SMP_DEBUG_BUILD_RTL
SMP_msg("DEBUG: Opnd %zu : ", OpNum);
PrintOperand(TempOp);
SMP_msg("\n");
#endif
if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
if (DestFound) {
SMP_msg("FATAL ERROR: More than one DEF operand in instruction at %llx\n", (uint64_t)this->GetAddr());
SMP_msg("Prior DEF: ");
PrintOperand(TempRT->GetConstLeftOperandNoNorm());
SMP_msg("\nSecond DEF: ");
PrintOperand(TempOp);
SMP_msg("\n");
assert(!TempOp->IsImmedOp());
assert(false);
}
else if (TempOp->IsImmedOp()) {
SMP_msg("FATAL ERROR: Immediate DEF operand in instruction at %llx\n", (uint64_t)this->GetAddr());
assert(false);
}
if (MDKnownOperandType(TempOp)) {
DestFound = true;
TempRT = new SMPRegTransfer;
......@@ -26967,6 +27129,25 @@ bool SMPInstr::BuildX86RTL(void)
return false;
break;
 
// Intel Affine Transformation instructions
case STARS_NN_gf2p8mulb: // Galois Field Multiply Bytes
case STARS_NN_gf2p8affineqb: // Computes Affine Transformation
case STARS_NN_gf2p8affineinvqb: // Computes Inverse Affine Transformation
// VEX versions
case STARS_NN_vgf2p8mulb: // Galois Field Multiply Bytes
case STARS_NN_vgf2p8affineqb: // Computes Affine Transformation
case STARS_NN_vgf2p8affineinvqb: // Computes Inverse Affine Transformation
// Intrinsics for Saving and Restoring the Extended Processor States (64-bits)
case STARS_NN_fxsave64: // Fast save FP context (64-bits)
case STARS_NN_fxrstor64: // Fast restore FP context (64-bits)
return false;
break;
default:
SMP_msg("ERROR: Unknown instruction opcode at %llx : %s\n", (uint64_t) this->GetAddr(),
DisAsmText.GetDisAsm(this->GetAddr()));
......@@ -27008,6 +27189,10 @@ void SMPInstr::SyncRTLDefUse(SMPRegTransfer *CurrRT, bool UseFP, STARS_sval_t FP
LeftOp = CurrRT->GetLeftOperand();
if (SMP_ASSIGN == CurrRT->GetOperator()) {
assert(! LeftOp->IsVoidOp());
if (LeftOp->IsImmedOp()) {
SMP_msg("FATAL ERROR: Assigning to immediate operand. Dumping instruction.\n");
this->Dump();
}
assert(! LeftOp->IsImmedOp());
LeftOp->CleanOpndEncoding();
CurrDef = this->Defs.FindRef(LeftOp);
......@@ -191,9 +191,11 @@ bool SMPProgram::FindGlobalMaxValue(const STARS_ea_t GlobalAddr, STARS_uval_t &M
// in the FuncMap, else return nullptr.
SMPFunction *SMPProgram::FindFunction(STARS_ea_t FirstAddr) const {
SMPFunction *FuncPtr = nullptr;
map<STARS_ea_t, SMPFunction *>::const_iterator FuncMapIter = this->FuncMap.find(FirstAddr);
if (this->FuncMap.cend() != FuncMapIter) {
FuncPtr = FuncMapIter->second;
if (STARS_BADADDR != FirstAddr) {
map<STARS_ea_t, SMPFunction *>::const_iterator FuncMapIter = this->FuncMap.find(FirstAddr);
if (this->FuncMap.cend() != FuncMapIter) {
FuncPtr = FuncMapIter->second;
}
}
return FuncPtr;
} // end of SMPProgram::FindFunction()
......@@ -724,18 +726,20 @@ void SMPProgram::Analyze(ProfilerInformation *pi, FILE *AnnotFile, FILE *InfoAnn
Time2 = time(nullptr);
for (size_t i = 0; i < NumCallTargets; ++i) {
STARS_ea_t CallAddr = CurrFunc->GetCallTargetAddr(i);
SMPFunction *ChildInstance = this->FindFunction(CallAddr);
if (!ChildInstance) {
if ((STARS_BADADDR != CallAddr) && (!STARS_IsExternalFunc(CallAddr))) {
SMPFunction *ChildInstance = this->FindFunction(CallAddr);
if (!ChildInstance) {
#if SMP_DEBUG_FUNC
// if a call target doesn't have a SMPFunction instance note it down
if (!CurrFunc->IsLinkerStub() && (STARS_BADADDR != CallAddr)) {
SMP_msg("ERROR: Function does not have SMPFunction instance at %llx from %s\n", (unsigned long long) CallAddr, CurrFunc->GetFuncName());
}
// if a call target doesn't have a SMPFunction instance note it down
if (!CurrFunc->IsLinkerStub() && (STARS_BADADDR != CallAddr)) {
SMP_msg("ERROR: Function does not have SMPFunction instance at %llx from %s\n", (unsigned long long) CallAddr, CurrFunc->GetFuncName());
}
#endif
continue;
continue;
}
UnsafeCallees |= (!ChildInstance->IsSafeCallee());
UnsafeSpecCallees |= (!ChildInstance->IsSpecSafeCallee());
}
UnsafeCallees |= (!ChildInstance->IsSafeCallee());
UnsafeSpecCallees |= (!ChildInstance->IsSpecSafeCallee());
}
Time3 = time(nullptr);
Analysis2 += difftime(Time3, Time2);
......@@ -800,7 +804,7 @@ void SMPProgram::Analyze(ProfilerInformation *pi, FILE *AnnotFile, FILE *InfoAnn
#if SMP_DEBUG_OPTIMIZATIONS_VERBOSE
if (DebugFlag) {
CurrFunc->Dump();
CurrFunc->Dump(false);
DebugFlag = false;
}
#endif
......@@ -859,9 +863,9 @@ void SMPProgram::Analyze(ProfilerInformation *pi, FILE *AnnotFile, FILE *InfoAnn
}
#if 1
// bool FuncFound = (0 == strcmp("__mktime_internal", CurrFunc->GetFuncName()));
bool FuncFound = (0x41e6f0 == CurrFunc->GetFirstFuncAddr());
bool FuncFound = (0x424ea2 == CurrFunc->GetFirstFuncAddr());
if ((!changed || (IterationCounter > STARS_INTERPROCEDURAL_ITERATION_LIMIT)) && FuncFound) {
CurrFunc->Dump();
CurrFunc->Dump(false);
CurrFunc->DumpDotCFG();
}
#endif
......@@ -1168,7 +1172,7 @@ bool SMPProgram::EmitProgramSPARKAda(void) {
if (TempFunc == nullptr) continue;
bool FuncFound = (0x444492 == TempFunc->GetFirstFuncAddr());
if (FuncFound) {
TempFunc->Dump();
TempFunc->Dump(false);
TempFunc->DumpDotCFG();
}
......@@ -1209,7 +1213,7 @@ bool SMPProgram::EmitProgramSPARKAda(void) {
if (TempFunc->HasGoodSSAForm()) {
bool EdgeSuccess = TempFunc->ComputeEdgeExpressions();
if (global_stars_interface->VerboseSPARKMode()) {
TempFunc->Dump();
TempFunc->Dump(false);
}
#if 0
else {
......@@ -1328,14 +1332,15 @@ FuncType SMPProgram::RecurseAndMarkRetAdd(SMPFunction* FuncAttrib) {
for (size_t i = 0; i < CallTargets.size(); i++) {
STARS_ea_t CallAddr = CallTargets[i];
SMPFunction* ChildInstance = this->FindFunction(CallAddr);
if (!ChildInstance && (STARS_BADADDR != CallAddr)) {
if (!ChildInstance && (STARS_BADADDR != CallAddr) && (!STARS_IsExternalFunc(CallAddr))) {
#if SMP_DEBUG_FUNC
// if a call target doesnt have a SMPFunction instance note it down
// If a call target doesn't have a SMPFunction instance note it.
SMP_msg("ERROR: Function does not have SMPFunction instance at %llx from %s\n",
(unsigned long long) CallAddr, FuncAttrib->GetFuncName());
(uint64_t) CallAddr, FuncAttrib->GetFuncName());
#endif
continue;
}
if (!ChildInstance)
continue;
UnsafeCallees |= (!ChildInstance->IsSafeCallee());
UnsafeSpecCallees |= (!ChildInstance->IsSpecSafeCallee());
switch (ChildInstance->GetReturnAddressStatus()) {
......@@ -1556,7 +1561,7 @@ void SMPProgram::Dump(void) {
map<STARS_ea_t, SMPFunction *>::iterator FuncIter;
for (FuncIter = this->FuncMap.begin(); FuncIter != this->FuncMap.end(); ++FuncIter) {
SMPFunction *TempFunc = FuncIter->second;
TempFunc->Dump();
TempFunc->Dump(false);
} // end for all functions
return;
} // end of SMPProgram::Dump()
......
......@@ -68,6 +68,7 @@
using namespace std;
#define SMP_DEBUG_DELAY 0 // for setting an early breakpoint
#define SMP_DELAY_TIME 25.0 // 25 seconds
// Set to 1 for debugging output
#define SMP_DEBUG 1
......@@ -380,11 +381,11 @@ bool idaapi IDAP_run(std::size_t arg) {
time_t current;
time(&start);
SMP_msg("delay for 15 seconds.\n");
printf("delay for 15 seconds.\n");
SMP_msg("delay for 25 seconds.\n");
printf("delay for 25 seconds.\n");
do {
time(&current);
} while(difftime(current,start) < 15.0);
} while(difftime(current,start) < SMP_DELAY_TIME);
#endif
#if SMP_DEBUG
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
......@@ -62,12 +62,12 @@ void STARS_IDA_Instruction_t::InitOperand(op_t &InitOp) const {
InitOp.specflag4 = 0;
#else // not 0
#if __GCC__ >= 8
#if __GNUC__ >= 8
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
(void) memset(&InitOp, 0, sizeof(op_t));
#if __GCC__ >= 8
#if __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif
......
......@@ -25,6 +25,7 @@
#endif
#include <funcs.hpp>
#include <segment.hpp> // for is_spec_ea()
#if (IDA_SDK_VERSION < 700)
#include <area.hpp>
......@@ -291,7 +292,13 @@ STARS_InstructionID_t STARS_IDA_Interface_t::FindFirstCallTarget(STARS_Instructi
}
// We found a target, not the fall-through.
CallTarget = xrefs.GetTo();
SMP_msg("Found indirect call target %lx at %lx\n", (unsigned long) CallTarget, (unsigned long) CallInstAddr);
if (::is_spec_ea(CallTarget)) {
// Call to external func, most likely. Signify with special address.
CallTarget = STARS_EXTERNAL_FUNC_ADDR;
}
else {
SMP_msg("Found indirect call target %llx at %llx\n", (uint64_t)CallTarget, (uint64_t)CallInstAddr);
}
break;
}
} // end for all code xrefs
......@@ -510,6 +517,11 @@ bool STARS_IDA_Interface_t::AuditEHFunctionBoundaries(void) {
SMP_msg("ERROR: Failed to redefine IDA FuncBounds.\n");
}
}
else if (nullptr == StartFunc) {
SMP_msg("INFO: FUNCBOUNDS: FDE range from %llx to %llx is orphan code.\n",
(uint64_t) CurrStartEA, (uint64_t) (CurrEndEA - 1));
ProblemFound = true;
}
} // end for (const auto FDEveciter : *FDEvecptr)
}
catch(const std::exception& e)
......
......@@ -2207,11 +2207,18 @@ inline uint32_t STARS_IRDB_Instruction_t::GetInitialInstFeatures(bool ShiftOpera
{
uint32_t my_features=0;
#define STARS_DEBUG_IMM_OPERANDS 0
#if STARS_DEBUG_IMM_OPERANDS
#define CHECK_ARG(p_disasm,num,use,def) \
if (p_disasm.hasOperand(num) && (p_disasm.getOperand(num)->isRead() || p_disasm.getOperand(num)->isConstant())) my_features |= use; \
if (p_disasm.hasOperand(num) && (!p_disasm.getOperand(num)->isConstant()) && p_disasm.getOperand(num)->isWritten()) my_features |= def; \
#else
#define CHECK_ARG(p_disasm,num,use,def) \
if(p_disasm.hasOperand(num) && p_disasm.getOperand(num)->isRead()) my_features|=use; \
if(p_disasm.hasOperand(num) && p_disasm.getOperand(num)->isWritten()) my_features|=def; \
#endif
if (!ShiftOperands) {
CHECK_ARG(p_disasm, 0, STARS_CF_USE1, STARS_CF_CHG1);
CHECK_ARG(p_disasm, 1, STARS_CF_USE2, STARS_CF_CHG2);
......@@ -2734,7 +2741,7 @@ bool STARS_IRDB_Instruction_t::STARS_GetCmd(void)
if(my_disasm.hasOperand(i))
Operands[i]=(std::make_shared<STARS_IRDB_op_t>(my_disasm,0,my_disasm.getOperand(i),length));
}
features=GetInitialInstFeatures(false,my_disasm);
this->features = GetInitialInstFeatures(false,my_disasm);
}
// Simplify the operand encoding so that identical operands don't appear to be different.
......@@ -2742,6 +2749,35 @@ bool STARS_IRDB_Instruction_t::STARS_GetCmd(void)
this->GetOpnd(i)->CleanOpndEncoding();
}
// Correct disasm errors by ensuring that an immediate operand is not a DEF.
bool DefFound = false;
bool DefFixed = false;
uint64_t InstAddr = (uint64_t)(this->GetID().GetIDWithinFile());
for (std::size_t i = 0; i < STARS_UA_MAXOP; ++i) {
if (nullptr != this->GetOpnd(i)) {
bool DefOperand = this->IsDefOpnd(i);
if (this->GetOpnd(i)->IsImmedOp()) {
if (DefOperand) {
SMP_msg("DEBUG: DISASM ERROR: Operand number %zu is immediate DEF at %llx. Changing to READ-only.\n",
i, InstAddr);
this->features &= (~DefMacros[i]); // unset only the DEF bit in the features.
DefFixed = true;
}
}
else if (DefOperand) {
DefFound = true;
}
}
} // end for all operands
if (DefFixed) {
if (DefFound) { // DEF other than immediate was found
SMP_msg("DEBUG: DISASM ERROR: Inst had good DEF and immediate DEF at %llx.\n", InstAddr);
}
else {
SMP_msg("DEBUG: DISASM ERROR: Only DEF was an immediate DEF at %llx.\n", InstAddr);
}
}
return length > 0;
}
......