//===- ThreadSafetyTIL.cpp -------------------------------------*- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT in the llvm repository for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
namespace clang {
namespace threadSafety {
namespace til {
StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) {
switch (Op) {
case UOP_Minus: return "-";
case UOP_BitNot: return "~";
case UOP_LogicNot: return "!";
}
return "";
}
StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) {
switch (Op) {
case BOP_Mul: return "*";
case BOP_Div: return "/";
case BOP_Rem: return "%";
case BOP_Add: return "+";
case BOP_Sub: return "-";
case BOP_Shl: return "<<";
case BOP_Shr: return ">>";
case BOP_BitAnd: return "&";
case BOP_BitXor: return "^";
case BOP_BitOr: return "|";
case BOP_Eq: return "==";
case BOP_Neq: return "!=";
case BOP_Lt: return "<";
case BOP_Leq: return "<=";
case BOP_LogicAnd: return "&&";
case BOP_LogicOr: return "||";
}
return "";
}
unsigned BasicBlock::addPredecessor(BasicBlock *Pred) {
unsigned Idx = Predecessors.size();
Predecessors.reserveCheck(1, Arena);
Predecessors.push_back(Pred);
for (Variable *V : Args) {
if (Phi* Ph = dyn_cast<Phi>(V->definition())) {
Ph->values().reserveCheck(1, Arena);
Ph->values().push_back(nullptr);
}
}
return Idx;
}
void BasicBlock::reservePredecessors(unsigned NumPreds) {
Predecessors.reserve(NumPreds, Arena);
for (Variable *V : Args) {
if (Phi* Ph = dyn_cast<Phi>(V->definition())) {
Ph->values().reserve(NumPreds, Arena);
}
}
}
void BasicBlock::renumberVars() {
unsigned VID = 0;
for (Variable *V : Args) {
V->setID(BlockID, VID++);
}
for (Variable *V : Instrs) {
V->setID(BlockID, VID++);
}
}
void SCFG::renumberVars() {
for (BasicBlock *B : Blocks) {
B->renumberVars();
}
}
// 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();
auto *V2 = dyn_cast<Variable>(D);
if (V2)
V = V2;
else
break;
} while (true);
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);
// Eliminate Redundant Phi node.
V->setDefinition(Ph->values()[0]);
}
} // end namespace til
} // end namespace threadSafety
} // end namespace clang