mirror of
https://github.com/intel/llvm.git
synced 2026-02-06 15:18:53 +08:00
Thread Safety Analysis: Convert to minimal SSA.
llvm-svn: 206681
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
void simplifyIncompleteArg(Variable *V, til::Phi *Ph);
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace til
|
||||
} // end namespace threadSafety
|
||||
} // end namespace clang
|
||||
|
||||
@@ -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 << ")";
|
||||
}
|
||||
|
||||
@@ -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(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<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(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<til::Phi>(V->definition());
|
||||
if (Ph && Ph->status() == til::Phi::PH_Incomplete)
|
||||
simplifyIncompleteArg(V, Ph);
|
||||
}
|
||||
|
||||
CurrentArguments.clear();
|
||||
CurrentInstructions.clear();
|
||||
IncompleteArgs.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user