blob: b916c75db92ce5119ba9f11e8de94a7481cc2fe9 [file] [log] [blame]
DeLesley Hutchinsb2213912014-04-07 18:09:54 +00001//===- ThreadSafetyCommon.cpp ----------------------------------*- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Implementation of the interfaces declared in ThreadSafetyCommon.h
11//
12//===----------------------------------------------------------------------===//
13
Aaron Ballman28347a72014-04-09 21:12:04 +000014#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000015#include "clang/AST/Attr.h"
16#include "clang/AST/DeclCXX.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/AST/StmtCXX.h"
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000019#include "clang/Analysis/Analyses/PostOrderCFGView.h"
DeLesley Hutchinsf7813c52014-04-08 22:21:22 +000020#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000021#include "clang/Analysis/AnalysisContext.h"
22#include "clang/Analysis/CFG.h"
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000023#include "clang/Basic/OperatorKinds.h"
24#include "clang/Basic/SourceLocation.h"
25#include "clang/Basic/SourceManager.h"
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000026#include "llvm/ADT/DenseMap.h"
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000027#include "llvm/ADT/SmallVector.h"
28#include "llvm/ADT/StringRef.h"
29#include <vector>
30
31
32namespace clang {
33namespace threadSafety {
34
35typedef SExprBuilder::CallingContext CallingContext;
36
37
38til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
39 if (!SMap)
Aaron Ballman3f993c12014-04-09 17:45:44 +000040 return nullptr;
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000041 auto It = SMap->find(S);
42 if (It != SMap->end())
43 return It->second;
Aaron Ballman3f993c12014-04-09 17:45:44 +000044 return nullptr;
DeLesley Hutchinsb2213912014-04-07 18:09:54 +000045}
46
47void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
48 SMap->insert(std::make_pair(S, V));
49}
50
51
52// Translate a clang statement or expression to a TIL expression.
53// Also performs substitution of variables; Ctx provides the context.
54// Dispatches on the type of S.
55til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
56 // Check if S has already been translated and cached.
57 // This handles the lookup of SSA names for DeclRefExprs here.
58 if (til::SExpr *E = lookupStmt(S))
59 return E;
60
61 switch (S->getStmtClass()) {
62 case Stmt::DeclRefExprClass:
63 return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);
64 case Stmt::CXXThisExprClass:
65 return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);
66 case Stmt::MemberExprClass:
67 return translateMemberExpr(cast<MemberExpr>(S), Ctx);
68 case Stmt::CallExprClass:
69 return translateCallExpr(cast<CallExpr>(S), Ctx);
70 case Stmt::CXXMemberCallExprClass:
71 return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);
72 case Stmt::CXXOperatorCallExprClass:
73 return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);
74 case Stmt::UnaryOperatorClass:
75 return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
76 case Stmt::BinaryOperatorClass:
77 return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
78
79 case Stmt::ArraySubscriptExprClass:
80 return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
81 case Stmt::ConditionalOperatorClass:
82 return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
83 case Stmt::BinaryConditionalOperatorClass:
84 return translateBinaryConditionalOperator(
85 cast<BinaryConditionalOperator>(S), Ctx);
86
87 // We treat these as no-ops
88 case Stmt::ParenExprClass:
89 return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
90 case Stmt::ExprWithCleanupsClass:
91 return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
92 case Stmt::CXXBindTemporaryExprClass:
93 return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
94
95 // Collect all literals
96 case Stmt::CharacterLiteralClass:
97 case Stmt::CXXNullPtrLiteralExprClass:
98 case Stmt::GNUNullExprClass:
99 case Stmt::CXXBoolLiteralExprClass:
100 case Stmt::FloatingLiteralClass:
101 case Stmt::ImaginaryLiteralClass:
102 case Stmt::IntegerLiteralClass:
103 case Stmt::StringLiteralClass:
104 case Stmt::ObjCStringLiteralClass:
105 return new (Arena) til::Literal(cast<Expr>(S));
106 default:
107 break;
108 }
109 if (const CastExpr *CE = dyn_cast<CastExpr>(S))
110 return translateCastExpr(CE, Ctx);
111
112 return new (Arena) til::Undefined(S);
113}
114
115
116til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
117 CallingContext *Ctx) {
118 const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
119
120 // Function parameters require substitution and/or renaming.
121 if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
122 const FunctionDecl *FD =
123 cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
124 unsigned I = PV->getFunctionScopeIndex();
125
126 if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) {
127 // Substitute call arguments for references to function parameters
128 assert(I < Ctx->NumArgs);
129 return translate(Ctx->FunArgs[I], Ctx->Prev);
130 }
131 // Map the param back to the param of the original function declaration
132 // for consistent comparisons.
133 VD = FD->getParamDecl(I);
134 }
135
136 // For non-local variables, treat it as a referenced to a named object.
137 return new (Arena) til::LiteralPtr(VD);
138}
139
140
141til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
142 CallingContext *Ctx) {
143 // Substitute for 'this'
144 if (Ctx && Ctx->SelfArg)
145 return translate(Ctx->SelfArg, Ctx->Prev);
146 assert(SelfVar && "We have no variable for 'this'!");
147 return SelfVar;
148}
149
150
151til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
152 CallingContext *Ctx) {
153 til::SExpr *E = translate(ME->getBase(), Ctx);
154 E = new (Arena) til::SApply(E);
155 return new (Arena) til::Project(E, ME->getMemberDecl());
156}
157
158
159til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
160 CallingContext *Ctx) {
161 // TODO -- Lock returned
162 til::SExpr *E = translate(CE->getCallee(), Ctx);
Aaron Ballman3f993c12014-04-09 17:45:44 +0000163 for (const auto *Arg : CE->arguments()) {
164 til::SExpr *A = translate(Arg, Ctx);
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000165 E = new (Arena) til::Apply(E, A);
166 }
167 return new (Arena) til::Call(E, CE);
168}
169
170
171til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
172 const CXXMemberCallExpr *ME, CallingContext *Ctx) {
173 return translateCallExpr(cast<CallExpr>(ME), Ctx);
174}
175
176
177til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
178 const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
179 return translateCallExpr(cast<CallExpr>(OCE), Ctx);
180}
181
182
183til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
184 CallingContext *Ctx) {
185 switch (UO->getOpcode()) {
186 case UO_PostInc:
187 case UO_PostDec:
188 case UO_PreInc:
189 case UO_PreDec:
190 return new (Arena) til::Undefined(UO);
191
192 // We treat these as no-ops
193 case UO_AddrOf:
194 case UO_Deref:
195 case UO_Plus:
196 return translate(UO->getSubExpr(), Ctx);
197
198 case UO_Minus:
199 case UO_Not:
200 case UO_LNot:
201 case UO_Real:
202 case UO_Imag:
Aaron Ballman3f993c12014-04-09 17:45:44 +0000203 case UO_Extension:
204 return new (Arena)
205 til::UnaryOp(UO->getOpcode(), translate(UO->getSubExpr(), Ctx));
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000206 }
207 return new (Arena) til::Undefined(UO);
208}
209
210til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
211 CallingContext *Ctx) {
212 switch (BO->getOpcode()) {
213 case BO_PtrMemD:
214 case BO_PtrMemI:
215 return new (Arena) til::Undefined(BO);
216
217 case BO_Mul:
218 case BO_Div:
219 case BO_Rem:
220 case BO_Add:
221 case BO_Sub:
222 case BO_Shl:
223 case BO_Shr:
224 case BO_LT:
225 case BO_GT:
226 case BO_LE:
227 case BO_GE:
228 case BO_EQ:
229 case BO_NE:
230 case BO_And:
231 case BO_Xor:
232 case BO_Or:
233 case BO_LAnd:
Aaron Ballman3f993c12014-04-09 17:45:44 +0000234 case BO_LOr:
235 return new (Arena)
236 til::BinaryOp(BO->getOpcode(), translate(BO->getLHS(), Ctx),
237 translate(BO->getRHS(), Ctx));
238
239 case BO_Assign:
240 return new (Arena)
241 til::Store(translate(BO->getLHS(), Ctx), translate(BO->getRHS(), Ctx));
242
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000243 case BO_MulAssign:
244 case BO_DivAssign:
245 case BO_RemAssign:
246 case BO_AddAssign:
247 case BO_SubAssign:
248 case BO_ShlAssign:
249 case BO_ShrAssign:
250 case BO_AndAssign:
251 case BO_XorAssign:
252 case BO_OrAssign:
253 return new (Arena) til::Undefined(BO);
254
255 case BO_Comma:
256 // TODO: handle LHS
257 return translate(BO->getRHS(), Ctx);
258 }
259
260 return new (Arena) til::Undefined(BO);
261}
262
263
264til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
265 CallingContext *Ctx) {
266 til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
267
268 clang::CastKind K = CE->getCastKind();
269 switch (K) {
270 case CK_LValueToRValue:
271 return new (Arena) til::Load(E0);
272
273 case CK_NoOp:
274 case CK_DerivedToBase:
275 case CK_UncheckedDerivedToBase:
276 case CK_ArrayToPointerDecay:
277 case CK_FunctionToPointerDecay:
278 return E0;
279
280 default:
281 return new (Arena) til::Cast(K, E0);
282 }
283}
284
Aaron Ballman3f993c12014-04-09 17:45:44 +0000285til::SExpr *
286SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
287 CallingContext *Ctx) {
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000288 return new (Arena) til::Undefined(E);
289}
290
Aaron Ballman3f993c12014-04-09 17:45:44 +0000291til::SExpr *
292SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
293 CallingContext *Ctx) {
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000294 return new (Arena) til::Undefined(C);
295}
296
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000297til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
298 const BinaryConditionalOperator *C, CallingContext *Ctx) {
299 return new (Arena) til::Undefined(C);
300}
301
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000302// Build a complete SCFG from a clang CFG.
Aaron Ballman3f993c12014-04-09 17:45:44 +0000303class SCFGBuilder {
304 void addStatement(til::SExpr* E, const Stmt *S) {
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000305 if (!E)
Aaron Ballman3f993c12014-04-09 17:45:44 +0000306 return;
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000307 if (til::ThreadSafetyTIL::isTrivial(E))
Aaron Ballman3f993c12014-04-09 17:45:44 +0000308 return;
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000309
310 til::Variable *V = new (Arena) til::Variable(til::Variable::VK_Let, E);
311 V->setID(CurrentBlockID, CurrentVarID++);
312 CurrentBB->addInstr(V);
313 if (S)
314 BuildEx.insertStmt(S, V);
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000315 }
316
Aaron Ballman3f993c12014-04-09 17:45:44 +0000317public:
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000318 // Enter the CFG for Decl D, and perform any initial setup operations.
319 void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000320 Scfg = new (Arena) til::SCFG(Arena, Cfg->getNumBlockIDs());
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000321 CallCtx = new SExprBuilder::CallingContext(D);
322 }
323
324 // Enter a CFGBlock.
325 void enterCFGBlock(const CFGBlock *B) {
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000326 CurrentBB = new (Arena) til::BasicBlock(Arena, 0, B->size());
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000327 CurrentBB->setBlockID(CurrentBlockID);
328 CurrentVarID = 0;
329 Scfg->add(CurrentBB);
330 }
331
332 // Process an ordinary statement.
333 void handleStatement(const Stmt *S) {
334 til::SExpr *E = BuildEx.translate(S, CallCtx);
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000335 addStatement(E, S);
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000336 }
337
338 // Process a destructor call
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000339 void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {
340 til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
341 til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
342 til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
Aaron Ballman3f993c12014-04-09 17:45:44 +0000343 til::SExpr *E = new (Arena) til::Call(Ap);
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000344 addStatement(E, nullptr);
345 }
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000346
347 // Process a successor edge.
348 void handleSuccessor(const CFGBlock *Succ) {}
349
350 // Process a successor back edge to a previously visited block.
351 void handleSuccessorBackEdge(const CFGBlock *Succ) {}
352
353 // Leave a CFGBlock.
354 void exitCFGBlock(const CFGBlock *B) {
355 CurrentBlockID++;
356 CurrentBB = 0;
357 }
358
359 // Leave the CFG, and perform any final cleanup operations.
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000360 void exitCFG(const CFGBlock *Last) {
Aaron Ballman3f993c12014-04-09 17:45:44 +0000361 delete CallCtx;
362 CallCtx = nullptr;
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000363 }
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000364
365 SCFGBuilder(til::MemRegionRef A)
Aaron Ballman3f993c12014-04-09 17:45:44 +0000366 : Arena(A), Scfg(nullptr), CurrentBB(nullptr), CurrentBlockID(0),
367 CurrentVarID(0), CallCtx(nullptr),
368 SMap(new SExprBuilder::StatementMap()), BuildEx(A, SMap) {}
369 ~SCFGBuilder() { delete SMap; }
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000370
371 til::SCFG *getCFG() const { return Scfg; }
372
373private:
374 til::MemRegionRef Arena;
375 til::SCFG *Scfg;
376 til::BasicBlock *CurrentBB;
377 unsigned CurrentBlockID;
378 unsigned CurrentVarID;
379
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000380 SExprBuilder::CallingContext *CallCtx;
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000381 SExprBuilder::StatementMap *SMap;
382 SExprBuilder BuildEx;
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000383};
384
385
386
387class LLVMPrinter :
DeLesley Hutchinsf7813c52014-04-08 22:21:22 +0000388 public til::PrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000389};
390
391
392void printSCFG(CFGWalker &walker) {
393 llvm::BumpPtrAllocator Bpa;
394 til::MemRegionRef Arena(&Bpa);
395 SCFGBuilder builder(Arena);
396 // CFGVisitor visitor;
397 walker.walk(builder);
398 LLVMPrinter::print(builder.getCFG(), llvm::errs());
399}
400
401
402
403} // end namespace threadSafety
404
405} // end namespace clang