From: DeLesley Hutchins Date: Sat, 19 Apr 2014 03:54:41 +0000 (+0000) Subject: Thread Safety Analysis: Convert to minimal SSA. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bb7d67a856cb823521195d1bae756308bda5d63c;p=clang Thread Safety Analysis: Convert to minimal SSA. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206681 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 6adef3471f..f8cfccc0a3 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -365,6 +365,7 @@ private: LVarDefinitionMap CurrentLVarMap; std::vector CurrentArguments; std::vector CurrentInstructions; + std::vector IncompleteArgs; til::BasicBlock *CurrentBB; BlockInfo *CurrentBlockInfo; }; diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index 94ef9b3951..b529ec013c 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -162,7 +162,7 @@ private: // Contains various helper functions for SExprs. namespace ThreadSafetyTIL { - inline bool isTrivial(SExpr *E) { + inline bool isTrivial(const SExpr *E) { unsigned Op = E->opcode(); return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr; } @@ -209,6 +209,7 @@ public: // Returns the definition (for let vars) or type (for parameter & self vars) SExpr *definition() { return Definition.get(); } + const SExpr *definition() const { return Definition.get(); } void attachVar() const { ++NumUses; } void detachVar() const { assert(NumUses > 0); --NumUses; } @@ -1107,6 +1108,15 @@ public: // TODO: change to SExprRef typedef SimpleArray ValArray; + // In minimal SSA form, all Phi nodes are MultiVal. + // During conversion to SSA, incomplete Phi nodes may be introduced, which + // are later determined to be SingleVal. + enum Status { + PH_MultiVal = 0, // Phi node has multiple distinct values. (Normal) + PH_SingleVal, // Phi node has one distinct value, and can be eliminated + PH_Incomplete // Phi node is incomplete + }; + static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; } Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {} @@ -1116,14 +1126,8 @@ public: const ValArray &values() const { return Values; } ValArray &values() { return Values; } - // Incomplete phi nodes are constructed during SSA conversion, and - // may not be necessary. - bool incomplete() const { return Flags == 1; } - - void setIncomplete(bool b) { - if (b) Flags = 1; - else Flags = 0; - } + Status status() const { return static_cast(Flags); } + void setStatus(Status s) { Flags = s; } template typename V::R_SExpr traverse(V &Visitor) { typename V::template Container Nvs(Visitor, @@ -1222,6 +1226,12 @@ private: }; +SExpr *getCanonicalVal(SExpr *E); +void simplifyIncompleteArg(Variable *V, til::Phi *Ph); + + + + } // end namespace til } // end namespace threadSafety } // end namespace clang diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h index dd10a34531..9d34aac325 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h @@ -505,16 +505,42 @@ protected: } void printLiteral(Literal *E, StreamType &SS) { - // TODO: actually pretty print the literal. - SS << "#lit"; + const clang::Expr *CE = E->clangExpr(); + switch (CE->getStmtClass()) { + case Stmt::IntegerLiteralClass: + SS << cast(CE)->getValue().toString(10, true); + return; + case Stmt::StringLiteralClass: + SS << "\"" << cast(CE)->getString() << "\""; + return; + case Stmt::CharacterLiteralClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::GNUNullExprClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::FloatingLiteralClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::ObjCStringLiteralClass: + default: + SS << "#lit"; + return; + } } void printLiteralPtr(LiteralPtr *E, StreamType &SS) { SS << E->clangDecl()->getNameAsString(); } - void printVariable(Variable *E, StreamType &SS) { + void printVariable(Variable *E, StreamType &SS, bool IsVarDecl = false) { SS << E->name() << E->getBlockID() << "_" << E->getID(); + if (IsVarDecl) + return; + + SExpr *V = getCanonicalVal(E); + if (V != E) { + SS << "{"; + printSExpr(V, SS, Prec_MAX); + SS << "}"; + } } void printFunction(Function *E, StreamType &SS, unsigned sugared = 0) { @@ -528,7 +554,7 @@ protected: SS << ", "; // Curried functions break; } - self()->printVariable(E->variableDecl(), SS); + self()->printVariable(E->variableDecl(), SS, true); SS << ": "; self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX); @@ -541,7 +567,7 @@ protected: void printSFunction(SFunction *E, StreamType &SS) { SS << "@"; - self()->printVariable(E->variableDecl(), SS); + self()->printVariable(E->variableDecl(), SS, true); SS << " "; self()->printSExpr(E->body(), SS, Prec_Decl); } @@ -632,7 +658,7 @@ protected: newline(SS); for (auto A : BBI->arguments()) { SS << "let "; - self()->printVariable(A, SS); + self()->printVariable(A, SS, true); SS << " = "; self()->printSExpr(A->definition(), SS, Prec_MAX); SS << ";"; @@ -641,7 +667,7 @@ protected: for (auto I : BBI->instructions()) { if (I->definition()->opcode() != COP_Store) { SS << "let "; - self()->printVariable(I, SS); + self()->printVariable(I, SS, true); SS << " = "; } self()->printSExpr(I->definition(), SS, Prec_MAX); @@ -663,11 +689,16 @@ protected: void printPhi(Phi *E, StreamType &SS) { SS << "phi("; unsigned i = 0; - for (auto V : E->values()) { - if (i > 0) - SS << ", "; - self()->printSExpr(V, SS, Prec_MAX); - ++i; + if (E->status() == Phi::PH_SingleVal) { + self()->printSExpr(E->values()[0], SS, Prec_MAX); + } + else { + for (auto V : E->values()) { + if (i > 0) + SS << ", "; + self()->printSExpr(V, SS, Prec_MAX); + ++i; + } } SS << ")"; } diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp index 6545bb1d0e..eae2552f05 100644 --- a/lib/Analysis/ThreadSafetyCommon.cpp +++ b/lib/Analysis/ThreadSafetyCommon.cpp @@ -36,6 +36,65 @@ namespace clang { namespace threadSafety { +namespace til { + +// If E is a variable, then trace back through any aliases or redundant +// Phi nodes to find the canonical definition. +SExpr *getCanonicalVal(SExpr *E) { + while (auto *V = dyn_cast(E)) { + SExpr *D; + do { + if (V->kind() != Variable::VK_Let) + return V; + D = V->definition(); + if (auto *V2 = dyn_cast(D)) { + V = V2; + continue; + } + } while(false); + + if (ThreadSafetyTIL::isTrivial(D)) + return D; + + if (Phi *Ph = dyn_cast(D)) { + if (Ph->status() == Phi::PH_Incomplete) + simplifyIncompleteArg(V, Ph); + + if (Ph->status() == Phi::PH_SingleVal) { + E = Ph->values()[0]; + continue; + } + } + return V; + } + return E; +} + + +// Trace the arguments of an incomplete Phi node to see if they have the same +// canonical definition. If so, mark the Phi node as redundant. +// getCanonicalVal() will recursively call simplifyIncompletePhi(). +void simplifyIncompleteArg(Variable *V, til::Phi *Ph) { + assert(!Ph && Ph->status() == Phi::PH_Incomplete); + + // eliminate infinite recursion -- assume that this node is not redundant. + Ph->setStatus(Phi::PH_MultiVal); + + SExpr *E0 = getCanonicalVal(Ph->values()[0]); + for (unsigned i=1, n=Ph->values().size(); ivalues()[i]); + if (Ei == V) + continue; // Recursive reference to itself. Don't count. + if (Ei != E0) { + return; // Status is already set to MultiVal. + } + } + Ph->setStatus(Phi::PH_SingleVal); +} + +} // end namespace til + + typedef SExprBuilder::CallingContext CallingContext; @@ -416,19 +475,6 @@ til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *E) { } -// Return true if the given expression represents a possibly unnecessary -// variable: i.e. a variable that references a Phi node that may be removed. -inline bool isIncompleteVar(til::SExpr *E) { - if (!E) - return true; // Null values are used on unknown backedges. - if (til::Variable *V = dyn_cast(E)) { - if (til::Phi *Ph = dyn_cast(V->definition())) - return Ph->incomplete(); - } - return false; -} - - // Make a Phi node in the current block for the i^th variable in CurrentVarMap. // If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E. // If E == null, this is a backedge and will be set later. @@ -444,8 +490,6 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) { assert(Ph && "Expecting Phi node."); if (E) Ph->values()[ArgIndex] = E; - if (!Ph->incomplete() && isIncompleteVar(E)) - Ph->setIncomplete(true); return; } @@ -457,12 +501,16 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) { Ph->values()[PIdx] = CurrentLVarMap[i].second; if (E) Ph->values()[ArgIndex] = E; - if (isIncompleteVar(E)) - Ph->setIncomplete(true); + if (!E) { + // This is a non-minimal SSA node, which may be removed later. + Ph->setStatus(til::Phi::PH_Incomplete); + } // Add Phi node to current block, and update CurrentLVarMap[i] auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first); CurrentArguments.push_back(Var); + if (Ph->status() == til::Phi::PH_Incomplete) + IncompleteArgs.push_back(Var); CurrentLVarMap.makeWritable(); CurrentLVarMap.elem(i).second = Var; @@ -680,8 +728,15 @@ void SExprBuilder::exitCFGBlock(const CFGBlock *B) { void SExprBuilder::exitCFG(const CFGBlock *Last) { + for (auto *V : IncompleteArgs) { + til::Phi *Ph = dyn_cast(V->definition()); + if (Ph && Ph->status() == til::Phi::PH_Incomplete) + simplifyIncompleteArg(V, Ph); + } + CurrentArguments.clear(); CurrentInstructions.clear(); + IncompleteArgs.clear(); }