blob: 7b9c91d351ffa1d0df4a2a1a3abad4394574c5bf [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
14#include "clang/AST/Attr.h"
15#include "clang/AST/DeclCXX.h"
16#include "clang/AST/ExprCXX.h"
17#include "clang/AST/StmtCXX.h"
18#include "clang/AST/StmtVisitor.h"
19#include "clang/Analysis/Analyses/PostOrderCFGView.h"
20#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
21#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
22#include "clang/Analysis/AnalysisContext.h"
23#include "clang/Analysis/CFG.h"
24#include "clang/Analysis/CFGStmtMap.h"
25#include "clang/Basic/OperatorKinds.h"
26#include "clang/Basic/SourceLocation.h"
27#include "clang/Basic/SourceManager.h"
28#include "llvm/ADT/BitVector.h"
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/FoldingSet.h"
31#include "llvm/ADT/ImmutableMap.h"
32#include "llvm/ADT/PostOrderIterator.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/ADT/StringRef.h"
35#include <vector>
36
37
38namespace clang {
39namespace threadSafety {
40
41typedef SExprBuilder::CallingContext CallingContext;
42
43
44til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
45 if (!SMap)
46 return 0;
47 auto It = SMap->find(S);
48 if (It != SMap->end())
49 return It->second;
50 return 0;
51}
52
53void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
54 SMap->insert(std::make_pair(S, V));
55}
56
57
58// Translate a clang statement or expression to a TIL expression.
59// Also performs substitution of variables; Ctx provides the context.
60// Dispatches on the type of S.
61til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
62 // Check if S has already been translated and cached.
63 // This handles the lookup of SSA names for DeclRefExprs here.
64 if (til::SExpr *E = lookupStmt(S))
65 return E;
66
67 switch (S->getStmtClass()) {
68 case Stmt::DeclRefExprClass:
69 return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);
70 case Stmt::CXXThisExprClass:
71 return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);
72 case Stmt::MemberExprClass:
73 return translateMemberExpr(cast<MemberExpr>(S), Ctx);
74 case Stmt::CallExprClass:
75 return translateCallExpr(cast<CallExpr>(S), Ctx);
76 case Stmt::CXXMemberCallExprClass:
77 return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);
78 case Stmt::CXXOperatorCallExprClass:
79 return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);
80 case Stmt::UnaryOperatorClass:
81 return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
82 case Stmt::BinaryOperatorClass:
83 return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
84
85 case Stmt::ArraySubscriptExprClass:
86 return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
87 case Stmt::ConditionalOperatorClass:
88 return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
89 case Stmt::BinaryConditionalOperatorClass:
90 return translateBinaryConditionalOperator(
91 cast<BinaryConditionalOperator>(S), Ctx);
92
93 // We treat these as no-ops
94 case Stmt::ParenExprClass:
95 return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
96 case Stmt::ExprWithCleanupsClass:
97 return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
98 case Stmt::CXXBindTemporaryExprClass:
99 return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
100
101 // Collect all literals
102 case Stmt::CharacterLiteralClass:
103 case Stmt::CXXNullPtrLiteralExprClass:
104 case Stmt::GNUNullExprClass:
105 case Stmt::CXXBoolLiteralExprClass:
106 case Stmt::FloatingLiteralClass:
107 case Stmt::ImaginaryLiteralClass:
108 case Stmt::IntegerLiteralClass:
109 case Stmt::StringLiteralClass:
110 case Stmt::ObjCStringLiteralClass:
111 return new (Arena) til::Literal(cast<Expr>(S));
112 default:
113 break;
114 }
115 if (const CastExpr *CE = dyn_cast<CastExpr>(S))
116 return translateCastExpr(CE, Ctx);
117
118 return new (Arena) til::Undefined(S);
119}
120
121
122til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
123 CallingContext *Ctx) {
124 const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
125
126 // Function parameters require substitution and/or renaming.
127 if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
128 const FunctionDecl *FD =
129 cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
130 unsigned I = PV->getFunctionScopeIndex();
131
132 if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) {
133 // Substitute call arguments for references to function parameters
134 assert(I < Ctx->NumArgs);
135 return translate(Ctx->FunArgs[I], Ctx->Prev);
136 }
137 // Map the param back to the param of the original function declaration
138 // for consistent comparisons.
139 VD = FD->getParamDecl(I);
140 }
141
142 // For non-local variables, treat it as a referenced to a named object.
143 return new (Arena) til::LiteralPtr(VD);
144}
145
146
147til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
148 CallingContext *Ctx) {
149 // Substitute for 'this'
150 if (Ctx && Ctx->SelfArg)
151 return translate(Ctx->SelfArg, Ctx->Prev);
152 assert(SelfVar && "We have no variable for 'this'!");
153 return SelfVar;
154}
155
156
157til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
158 CallingContext *Ctx) {
159 til::SExpr *E = translate(ME->getBase(), Ctx);
160 E = new (Arena) til::SApply(E);
161 return new (Arena) til::Project(E, ME->getMemberDecl());
162}
163
164
165til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
166 CallingContext *Ctx) {
167 // TODO -- Lock returned
168 til::SExpr *E = translate(CE->getCallee(), Ctx);
169 for (unsigned I = 0, N = CE->getNumArgs(); I < N; ++I) {
170 til::SExpr *A = translate(CE->getArg(I), Ctx);
171 E = new (Arena) til::Apply(E, A);
172 }
173 return new (Arena) til::Call(E, CE);
174}
175
176
177til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
178 const CXXMemberCallExpr *ME, CallingContext *Ctx) {
179 return translateCallExpr(cast<CallExpr>(ME), Ctx);
180}
181
182
183til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
184 const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
185 return translateCallExpr(cast<CallExpr>(OCE), Ctx);
186}
187
188
189til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
190 CallingContext *Ctx) {
191 switch (UO->getOpcode()) {
192 case UO_PostInc:
193 case UO_PostDec:
194 case UO_PreInc:
195 case UO_PreDec:
196 return new (Arena) til::Undefined(UO);
197
198 // We treat these as no-ops
199 case UO_AddrOf:
200 case UO_Deref:
201 case UO_Plus:
202 return translate(UO->getSubExpr(), Ctx);
203
204 case UO_Minus:
205 case UO_Not:
206 case UO_LNot:
207 case UO_Real:
208 case UO_Imag:
209 case UO_Extension: {
210 til::SExpr *E0 = translate(UO->getSubExpr(), Ctx);
211 return new (Arena) til::UnaryOp(UO->getOpcode(), E0);
212 }
213 }
214 return new (Arena) til::Undefined(UO);
215}
216
217til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
218 CallingContext *Ctx) {
219 switch (BO->getOpcode()) {
220 case BO_PtrMemD:
221 case BO_PtrMemI:
222 return new (Arena) til::Undefined(BO);
223
224 case BO_Mul:
225 case BO_Div:
226 case BO_Rem:
227 case BO_Add:
228 case BO_Sub:
229 case BO_Shl:
230 case BO_Shr:
231 case BO_LT:
232 case BO_GT:
233 case BO_LE:
234 case BO_GE:
235 case BO_EQ:
236 case BO_NE:
237 case BO_And:
238 case BO_Xor:
239 case BO_Or:
240 case BO_LAnd:
241 case BO_LOr: {
242 til::SExpr *E0 = translate(BO->getLHS(), Ctx);
243 til::SExpr *E1 = translate(BO->getRHS(), Ctx);
244 return new (Arena) til::BinaryOp(BO->getOpcode(), E0, E1);
245 }
246 case BO_Assign: {
247 til::SExpr *E0 = translate(BO->getLHS(), Ctx);
248 til::SExpr *E1 = translate(BO->getRHS(), Ctx);
249 return new (Arena) til::Store(E0, E1);
250 }
251 case BO_MulAssign:
252 case BO_DivAssign:
253 case BO_RemAssign:
254 case BO_AddAssign:
255 case BO_SubAssign:
256 case BO_ShlAssign:
257 case BO_ShrAssign:
258 case BO_AndAssign:
259 case BO_XorAssign:
260 case BO_OrAssign:
261 return new (Arena) til::Undefined(BO);
262
263 case BO_Comma:
264 // TODO: handle LHS
265 return translate(BO->getRHS(), Ctx);
266 }
267
268 return new (Arena) til::Undefined(BO);
269}
270
271
272til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
273 CallingContext *Ctx) {
274 til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
275
276 clang::CastKind K = CE->getCastKind();
277 switch (K) {
278 case CK_LValueToRValue:
279 return new (Arena) til::Load(E0);
280
281 case CK_NoOp:
282 case CK_DerivedToBase:
283 case CK_UncheckedDerivedToBase:
284 case CK_ArrayToPointerDecay:
285 case CK_FunctionToPointerDecay:
286 return E0;
287
288 default:
289 return new (Arena) til::Cast(K, E0);
290 }
291}
292
293
294til::SExpr *SExprBuilder::translateArraySubscriptExpr(
295 const ArraySubscriptExpr *E, CallingContext *Ctx) {
296 return new (Arena) til::Undefined(E);
297}
298
299
300til::SExpr *SExprBuilder::translateConditionalOperator(
301 const ConditionalOperator *C, CallingContext *Ctx) {
302 return new (Arena) til::Undefined(C);
303}
304
305
306til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
307 const BinaryConditionalOperator *C, CallingContext *Ctx) {
308 return new (Arena) til::Undefined(C);
309}
310
311
312// Build a complete SCFG from a clang CFG.
313class SCFGBuilder : public CFGVisitor {
314public:
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000315 til::Variable *addStatement(til::SExpr* E, const Stmt *S) {
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000316 if (!E)
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000317 return 0;
318 if (til::ThreadSafetyTIL::isTrivial(E))
319 return 0;
320
321 til::Variable *V = new (Arena) til::Variable(til::Variable::VK_Let, E);
322 V->setID(CurrentBlockID, CurrentVarID++);
323 CurrentBB->addInstr(V);
324 if (S)
325 BuildEx.insertStmt(S, V);
326 return V;
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000327 }
328
329 // Enter the CFG for Decl D, and perform any initial setup operations.
330 void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000331 Scfg = new (Arena) til::SCFG(Arena, Cfg->getNumBlockIDs());
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000332 CallCtx = new SExprBuilder::CallingContext(D);
333 }
334
335 // Enter a CFGBlock.
336 void enterCFGBlock(const CFGBlock *B) {
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000337 CurrentBB = new (Arena) til::BasicBlock(Arena, 0, B->size());
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000338 CurrentBB->setBlockID(CurrentBlockID);
339 CurrentVarID = 0;
340 Scfg->add(CurrentBB);
341 }
342
343 // Process an ordinary statement.
344 void handleStatement(const Stmt *S) {
345 til::SExpr *E = BuildEx.translate(S, CallCtx);
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000346 addStatement(E, S);
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000347 }
348
349 // Process a destructor call
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000350 void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {
351 til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
352 til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
353 til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
354 til::SExpr *E = new (Arena) til::Call(Ap, 0);
355 addStatement(E, nullptr);
356 }
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000357
358 // Process a successor edge.
359 void handleSuccessor(const CFGBlock *Succ) {}
360
361 // Process a successor back edge to a previously visited block.
362 void handleSuccessorBackEdge(const CFGBlock *Succ) {}
363
364 // Leave a CFGBlock.
365 void exitCFGBlock(const CFGBlock *B) {
366 CurrentBlockID++;
367 CurrentBB = 0;
368 }
369
370 // Leave the CFG, and perform any final cleanup operations.
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000371 void exitCFG(const CFGBlock *Last) {
372 if (CallCtx) {
373 delete CallCtx;
374 CallCtx = nullptr;
375 }
376 }
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000377
378 SCFGBuilder(til::MemRegionRef A)
379 : Arena(A), Scfg(0), CurrentBB(0), CurrentBlockID(0),
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000380 CallCtx(0), SMap(new SExprBuilder::StatementMap()),
381 BuildEx(A, SMap)
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000382 { }
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000383 ~SCFGBuilder() {
384 delete SMap;
385 }
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000386
387 til::SCFG *getCFG() const { return Scfg; }
388
389private:
390 til::MemRegionRef Arena;
391 til::SCFG *Scfg;
392 til::BasicBlock *CurrentBB;
393 unsigned CurrentBlockID;
394 unsigned CurrentVarID;
395
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000396 SExprBuilder::CallingContext *CallCtx;
DeLesley Hutchins11bb30872014-04-07 22:56:24 +0000397 SExprBuilder::StatementMap *SMap;
398 SExprBuilder BuildEx;
DeLesley Hutchinsb2213912014-04-07 18:09:54 +0000399};
400
401
402
403class LLVMPrinter :
404 public til::TILPrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
405};
406
407
408void printSCFG(CFGWalker &walker) {
409 llvm::BumpPtrAllocator Bpa;
410 til::MemRegionRef Arena(&Bpa);
411 SCFGBuilder builder(Arena);
412 // CFGVisitor visitor;
413 walker.walk(builder);
414 LLVMPrinter::print(builder.getCFG(), llvm::errs());
415}
416
417
418
419} // end namespace threadSafety
420
421} // end namespace clang