r206681 - Thread Safety Analysis: Convert to minimal SSA.
Aaron Ballman
aaron at aaronballman.com
Wed Apr 23 07:27:07 PDT 2014
On Fri, Apr 18, 2014 at 11:54 PM, DeLesley Hutchins <delesley at google.com> wrote:
> Author: delesley
> Date: Fri Apr 18 22:54:41 2014
> New Revision: 206681
>
> URL: http://llvm.org/viewvc/llvm-project?rev=206681&view=rev
> Log:
> Thread Safety Analysis: Convert to minimal SSA.
>
> Modified:
> cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
> cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
> cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
> cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
>
> Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=206681&r1=206680&r2=206681&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Fri Apr 18 22:54:41 2014
> @@ -365,6 +365,7 @@ private:
> LVarDefinitionMap CurrentLVarMap;
> std::vector<til::Variable*> CurrentArguments;
> std::vector<til::Variable*> CurrentInstructions;
> + std::vector<til::Variable*> IncompleteArgs;
> til::BasicBlock *CurrentBB;
> BlockInfo *CurrentBlockInfo;
> };
>
> Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h?rev=206681&r1=206680&r2=206681&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Fri Apr 18 22:54:41 2014
> @@ -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<SExpr *> 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<Status>(Flags); }
> + void setStatus(Status s) { Flags = s; }
>
> template <class V> typename V::R_SExpr traverse(V &Visitor) {
> typename V::template Container<typename V::R_SExpr> Nvs(Visitor,
> @@ -1222,6 +1226,12 @@ private:
> };
>
>
> +SExpr *getCanonicalVal(SExpr *E);
This function is declared in TheadSafetyTIL.h but defined in
ThreadSafetyCommon.cpp; should it instead be declared in
ThreadSafetyCommon.h?
> +void simplifyIncompleteArg(Variable *V, til::Phi *Ph);
This function is only used in ThreadSafetyCommon.cpp; should it be a
static function in that file instead, or are you intending to use it
outside of that file soon?
> +
> +
> +
> +
> } // end namespace til
> } // end namespace threadSafety
> } // end namespace clang
>
> Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h?rev=206681&r1=206680&r2=206681&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h Fri Apr 18 22:54:41 2014
> @@ -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<IntegerLiteral>(CE)->getValue().toString(10, true);
> + return;
> + case Stmt::StringLiteralClass:
> + SS << "\"" << cast<StringLiteral>(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 << ")";
> }
>
> Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=206681&r1=206680&r2=206681&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
> +++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Fri Apr 18 22:54:41 2014
> @@ -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<Variable>(E)) {
> + SExpr *D;
> + do {
> + if (V->kind() != Variable::VK_Let)
> + return V;
> + D = V->definition();
> + if (auto *V2 = dyn_cast<Variable>(D)) {
> + V = V2;
> + continue;
> + }
> + } while(false);
> +
> + if (ThreadSafetyTIL::isTrivial(D))
> + return D;
> +
> + if (Phi *Ph = dyn_cast<Phi>(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(); i<n; ++i) {
> + SExpr *Ei = getCanonicalVal(Ph->values()[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(
> }
>
>
> -// 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<til::Variable>(E)) {
> - if (til::Phi *Ph = dyn_cast<til::Phi>(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(unsign
> 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(unsign
> 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 CF
>
>
> void SExprBuilder::exitCFG(const CFGBlock *Last) {
> + for (auto *V : IncompleteArgs) {
> + til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
> + if (Ph && Ph->status() == til::Phi::PH_Incomplete)
> + simplifyIncompleteArg(V, Ph);
> + }
> +
> CurrentArguments.clear();
> CurrentInstructions.clear();
> + IncompleteArgs.clear();
> }
>
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
~Aaron
More information about the cfe-commits
mailing list