r206681 - Thread Safety Analysis: Convert to minimal SSA.

Delesley Hutchins delesley at google.com
Wed Apr 23 11:16:15 PDT 2014


I need to make a ThreadSafetyTIL.cpp, and move some of this stuff
there.  Future patch.

  -DeLesley

On Wed, Apr 23, 2014 at 7:27 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
> 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



-- 
DeLesley Hutchins | Software Engineer | delesley at google.com | 505-206-0315



More information about the cfe-commits mailing list