Path: blob/main/contrib/llvm-project/clang/lib/Analysis/ThreadSafetyCommon.cpp
35233 views
//===- ThreadSafetyCommon.cpp ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Implementation of the interfaces declared in ThreadSafetyCommon.h9//10//===----------------------------------------------------------------------===//1112#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"13#include "clang/AST/Attr.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclCXX.h"16#include "clang/AST/DeclGroup.h"17#include "clang/AST/DeclObjC.h"18#include "clang/AST/Expr.h"19#include "clang/AST/ExprCXX.h"20#include "clang/AST/OperationKinds.h"21#include "clang/AST/Stmt.h"22#include "clang/AST/Type.h"23#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"24#include "clang/Analysis/CFG.h"25#include "clang/Basic/LLVM.h"26#include "clang/Basic/OperatorKinds.h"27#include "clang/Basic/Specifiers.h"28#include "llvm/ADT/StringExtras.h"29#include "llvm/ADT/StringRef.h"30#include "llvm/Support/Casting.h"31#include <algorithm>32#include <cassert>33#include <string>34#include <utility>3536using namespace clang;37using namespace threadSafety;3839// From ThreadSafetyUtil.h40std::string threadSafety::getSourceLiteralString(const Expr *CE) {41switch (CE->getStmtClass()) {42case Stmt::IntegerLiteralClass:43return toString(cast<IntegerLiteral>(CE)->getValue(), 10, true);44case Stmt::StringLiteralClass: {45std::string ret("\"");46ret += cast<StringLiteral>(CE)->getString();47ret += "\"";48return ret;49}50case Stmt::CharacterLiteralClass:51case Stmt::CXXNullPtrLiteralExprClass:52case Stmt::GNUNullExprClass:53case Stmt::CXXBoolLiteralExprClass:54case Stmt::FloatingLiteralClass:55case Stmt::ImaginaryLiteralClass:56case Stmt::ObjCStringLiteralClass:57default:58return "#lit";59}60}6162// Return true if E is a variable that points to an incomplete Phi node.63static bool isIncompletePhi(const til::SExpr *E) {64if (const auto *Ph = dyn_cast<til::Phi>(E))65return Ph->status() == til::Phi::PH_Incomplete;66return false;67}6869using CallingContext = SExprBuilder::CallingContext;7071til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) { return SMap.lookup(S); }7273til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {74Walker.walk(*this);75return Scfg;76}7778static bool isCalleeArrow(const Expr *E) {79const auto *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());80return ME ? ME->isArrow() : false;81}8283static StringRef ClassifyDiagnostic(const CapabilityAttr *A) {84return A->getName();85}8687static StringRef ClassifyDiagnostic(QualType VDT) {88// We need to look at the declaration of the type of the value to determine89// which it is. The type should either be a record or a typedef, or a pointer90// or reference thereof.91if (const auto *RT = VDT->getAs<RecordType>()) {92if (const auto *RD = RT->getDecl())93if (const auto *CA = RD->getAttr<CapabilityAttr>())94return ClassifyDiagnostic(CA);95} else if (const auto *TT = VDT->getAs<TypedefType>()) {96if (const auto *TD = TT->getDecl())97if (const auto *CA = TD->getAttr<CapabilityAttr>())98return ClassifyDiagnostic(CA);99} else if (VDT->isPointerType() || VDT->isReferenceType())100return ClassifyDiagnostic(VDT->getPointeeType());101102return "mutex";103}104105/// Translate a clang expression in an attribute to a til::SExpr.106/// Constructs the context from D, DeclExp, and SelfDecl.107///108/// \param AttrExp The expression to translate.109/// \param D The declaration to which the attribute is attached.110/// \param DeclExp An expression involving the Decl to which the attribute111/// is attached. E.g. the call to a function.112/// \param Self S-expression to substitute for a \ref CXXThisExpr in a call,113/// or argument to a cleanup function.114CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,115const NamedDecl *D,116const Expr *DeclExp,117til::SExpr *Self) {118// If we are processing a raw attribute expression, with no substitutions.119if (!DeclExp && !Self)120return translateAttrExpr(AttrExp, nullptr);121122CallingContext Ctx(nullptr, D);123124// Examine DeclExp to find SelfArg and FunArgs, which are used to substitute125// for formal parameters when we call buildMutexID later.126if (!DeclExp)127/* We'll use Self. */;128else if (const auto *ME = dyn_cast<MemberExpr>(DeclExp)) {129Ctx.SelfArg = ME->getBase();130Ctx.SelfArrow = ME->isArrow();131} else if (const auto *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {132Ctx.SelfArg = CE->getImplicitObjectArgument();133Ctx.SelfArrow = isCalleeArrow(CE->getCallee());134Ctx.NumArgs = CE->getNumArgs();135Ctx.FunArgs = CE->getArgs();136} else if (const auto *CE = dyn_cast<CallExpr>(DeclExp)) {137Ctx.NumArgs = CE->getNumArgs();138Ctx.FunArgs = CE->getArgs();139} else if (const auto *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {140Ctx.SelfArg = nullptr; // Will be set below141Ctx.NumArgs = CE->getNumArgs();142Ctx.FunArgs = CE->getArgs();143}144145if (Self) {146assert(!Ctx.SelfArg && "Ambiguous self argument");147assert(isa<FunctionDecl>(D) && "Self argument requires function");148if (isa<CXXMethodDecl>(D))149Ctx.SelfArg = Self;150else151Ctx.FunArgs = Self;152153// If the attribute has no arguments, then assume the argument is "this".154if (!AttrExp)155return CapabilityExpr(156Self,157ClassifyDiagnostic(158cast<CXXMethodDecl>(D)->getFunctionObjectParameterType()),159false);160else // For most attributes.161return translateAttrExpr(AttrExp, &Ctx);162}163164// If the attribute has no arguments, then assume the argument is "this".165if (!AttrExp)166return translateAttrExpr(cast<const Expr *>(Ctx.SelfArg), nullptr);167else // For most attributes.168return translateAttrExpr(AttrExp, &Ctx);169}170171/// Translate a clang expression in an attribute to a til::SExpr.172// This assumes a CallingContext has already been created.173CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,174CallingContext *Ctx) {175if (!AttrExp)176return CapabilityExpr();177178if (const auto* SLit = dyn_cast<StringLiteral>(AttrExp)) {179if (SLit->getString() == "*")180// The "*" expr is a universal lock, which essentially turns off181// checks until it is removed from the lockset.182return CapabilityExpr(new (Arena) til::Wildcard(), StringRef("wildcard"),183false);184else185// Ignore other string literals for now.186return CapabilityExpr();187}188189bool Neg = false;190if (const auto *OE = dyn_cast<CXXOperatorCallExpr>(AttrExp)) {191if (OE->getOperator() == OO_Exclaim) {192Neg = true;193AttrExp = OE->getArg(0);194}195}196else if (const auto *UO = dyn_cast<UnaryOperator>(AttrExp)) {197if (UO->getOpcode() == UO_LNot) {198Neg = true;199AttrExp = UO->getSubExpr()->IgnoreImplicit();200}201}202203til::SExpr *E = translate(AttrExp, Ctx);204205// Trap mutex expressions like nullptr, or 0.206// Any literal value is nonsense.207if (!E || isa<til::Literal>(E))208return CapabilityExpr();209210StringRef Kind = ClassifyDiagnostic(AttrExp->getType());211212// Hack to deal with smart pointers -- strip off top-level pointer casts.213if (const auto *CE = dyn_cast<til::Cast>(E)) {214if (CE->castOpcode() == til::CAST_objToPtr)215return CapabilityExpr(CE->expr(), Kind, Neg);216}217return CapabilityExpr(E, Kind, Neg);218}219220til::LiteralPtr *SExprBuilder::createVariable(const VarDecl *VD) {221return new (Arena) til::LiteralPtr(VD);222}223224std::pair<til::LiteralPtr *, StringRef>225SExprBuilder::createThisPlaceholder(const Expr *Exp) {226return {new (Arena) til::LiteralPtr(nullptr),227ClassifyDiagnostic(Exp->getType())};228}229230// Translate a clang statement or expression to a TIL expression.231// Also performs substitution of variables; Ctx provides the context.232// Dispatches on the type of S.233til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {234if (!S)235return nullptr;236237// Check if S has already been translated and cached.238// This handles the lookup of SSA names for DeclRefExprs here.239if (til::SExpr *E = lookupStmt(S))240return E;241242switch (S->getStmtClass()) {243case Stmt::DeclRefExprClass:244return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);245case Stmt::CXXThisExprClass:246return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);247case Stmt::MemberExprClass:248return translateMemberExpr(cast<MemberExpr>(S), Ctx);249case Stmt::ObjCIvarRefExprClass:250return translateObjCIVarRefExpr(cast<ObjCIvarRefExpr>(S), Ctx);251case Stmt::CallExprClass:252return translateCallExpr(cast<CallExpr>(S), Ctx);253case Stmt::CXXMemberCallExprClass:254return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);255case Stmt::CXXOperatorCallExprClass:256return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);257case Stmt::UnaryOperatorClass:258return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);259case Stmt::BinaryOperatorClass:260case Stmt::CompoundAssignOperatorClass:261return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);262263case Stmt::ArraySubscriptExprClass:264return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);265case Stmt::ConditionalOperatorClass:266return translateAbstractConditionalOperator(267cast<ConditionalOperator>(S), Ctx);268case Stmt::BinaryConditionalOperatorClass:269return translateAbstractConditionalOperator(270cast<BinaryConditionalOperator>(S), Ctx);271272// We treat these as no-ops273case Stmt::ConstantExprClass:274return translate(cast<ConstantExpr>(S)->getSubExpr(), Ctx);275case Stmt::ParenExprClass:276return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);277case Stmt::ExprWithCleanupsClass:278return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);279case Stmt::CXXBindTemporaryExprClass:280return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);281case Stmt::MaterializeTemporaryExprClass:282return translate(cast<MaterializeTemporaryExpr>(S)->getSubExpr(), Ctx);283284// Collect all literals285case Stmt::CharacterLiteralClass:286case Stmt::CXXNullPtrLiteralExprClass:287case Stmt::GNUNullExprClass:288case Stmt::CXXBoolLiteralExprClass:289case Stmt::FloatingLiteralClass:290case Stmt::ImaginaryLiteralClass:291case Stmt::IntegerLiteralClass:292case Stmt::StringLiteralClass:293case Stmt::ObjCStringLiteralClass:294return new (Arena) til::Literal(cast<Expr>(S));295296case Stmt::DeclStmtClass:297return translateDeclStmt(cast<DeclStmt>(S), Ctx);298default:299break;300}301if (const auto *CE = dyn_cast<CastExpr>(S))302return translateCastExpr(CE, Ctx);303304return new (Arena) til::Undefined(S);305}306307til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,308CallingContext *Ctx) {309const auto *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());310311// Function parameters require substitution and/or renaming.312if (const auto *PV = dyn_cast<ParmVarDecl>(VD)) {313unsigned I = PV->getFunctionScopeIndex();314const DeclContext *D = PV->getDeclContext();315if (Ctx && Ctx->FunArgs) {316const Decl *Canonical = Ctx->AttrDecl->getCanonicalDecl();317if (isa<FunctionDecl>(D)318? (cast<FunctionDecl>(D)->getCanonicalDecl() == Canonical)319: (cast<ObjCMethodDecl>(D)->getCanonicalDecl() == Canonical)) {320// Substitute call arguments for references to function parameters321if (const Expr *const *FunArgs =322Ctx->FunArgs.dyn_cast<const Expr *const *>()) {323assert(I < Ctx->NumArgs);324return translate(FunArgs[I], Ctx->Prev);325}326327assert(I == 0);328return Ctx->FunArgs.get<til::SExpr *>();329}330}331// Map the param back to the param of the original function declaration332// for consistent comparisons.333VD = isa<FunctionDecl>(D)334? cast<FunctionDecl>(D)->getCanonicalDecl()->getParamDecl(I)335: cast<ObjCMethodDecl>(D)->getCanonicalDecl()->getParamDecl(I);336}337338// For non-local variables, treat it as a reference to a named object.339return new (Arena) til::LiteralPtr(VD);340}341342til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,343CallingContext *Ctx) {344// Substitute for 'this'345if (Ctx && Ctx->SelfArg) {346if (const auto *SelfArg = dyn_cast<const Expr *>(Ctx->SelfArg))347return translate(SelfArg, Ctx->Prev);348else349return cast<til::SExpr *>(Ctx->SelfArg);350}351assert(SelfVar && "We have no variable for 'this'!");352return SelfVar;353}354355static const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {356if (const auto *V = dyn_cast<til::Variable>(E))357return V->clangDecl();358if (const auto *Ph = dyn_cast<til::Phi>(E))359return Ph->clangDecl();360if (const auto *P = dyn_cast<til::Project>(E))361return P->clangDecl();362if (const auto *L = dyn_cast<til::LiteralPtr>(E))363return L->clangDecl();364return nullptr;365}366367static bool hasAnyPointerType(const til::SExpr *E) {368auto *VD = getValueDeclFromSExpr(E);369if (VD && VD->getType()->isAnyPointerType())370return true;371if (const auto *C = dyn_cast<til::Cast>(E))372return C->castOpcode() == til::CAST_objToPtr;373374return false;375}376377// Grab the very first declaration of virtual method D378static const CXXMethodDecl *getFirstVirtualDecl(const CXXMethodDecl *D) {379while (true) {380D = D->getCanonicalDecl();381auto OverriddenMethods = D->overridden_methods();382if (OverriddenMethods.begin() == OverriddenMethods.end())383return D; // Method does not override anything384// FIXME: this does not work with multiple inheritance.385D = *OverriddenMethods.begin();386}387return nullptr;388}389390til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,391CallingContext *Ctx) {392til::SExpr *BE = translate(ME->getBase(), Ctx);393til::SExpr *E = new (Arena) til::SApply(BE);394395const auto *D = cast<ValueDecl>(ME->getMemberDecl()->getCanonicalDecl());396if (const auto *VD = dyn_cast<CXXMethodDecl>(D))397D = getFirstVirtualDecl(VD);398399til::Project *P = new (Arena) til::Project(E, D);400if (hasAnyPointerType(BE))401P->setArrow(true);402return P;403}404405til::SExpr *SExprBuilder::translateObjCIVarRefExpr(const ObjCIvarRefExpr *IVRE,406CallingContext *Ctx) {407til::SExpr *BE = translate(IVRE->getBase(), Ctx);408til::SExpr *E = new (Arena) til::SApply(BE);409410const auto *D = cast<ObjCIvarDecl>(IVRE->getDecl()->getCanonicalDecl());411412til::Project *P = new (Arena) til::Project(E, D);413if (hasAnyPointerType(BE))414P->setArrow(true);415return P;416}417418til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,419CallingContext *Ctx,420const Expr *SelfE) {421if (CapabilityExprMode) {422// Handle LOCK_RETURNED423if (const FunctionDecl *FD = CE->getDirectCallee()) {424FD = FD->getMostRecentDecl();425if (LockReturnedAttr *At = FD->getAttr<LockReturnedAttr>()) {426CallingContext LRCallCtx(Ctx);427LRCallCtx.AttrDecl = CE->getDirectCallee();428LRCallCtx.SelfArg = SelfE;429LRCallCtx.NumArgs = CE->getNumArgs();430LRCallCtx.FunArgs = CE->getArgs();431return const_cast<til::SExpr *>(432translateAttrExpr(At->getArg(), &LRCallCtx).sexpr());433}434}435}436437til::SExpr *E = translate(CE->getCallee(), Ctx);438for (const auto *Arg : CE->arguments()) {439til::SExpr *A = translate(Arg, Ctx);440E = new (Arena) til::Apply(E, A);441}442return new (Arena) til::Call(E, CE);443}444445til::SExpr *SExprBuilder::translateCXXMemberCallExpr(446const CXXMemberCallExpr *ME, CallingContext *Ctx) {447if (CapabilityExprMode) {448// Ignore calls to get() on smart pointers.449if (ME->getMethodDecl()->getNameAsString() == "get" &&450ME->getNumArgs() == 0) {451auto *E = translate(ME->getImplicitObjectArgument(), Ctx);452return new (Arena) til::Cast(til::CAST_objToPtr, E);453// return E;454}455}456return translateCallExpr(cast<CallExpr>(ME), Ctx,457ME->getImplicitObjectArgument());458}459460til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(461const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {462if (CapabilityExprMode) {463// Ignore operator * and operator -> on smart pointers.464OverloadedOperatorKind k = OCE->getOperator();465if (k == OO_Star || k == OO_Arrow) {466auto *E = translate(OCE->getArg(0), Ctx);467return new (Arena) til::Cast(til::CAST_objToPtr, E);468// return E;469}470}471return translateCallExpr(cast<CallExpr>(OCE), Ctx);472}473474til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,475CallingContext *Ctx) {476switch (UO->getOpcode()) {477case UO_PostInc:478case UO_PostDec:479case UO_PreInc:480case UO_PreDec:481return new (Arena) til::Undefined(UO);482483case UO_AddrOf:484if (CapabilityExprMode) {485// interpret &Graph::mu_ as an existential.486if (const auto *DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {487if (DRE->getDecl()->isCXXInstanceMember()) {488// This is a pointer-to-member expression, e.g. &MyClass::mu_.489// We interpret this syntax specially, as a wildcard.490auto *W = new (Arena) til::Wildcard();491return new (Arena) til::Project(W, DRE->getDecl());492}493}494}495// otherwise, & is a no-op496return translate(UO->getSubExpr(), Ctx);497498// We treat these as no-ops499case UO_Deref:500case UO_Plus:501return translate(UO->getSubExpr(), Ctx);502503case UO_Minus:504return new (Arena)505til::UnaryOp(til::UOP_Minus, translate(UO->getSubExpr(), Ctx));506case UO_Not:507return new (Arena)508til::UnaryOp(til::UOP_BitNot, translate(UO->getSubExpr(), Ctx));509case UO_LNot:510return new (Arena)511til::UnaryOp(til::UOP_LogicNot, translate(UO->getSubExpr(), Ctx));512513// Currently unsupported514case UO_Real:515case UO_Imag:516case UO_Extension:517case UO_Coawait:518return new (Arena) til::Undefined(UO);519}520return new (Arena) til::Undefined(UO);521}522523til::SExpr *SExprBuilder::translateBinOp(til::TIL_BinaryOpcode Op,524const BinaryOperator *BO,525CallingContext *Ctx, bool Reverse) {526til::SExpr *E0 = translate(BO->getLHS(), Ctx);527til::SExpr *E1 = translate(BO->getRHS(), Ctx);528if (Reverse)529return new (Arena) til::BinaryOp(Op, E1, E0);530else531return new (Arena) til::BinaryOp(Op, E0, E1);532}533534til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,535const BinaryOperator *BO,536CallingContext *Ctx,537bool Assign) {538const Expr *LHS = BO->getLHS();539const Expr *RHS = BO->getRHS();540til::SExpr *E0 = translate(LHS, Ctx);541til::SExpr *E1 = translate(RHS, Ctx);542543const ValueDecl *VD = nullptr;544til::SExpr *CV = nullptr;545if (const auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {546VD = DRE->getDecl();547CV = lookupVarDecl(VD);548}549550if (!Assign) {551til::SExpr *Arg = CV ? CV : new (Arena) til::Load(E0);552E1 = new (Arena) til::BinaryOp(Op, Arg, E1);553E1 = addStatement(E1, nullptr, VD);554}555if (VD && CV)556return updateVarDecl(VD, E1);557return new (Arena) til::Store(E0, E1);558}559560til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,561CallingContext *Ctx) {562switch (BO->getOpcode()) {563case BO_PtrMemD:564case BO_PtrMemI:565return new (Arena) til::Undefined(BO);566567case BO_Mul: return translateBinOp(til::BOP_Mul, BO, Ctx);568case BO_Div: return translateBinOp(til::BOP_Div, BO, Ctx);569case BO_Rem: return translateBinOp(til::BOP_Rem, BO, Ctx);570case BO_Add: return translateBinOp(til::BOP_Add, BO, Ctx);571case BO_Sub: return translateBinOp(til::BOP_Sub, BO, Ctx);572case BO_Shl: return translateBinOp(til::BOP_Shl, BO, Ctx);573case BO_Shr: return translateBinOp(til::BOP_Shr, BO, Ctx);574case BO_LT: return translateBinOp(til::BOP_Lt, BO, Ctx);575case BO_GT: return translateBinOp(til::BOP_Lt, BO, Ctx, true);576case BO_LE: return translateBinOp(til::BOP_Leq, BO, Ctx);577case BO_GE: return translateBinOp(til::BOP_Leq, BO, Ctx, true);578case BO_EQ: return translateBinOp(til::BOP_Eq, BO, Ctx);579case BO_NE: return translateBinOp(til::BOP_Neq, BO, Ctx);580case BO_Cmp: return translateBinOp(til::BOP_Cmp, BO, Ctx);581case BO_And: return translateBinOp(til::BOP_BitAnd, BO, Ctx);582case BO_Xor: return translateBinOp(til::BOP_BitXor, BO, Ctx);583case BO_Or: return translateBinOp(til::BOP_BitOr, BO, Ctx);584case BO_LAnd: return translateBinOp(til::BOP_LogicAnd, BO, Ctx);585case BO_LOr: return translateBinOp(til::BOP_LogicOr, BO, Ctx);586587case BO_Assign: return translateBinAssign(til::BOP_Eq, BO, Ctx, true);588case BO_MulAssign: return translateBinAssign(til::BOP_Mul, BO, Ctx);589case BO_DivAssign: return translateBinAssign(til::BOP_Div, BO, Ctx);590case BO_RemAssign: return translateBinAssign(til::BOP_Rem, BO, Ctx);591case BO_AddAssign: return translateBinAssign(til::BOP_Add, BO, Ctx);592case BO_SubAssign: return translateBinAssign(til::BOP_Sub, BO, Ctx);593case BO_ShlAssign: return translateBinAssign(til::BOP_Shl, BO, Ctx);594case BO_ShrAssign: return translateBinAssign(til::BOP_Shr, BO, Ctx);595case BO_AndAssign: return translateBinAssign(til::BOP_BitAnd, BO, Ctx);596case BO_XorAssign: return translateBinAssign(til::BOP_BitXor, BO, Ctx);597case BO_OrAssign: return translateBinAssign(til::BOP_BitOr, BO, Ctx);598599case BO_Comma:600// The clang CFG should have already processed both sides.601return translate(BO->getRHS(), Ctx);602}603return new (Arena) til::Undefined(BO);604}605606til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,607CallingContext *Ctx) {608CastKind K = CE->getCastKind();609switch (K) {610case CK_LValueToRValue: {611if (const auto *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {612til::SExpr *E0 = lookupVarDecl(DRE->getDecl());613if (E0)614return E0;615}616til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);617return E0;618// FIXME!! -- get Load working properly619// return new (Arena) til::Load(E0);620}621case CK_NoOp:622case CK_DerivedToBase:623case CK_UncheckedDerivedToBase:624case CK_ArrayToPointerDecay:625case CK_FunctionToPointerDecay: {626til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);627return E0;628}629default: {630// FIXME: handle different kinds of casts.631til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);632if (CapabilityExprMode)633return E0;634return new (Arena) til::Cast(til::CAST_none, E0);635}636}637}638639til::SExpr *640SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,641CallingContext *Ctx) {642til::SExpr *E0 = translate(E->getBase(), Ctx);643til::SExpr *E1 = translate(E->getIdx(), Ctx);644return new (Arena) til::ArrayIndex(E0, E1);645}646647til::SExpr *648SExprBuilder::translateAbstractConditionalOperator(649const AbstractConditionalOperator *CO, CallingContext *Ctx) {650auto *C = translate(CO->getCond(), Ctx);651auto *T = translate(CO->getTrueExpr(), Ctx);652auto *E = translate(CO->getFalseExpr(), Ctx);653return new (Arena) til::IfThenElse(C, T, E);654}655656til::SExpr *657SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {658DeclGroupRef DGrp = S->getDeclGroup();659for (auto *I : DGrp) {660if (auto *VD = dyn_cast_or_null<VarDecl>(I)) {661Expr *E = VD->getInit();662til::SExpr* SE = translate(E, Ctx);663664// Add local variables with trivial type to the variable map665QualType T = VD->getType();666if (T.isTrivialType(VD->getASTContext()))667return addVarDecl(VD, SE);668else {669// TODO: add alloca670}671}672}673return nullptr;674}675676// If (E) is non-trivial, then add it to the current basic block, and677// update the statement map so that S refers to E. Returns a new variable678// that refers to E.679// If E is trivial returns E.680til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,681const ValueDecl *VD) {682if (!E || !CurrentBB || E->block() || til::ThreadSafetyTIL::isTrivial(E))683return E;684if (VD)685E = new (Arena) til::Variable(E, VD);686CurrentInstructions.push_back(E);687if (S)688insertStmt(S, E);689return E;690}691692// Returns the current value of VD, if known, and nullptr otherwise.693til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {694auto It = LVarIdxMap.find(VD);695if (It != LVarIdxMap.end()) {696assert(CurrentLVarMap[It->second].first == VD);697return CurrentLVarMap[It->second].second;698}699return nullptr;700}701702// if E is a til::Variable, update its clangDecl.703static void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {704if (!E)705return;706if (auto *V = dyn_cast<til::Variable>(E)) {707if (!V->clangDecl())708V->setClangDecl(VD);709}710}711712// Adds a new variable declaration.713til::SExpr *SExprBuilder::addVarDecl(const ValueDecl *VD, til::SExpr *E) {714maybeUpdateVD(E, VD);715LVarIdxMap.insert(std::make_pair(VD, CurrentLVarMap.size()));716CurrentLVarMap.makeWritable();717CurrentLVarMap.push_back(std::make_pair(VD, E));718return E;719}720721// Updates a current variable declaration. (E.g. by assignment)722til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *E) {723maybeUpdateVD(E, VD);724auto It = LVarIdxMap.find(VD);725if (It == LVarIdxMap.end()) {726til::SExpr *Ptr = new (Arena) til::LiteralPtr(VD);727til::SExpr *St = new (Arena) til::Store(Ptr, E);728return St;729}730CurrentLVarMap.makeWritable();731CurrentLVarMap.elem(It->second).second = E;732return E;733}734735// Make a Phi node in the current block for the i^th variable in CurrentVarMap.736// If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E.737// If E == null, this is a backedge and will be set later.738void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {739unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;740assert(ArgIndex > 0 && ArgIndex < NPreds);741742til::SExpr *CurrE = CurrentLVarMap[i].second;743if (CurrE->block() == CurrentBB) {744// We already have a Phi node in the current block,745// so just add the new variable to the Phi node.746auto *Ph = dyn_cast<til::Phi>(CurrE);747assert(Ph && "Expecting Phi node.");748if (E)749Ph->values()[ArgIndex] = E;750return;751}752753// Make a new phi node: phi(..., E)754// All phi args up to the current index are set to the current value.755til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);756Ph->values().setValues(NPreds, nullptr);757for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)758Ph->values()[PIdx] = CurrE;759if (E)760Ph->values()[ArgIndex] = E;761Ph->setClangDecl(CurrentLVarMap[i].first);762// If E is from a back-edge, or either E or CurrE are incomplete, then763// mark this node as incomplete; we may need to remove it later.764if (!E || isIncompletePhi(E) || isIncompletePhi(CurrE))765Ph->setStatus(til::Phi::PH_Incomplete);766767// Add Phi node to current block, and update CurrentLVarMap[i]768CurrentArguments.push_back(Ph);769if (Ph->status() == til::Phi::PH_Incomplete)770IncompleteArgs.push_back(Ph);771772CurrentLVarMap.makeWritable();773CurrentLVarMap.elem(i).second = Ph;774}775776// Merge values from Map into the current variable map.777// This will construct Phi nodes in the current basic block as necessary.778void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {779assert(CurrentBlockInfo && "Not processing a block!");780781if (!CurrentLVarMap.valid()) {782// Steal Map, using copy-on-write.783CurrentLVarMap = std::move(Map);784return;785}786if (CurrentLVarMap.sameAs(Map))787return; // Easy merge: maps from different predecessors are unchanged.788789unsigned NPreds = CurrentBB->numPredecessors();790unsigned ESz = CurrentLVarMap.size();791unsigned MSz = Map.size();792unsigned Sz = std::min(ESz, MSz);793794for (unsigned i = 0; i < Sz; ++i) {795if (CurrentLVarMap[i].first != Map[i].first) {796// We've reached the end of variables in common.797CurrentLVarMap.makeWritable();798CurrentLVarMap.downsize(i);799break;800}801if (CurrentLVarMap[i].second != Map[i].second)802makePhiNodeVar(i, NPreds, Map[i].second);803}804if (ESz > MSz) {805CurrentLVarMap.makeWritable();806CurrentLVarMap.downsize(Map.size());807}808}809810// Merge a back edge into the current variable map.811// This will create phi nodes for all variables in the variable map.812void SExprBuilder::mergeEntryMapBackEdge() {813// We don't have definitions for variables on the backedge, because we814// haven't gotten that far in the CFG. Thus, when encountering a back edge,815// we conservatively create Phi nodes for all variables. Unnecessary Phi816// nodes will be marked as incomplete, and stripped out at the end.817//818// An Phi node is unnecessary if it only refers to itself and one other819// variable, e.g. x = Phi(y, y, x) can be reduced to x = y.820821assert(CurrentBlockInfo && "Not processing a block!");822823if (CurrentBlockInfo->HasBackEdges)824return;825CurrentBlockInfo->HasBackEdges = true;826827CurrentLVarMap.makeWritable();828unsigned Sz = CurrentLVarMap.size();829unsigned NPreds = CurrentBB->numPredecessors();830831for (unsigned i = 0; i < Sz; ++i)832makePhiNodeVar(i, NPreds, nullptr);833}834835// Update the phi nodes that were initially created for a back edge836// once the variable definitions have been computed.837// I.e., merge the current variable map into the phi nodes for Blk.838void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {839til::BasicBlock *BB = lookupBlock(Blk);840unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;841assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());842843for (til::SExpr *PE : BB->arguments()) {844auto *Ph = dyn_cast_or_null<til::Phi>(PE);845assert(Ph && "Expecting Phi Node.");846assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");847848til::SExpr *E = lookupVarDecl(Ph->clangDecl());849assert(E && "Couldn't find local variable for Phi node.");850Ph->values()[ArgIndex] = E;851}852}853854void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,855const CFGBlock *First) {856// Perform initial setup operations.857unsigned NBlocks = Cfg->getNumBlockIDs();858Scfg = new (Arena) til::SCFG(Arena, NBlocks);859860// allocate all basic blocks immediately, to handle forward references.861BBInfo.resize(NBlocks);862BlockMap.resize(NBlocks, nullptr);863// create map from clang blockID to til::BasicBlocks864for (auto *B : *Cfg) {865auto *BB = new (Arena) til::BasicBlock(Arena);866BB->reserveInstructions(B->size());867BlockMap[B->getBlockID()] = BB;868}869870CurrentBB = lookupBlock(&Cfg->getEntry());871auto Parms = isa<ObjCMethodDecl>(D) ? cast<ObjCMethodDecl>(D)->parameters()872: cast<FunctionDecl>(D)->parameters();873for (auto *Pm : Parms) {874QualType T = Pm->getType();875if (!T.isTrivialType(Pm->getASTContext()))876continue;877878// Add parameters to local variable map.879// FIXME: right now we emulate params with loads; that should be fixed.880til::SExpr *Lp = new (Arena) til::LiteralPtr(Pm);881til::SExpr *Ld = new (Arena) til::Load(Lp);882til::SExpr *V = addStatement(Ld, nullptr, Pm);883addVarDecl(Pm, V);884}885}886887void SExprBuilder::enterCFGBlock(const CFGBlock *B) {888// Initialize TIL basic block and add it to the CFG.889CurrentBB = lookupBlock(B);890CurrentBB->reservePredecessors(B->pred_size());891Scfg->add(CurrentBB);892893CurrentBlockInfo = &BBInfo[B->getBlockID()];894895// CurrentLVarMap is moved to ExitMap on block exit.896// FIXME: the entry block will hold function parameters.897// assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");898}899900void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {901// Compute CurrentLVarMap on entry from ExitMaps of predecessors902903CurrentBB->addPredecessor(BlockMap[Pred->getBlockID()]);904BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];905assert(PredInfo->UnprocessedSuccessors > 0);906907if (--PredInfo->UnprocessedSuccessors == 0)908mergeEntryMap(std::move(PredInfo->ExitMap));909else910mergeEntryMap(PredInfo->ExitMap.clone());911912++CurrentBlockInfo->ProcessedPredecessors;913}914915void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {916mergeEntryMapBackEdge();917}918919void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {920// The merge*() methods have created arguments.921// Push those arguments onto the basic block.922CurrentBB->arguments().reserve(923static_cast<unsigned>(CurrentArguments.size()), Arena);924for (auto *A : CurrentArguments)925CurrentBB->addArgument(A);926}927928void SExprBuilder::handleStatement(const Stmt *S) {929til::SExpr *E = translate(S, nullptr);930addStatement(E, S);931}932933void SExprBuilder::handleDestructorCall(const VarDecl *VD,934const CXXDestructorDecl *DD) {935til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);936til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);937til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);938til::SExpr *E = new (Arena) til::Call(Ap);939addStatement(E, nullptr);940}941942void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {943CurrentBB->instructions().reserve(944static_cast<unsigned>(CurrentInstructions.size()), Arena);945for (auto *V : CurrentInstructions)946CurrentBB->addInstruction(V);947948// Create an appropriate terminator949unsigned N = B->succ_size();950auto It = B->succ_begin();951if (N == 1) {952til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;953// TODO: set index954unsigned Idx = BB ? BB->findPredecessorIndex(CurrentBB) : 0;955auto *Tm = new (Arena) til::Goto(BB, Idx);956CurrentBB->setTerminator(Tm);957}958else if (N == 2) {959til::SExpr *C = translate(B->getTerminatorCondition(true), nullptr);960til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;961++It;962til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;963// FIXME: make sure these aren't critical edges.964auto *Tm = new (Arena) til::Branch(C, BB1, BB2);965CurrentBB->setTerminator(Tm);966}967}968969void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {970++CurrentBlockInfo->UnprocessedSuccessors;971}972973void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {974mergePhiNodesBackEdge(Succ);975++BBInfo[Succ->getBlockID()].ProcessedPredecessors;976}977978void SExprBuilder::exitCFGBlock(const CFGBlock *B) {979CurrentArguments.clear();980CurrentInstructions.clear();981CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);982CurrentBB = nullptr;983CurrentBlockInfo = nullptr;984}985986void SExprBuilder::exitCFG(const CFGBlock *Last) {987for (auto *Ph : IncompleteArgs) {988if (Ph->status() == til::Phi::PH_Incomplete)989simplifyIncompleteArg(Ph);990}991992CurrentArguments.clear();993CurrentInstructions.clear();994IncompleteArgs.clear();995}996997#ifndef NDEBUG998namespace {9991000class TILPrinter :1001public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};10021003} // namespace10041005namespace clang {1006namespace threadSafety {10071008void printSCFG(CFGWalker &Walker) {1009llvm::BumpPtrAllocator Bpa;1010til::MemRegionRef Arena(&Bpa);1011SExprBuilder SxBuilder(Arena);1012til::SCFG *Scfg = SxBuilder.buildCFG(Walker);1013TILPrinter::print(Scfg, llvm::errs());1014}10151016} // namespace threadSafety1017} // namespace clang1018#endif // NDEBUG101910201021