Thread safety analysis: misc updates to SExpr handling. Fix to minimal SSA,
function parameters, and compound assignment.
llvm-svn: 206827
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index eae2552..cf9a7b8 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -47,11 +47,12 @@
if (V->kind() != Variable::VK_Let)
return V;
D = V->definition();
- if (auto *V2 = dyn_cast<Variable>(D)) {
+ auto *V2 = dyn_cast<Variable>(D);
+ if (V2)
V = V2;
- continue;
- }
- } while(false);
+ else
+ break;
+ } while (true);
if (ThreadSafetyTIL::isTrivial(D))
return D;
@@ -75,7 +76,7 @@
// 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);
+ assert(Ph && Ph->status() == Phi::PH_Incomplete);
// eliminate infinite recursion -- assume that this node is not redundant.
Ph->setStatus(Phi::PH_MultiVal);
@@ -90,8 +91,21 @@
}
}
Ph->setStatus(Phi::PH_SingleVal);
+ // Eliminate Redundant Phi node.
+ V->setDefinition(Ph->values()[0]);
}
+
+// Return true if E is a variable that points to an incomplete Phi node.
+inline bool isIncompleteVar(SExpr *E) {
+ if (Variable *V = dyn_cast<Variable>(E)) {
+ if (Phi *Ph = dyn_cast<Phi>(V->definition()))
+ return Ph->status() == Phi::PH_Incomplete;
+ }
+ return false;
+}
+
+
} // end namespace til
@@ -140,6 +154,7 @@
case Stmt::UnaryOperatorClass:
return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
case Stmt::BinaryOperatorClass:
+ case Stmt::CompoundAssignOperatorClass:
return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
case Stmt::ArraySubscriptExprClass:
@@ -277,6 +292,32 @@
}
+til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx) {
+ const Expr *LHS = BO->getLHS();
+ const Expr *RHS = BO->getRHS();
+ til::SExpr *E0 = translate(LHS, Ctx);
+ til::SExpr *E1 = translate(RHS, Ctx);
+
+ const ValueDecl *VD = nullptr;
+ til::SExpr *CV = nullptr;
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
+ VD = DRE->getDecl();
+ CV = lookupVarDecl(VD);
+ }
+
+ if (Op != BO_Assign) {
+ til::SExpr *Arg = CV ? CV : new (Arena) til::Load(E0);
+ E1 = new (Arena) til::BinaryOp(Op, Arg, E1);
+ E1 = addStatement(E1, nullptr, VD);
+ }
+ if (VD && CV)
+ return updateVarDecl(VD, E1);
+ return new (Arena) til::Store(E0, E1);
+}
+
+
til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
CallingContext *Ctx) {
switch (BO->getOpcode()) {
@@ -306,35 +347,24 @@
til::BinaryOp(BO->getOpcode(), translate(BO->getLHS(), Ctx),
translate(BO->getRHS(), Ctx));
- case BO_Assign: {
- const Expr *LHS = BO->getLHS();
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
- const Expr *RHS = BO->getRHS();
- til::SExpr *E1 = translate(RHS, Ctx);
- return updateVarDecl(DRE->getDecl(), E1);
- }
- til::SExpr *E0 = translate(LHS, Ctx);
- til::SExpr *E1 = translate(BO->getRHS(), Ctx);
- return new (Arena) til::Store(E0, E1);
- }
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_RemAssign:
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_AndAssign:
- case BO_XorAssign:
- case BO_OrAssign:
- return new (Arena) til::Undefined(BO);
+ case BO_Assign: return translateBinAssign(BO_Assign, BO, Ctx);
+ case BO_MulAssign: return translateBinAssign(BO_Mul, BO, Ctx);
+ case BO_DivAssign: return translateBinAssign(BO_Div, BO, Ctx);
+ case BO_RemAssign: return translateBinAssign(BO_Rem, BO, Ctx);
+ case BO_AddAssign: return translateBinAssign(BO_Add, BO, Ctx);
+ case BO_SubAssign: return translateBinAssign(BO_Sub, BO, Ctx);
+ case BO_ShlAssign: return translateBinAssign(BO_Shl, BO, Ctx);
+ case BO_ShrAssign: return translateBinAssign(BO_Shr, BO, Ctx);
+ case BO_AndAssign: return translateBinAssign(BO_And, BO, Ctx);
+ case BO_XorAssign: return translateBinAssign(BO_Xor, BO, Ctx);
+ case BO_OrAssign: return translateBinAssign(BO_Or, BO, Ctx);
case BO_Comma:
- // TODO: handle LHS
+ // The clang CFG should have already processed both sides.
return translate(BO->getRHS(), Ctx);
- }
return new (Arena) til::Undefined(BO);
+ }
}
@@ -495,14 +525,16 @@
// Make a new phi node: phi(..., E)
// All phi args up to the current index are set to the current value.
+ til::SExpr *CurrE = CurrentLVarMap[i].second;
til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
Ph->values().setValues(NPreds, nullptr);
for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
- Ph->values()[PIdx] = CurrentLVarMap[i].second;
+ Ph->values()[PIdx] = CurrE;
if (E)
Ph->values()[ArgIndex] = E;
- if (!E) {
- // This is a non-minimal SSA node, which may be removed later.
+ // If E is from a back-edge, or either E or CurrE are incomplete, then
+ // mark this node as incomplete; we may need to remove it later.
+ if (!E || isIncompleteVar(E) || isIncompleteVar(CurrE)) {
Ph->setStatus(til::Phi::PH_Incomplete);
}
@@ -601,8 +633,7 @@
}
-
-void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
+void SExprBuilder::enterCFG(CFG *Cfg, const FunctionDecl *FD,
const CFGBlock *First) {
// Perform initial setup operations.
unsigned NBlocks = Cfg->getNumBlockIDs();
@@ -616,22 +647,35 @@
auto *BB = new (Arena) til::BasicBlock(Arena, 0, B->size());
BlockMap[B->getBlockID()] = BB;
}
- CallCtx = new SExprBuilder::CallingContext(D);
+ CallCtx = new SExprBuilder::CallingContext(FD);
+
+ CurrentBB = lookupBlock(&Cfg->getEntry());
+ for (auto *Pm : FD->parameters()) {
+ QualType T = Pm->getType();
+ if (!T.isTrivialType(Pm->getASTContext()))
+ continue;
+
+ // Add parameters to local variable map.
+ // FIXME: right now we emulate params with loads; that should be fixed.
+ til::SExpr *Lp = new (Arena) til::LiteralPtr(Pm);
+ til::SExpr *Ld = new (Arena) til::Load(Lp);
+ til::SExpr *V = addStatement(Ld, nullptr, Pm);
+ addVarDecl(Pm, V);
+ }
}
void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
// Intialize TIL basic block and add it to the CFG.
- CurrentBB = BlockMap[B->getBlockID()];
+ CurrentBB = lookupBlock(B);
CurrentBB->setNumPredecessors(B->pred_size());
Scfg->add(CurrentBB);
CurrentBlockInfo = &BBInfo[B->getBlockID()];
- CurrentArguments.clear();
- CurrentInstructions.clear();
// CurrentLVarMap is moved to ExitMap on block exit.
- assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
+ // FIXME: the entry block will hold function parameters.
+ // assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
}
@@ -721,6 +765,8 @@
void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);
CurrentBB = nullptr;
CurrentBlockInfo = nullptr;