1 //===- ThreadSafetyTraverse.h -----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines a framework for doing generic traversals and rewriting 10 // operations over the Thread Safety TIL. 11 // 12 // UNDER CONSTRUCTION. USE AT YOUR OWN RISK. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H 17 #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H 18 19 #include "clang/AST/Decl.h" 20 #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" 21 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h" 22 #include "clang/Basic/LLVM.h" 23 #include "llvm/ADT/StringRef.h" 24 #include "llvm/Support/Casting.h" 25 #include <cstdint> 26 #include <ostream> 27 28 namespace clang { 29 namespace threadSafety { 30 namespace til { 31 32 // Defines an interface used to traverse SExprs. Traversals have been made as 33 // generic as possible, and are intended to handle any kind of pass over the 34 // AST, e.g. visitors, copying, non-destructive rewriting, destructive 35 // (in-place) rewriting, hashing, typing, etc. 36 // 37 // Traversals implement the functional notion of a "fold" operation on SExprs. 38 // Each SExpr class provides a traverse method, which does the following: 39 // * e->traverse(v): 40 // // compute a result r_i for each subexpression e_i 41 // for (i = 1..n) r_i = v.traverse(e_i); 42 // // combine results into a result for e, where X is the class of e 43 // return v.reduceX(*e, r_1, .. r_n). 44 // 45 // A visitor can control the traversal by overriding the following methods: 46 // * v.traverse(e): 47 // return v.traverseByCase(e), which returns v.traverseX(e) 48 // * v.traverseX(e): (X is the class of e) 49 // return e->traverse(v). 50 // * v.reduceX(*e, r_1, .. r_n): 51 // compute a result for a node of type X 52 // 53 // The reduceX methods control the kind of traversal (visitor, copy, etc.). 54 // They are defined in derived classes. 55 // 56 // Class R defines the basic interface types (R_SExpr). 57 template <class Self, class R> 58 class Traversal { 59 public: self()60 Self *self() { return static_cast<Self *>(this); } 61 62 // Traverse an expression -- returning a result of type R_SExpr. 63 // Override this method to do something for every expression, regardless 64 // of which kind it is. 65 // E is a reference, so this can be use for in-place updates. 66 // The type T must be a subclass of SExpr. 67 template <class T> traverse(T * & E,typename R::R_Ctx Ctx)68 typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) { 69 return traverseSExpr(E, Ctx); 70 } 71 72 // Override this method to do something for every expression. 73 // Does not allow in-place updates. traverseSExpr(SExpr * E,typename R::R_Ctx Ctx)74 typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) { 75 return traverseByCase(E, Ctx); 76 } 77 78 // Helper method to call traverseX(e) on the appropriate type. traverseByCase(SExpr * E,typename R::R_Ctx Ctx)79 typename R::R_SExpr traverseByCase(SExpr *E, typename R::R_Ctx Ctx) { 80 switch (E->opcode()) { 81 #define TIL_OPCODE_DEF(X) \ 82 case COP_##X: \ 83 return self()->traverse##X(cast<X>(E), Ctx); 84 #include "ThreadSafetyOps.def" 85 #undef TIL_OPCODE_DEF 86 } 87 return self()->reduceNull(); 88 } 89 90 // Traverse e, by static dispatch on the type "X" of e. 91 // Override these methods to do something for a particular kind of term. 92 #define TIL_OPCODE_DEF(X) \ 93 typename R::R_SExpr traverse##X(X *e, typename R::R_Ctx Ctx) { \ 94 return e->traverse(*self(), Ctx); \ 95 } 96 #include "ThreadSafetyOps.def" 97 #undef TIL_OPCODE_DEF 98 }; 99 100 // Base class for simple reducers that don't much care about the context. 101 class SimpleReducerBase { 102 public: 103 enum TraversalKind { 104 // Ordinary subexpressions. 105 TRV_Normal, 106 107 // Declarations (e.g. function bodies). 108 TRV_Decl, 109 110 // Expressions that require lazy evaluation. 111 TRV_Lazy, 112 113 // Type expressions. 114 TRV_Type 115 }; 116 117 // R_Ctx defines a "context" for the traversal, which encodes information 118 // about where a term appears. This can be used to encoding the 119 // "current continuation" for CPS transforms, or other information. 120 using R_Ctx = TraversalKind; 121 122 // Create context for an ordinary subexpression. subExprCtx(R_Ctx Ctx)123 R_Ctx subExprCtx(R_Ctx Ctx) { return TRV_Normal; } 124 125 // Create context for a subexpression that occurs in a declaration position 126 // (e.g. function body). declCtx(R_Ctx Ctx)127 R_Ctx declCtx(R_Ctx Ctx) { return TRV_Decl; } 128 129 // Create context for a subexpression that occurs in a position that 130 // should be reduced lazily. (e.g. code body). lazyCtx(R_Ctx Ctx)131 R_Ctx lazyCtx(R_Ctx Ctx) { return TRV_Lazy; } 132 133 // Create context for a subexpression that occurs in a type position. typeCtx(R_Ctx Ctx)134 R_Ctx typeCtx(R_Ctx Ctx) { return TRV_Type; } 135 }; 136 137 // Base class for traversals that rewrite an SExpr to another SExpr. 138 class CopyReducerBase : public SimpleReducerBase { 139 public: 140 // R_SExpr is the result type for a traversal. 141 // A copy or non-destructive rewrite returns a newly allocated term. 142 using R_SExpr = SExpr *; 143 using R_BasicBlock = BasicBlock *; 144 145 // Container is a minimal interface used to store results when traversing 146 // SExprs of variable arity, such as Phi, Goto, and SCFG. 147 template <class T> class Container { 148 public: 149 // Allocate a new container with a capacity for n elements. Container(CopyReducerBase & S,unsigned N)150 Container(CopyReducerBase &S, unsigned N) : Elems(S.Arena, N) {} 151 152 // Push a new element onto the container. push_back(T E)153 void push_back(T E) { Elems.push_back(E); } 154 155 SimpleArray<T> Elems; 156 }; 157 CopyReducerBase(MemRegionRef A)158 CopyReducerBase(MemRegionRef A) : Arena(A) {} 159 160 protected: 161 MemRegionRef Arena; 162 }; 163 164 // Base class for visit traversals. 165 class VisitReducerBase : public SimpleReducerBase { 166 public: 167 // A visitor returns a bool, representing success or failure. 168 using R_SExpr = bool; 169 using R_BasicBlock = bool; 170 171 // A visitor "container" is a single bool, which accumulates success. 172 template <class T> class Container { 173 public: 174 bool Success = true; 175 Container(VisitReducerBase & S,unsigned N)176 Container(VisitReducerBase &S, unsigned N) {} 177 push_back(bool E)178 void push_back(bool E) { Success = Success && E; } 179 }; 180 }; 181 182 // Implements a traversal that visits each subexpression, and returns either 183 // true or false. 184 template <class Self> 185 class VisitReducer : public Traversal<Self, VisitReducerBase>, 186 public VisitReducerBase { 187 public: 188 VisitReducer() = default; 189 190 public: reduceNull()191 R_SExpr reduceNull() { return true; } reduceUndefined(Undefined & Orig)192 R_SExpr reduceUndefined(Undefined &Orig) { return true; } reduceWildcard(Wildcard & Orig)193 R_SExpr reduceWildcard(Wildcard &Orig) { return true; } 194 reduceLiteral(Literal & Orig)195 R_SExpr reduceLiteral(Literal &Orig) { return true; } 196 template<class T> reduceLiteralT(LiteralT<T> & Orig)197 R_SExpr reduceLiteralT(LiteralT<T> &Orig) { return true; } reduceLiteralPtr(Literal & Orig)198 R_SExpr reduceLiteralPtr(Literal &Orig) { return true; } 199 reduceFunction(Function & Orig,Variable * Nvd,R_SExpr E0)200 R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) { 201 return Nvd && E0; 202 } 203 reduceSFunction(SFunction & Orig,Variable * Nvd,R_SExpr E0)204 R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) { 205 return Nvd && E0; 206 } 207 reduceCode(Code & Orig,R_SExpr E0,R_SExpr E1)208 R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) { 209 return E0 && E1; 210 } 211 reduceField(Field & Orig,R_SExpr E0,R_SExpr E1)212 R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) { 213 return E0 && E1; 214 } 215 reduceApply(Apply & Orig,R_SExpr E0,R_SExpr E1)216 R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) { 217 return E0 && E1; 218 } 219 reduceSApply(SApply & Orig,R_SExpr E0,R_SExpr E1)220 R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) { 221 return E0 && E1; 222 } 223 reduceProject(Project & Orig,R_SExpr E0)224 R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; } reduceCall(Call & Orig,R_SExpr E0)225 R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; } reduceAlloc(Alloc & Orig,R_SExpr E0)226 R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; } reduceLoad(Load & Orig,R_SExpr E0)227 R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; } reduceStore(Store & Orig,R_SExpr E0,R_SExpr E1)228 R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; } 229 reduceArrayIndex(Store & Orig,R_SExpr E0,R_SExpr E1)230 R_SExpr reduceArrayIndex(Store &Orig, R_SExpr E0, R_SExpr E1) { 231 return E0 && E1; 232 } 233 reduceArrayAdd(Store & Orig,R_SExpr E0,R_SExpr E1)234 R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1) { 235 return E0 && E1; 236 } 237 reduceUnaryOp(UnaryOp & Orig,R_SExpr E0)238 R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; } 239 reduceBinaryOp(BinaryOp & Orig,R_SExpr E0,R_SExpr E1)240 R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { 241 return E0 && E1; 242 } 243 reduceCast(Cast & Orig,R_SExpr E0)244 R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; } 245 reduceSCFG(SCFG & Orig,Container<BasicBlock * > Bbs)246 R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) { 247 return Bbs.Success; 248 } 249 reduceBasicBlock(BasicBlock & Orig,Container<R_SExpr> & As,Container<R_SExpr> & Is,R_SExpr T)250 R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<R_SExpr> &As, 251 Container<R_SExpr> &Is, R_SExpr T) { 252 return (As.Success && Is.Success && T); 253 } 254 reducePhi(Phi & Orig,Container<R_SExpr> & As)255 R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) { 256 return As.Success; 257 } 258 reduceGoto(Goto & Orig,BasicBlock * B)259 R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) { 260 return true; 261 } 262 reduceBranch(Branch & O,R_SExpr C,BasicBlock * B0,BasicBlock * B1)263 R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { 264 return C; 265 } 266 reduceReturn(Return & O,R_SExpr E)267 R_SExpr reduceReturn(Return &O, R_SExpr E) { 268 return E; 269 } 270 reduceIdentifier(Identifier & Orig)271 R_SExpr reduceIdentifier(Identifier &Orig) { 272 return true; 273 } 274 reduceIfThenElse(IfThenElse & Orig,R_SExpr C,R_SExpr T,R_SExpr E)275 R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) { 276 return C && T && E; 277 } 278 reduceLet(Let & Orig,Variable * Nvd,R_SExpr B)279 R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) { 280 return Nvd && B; 281 } 282 enterScope(Variable & Orig,R_SExpr E0)283 Variable *enterScope(Variable &Orig, R_SExpr E0) { return &Orig; } exitScope(const Variable & Orig)284 void exitScope(const Variable &Orig) {} enterCFG(SCFG & Cfg)285 void enterCFG(SCFG &Cfg) {} exitCFG(SCFG & Cfg)286 void exitCFG(SCFG &Cfg) {} enterBasicBlock(BasicBlock & BB)287 void enterBasicBlock(BasicBlock &BB) {} exitBasicBlock(BasicBlock & BB)288 void exitBasicBlock(BasicBlock &BB) {} 289 reduceVariableRef(Variable * Ovd)290 Variable *reduceVariableRef(Variable *Ovd) { return Ovd; } reduceBasicBlockRef(BasicBlock * Obb)291 BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; } 292 293 public: 294 bool traverse(SExpr *E, TraversalKind K = TRV_Normal) { 295 Success = Success && this->traverseByCase(E); 296 return Success; 297 } 298 visit(SExpr * E)299 static bool visit(SExpr *E) { 300 Self Visitor; 301 return Visitor.traverse(E, TRV_Normal); 302 } 303 304 private: 305 bool Success; 306 }; 307 308 // Basic class for comparison operations over expressions. 309 template <typename Self> 310 class Comparator { 311 protected: self()312 Self *self() { return reinterpret_cast<Self *>(this); } 313 314 public: compare(const SExpr * E1,const SExpr * E2)315 bool compare(const SExpr *E1, const SExpr *E2) { 316 if (E1->opcode() != E2->opcode()) 317 return false; 318 switch (E1->opcode()) { 319 #define TIL_OPCODE_DEF(X) \ 320 case COP_##X: \ 321 return cast<X>(E1)->compare(cast<X>(E2), *self()); 322 #include "ThreadSafetyOps.def" 323 #undef TIL_OPCODE_DEF 324 } 325 return false; 326 } 327 }; 328 329 class EqualsComparator : public Comparator<EqualsComparator> { 330 public: 331 // Result type for the comparison, e.g. bool for simple equality, 332 // or int for lexigraphic comparison (-1, 0, 1). Must have one value which 333 // denotes "true". 334 using CType = bool; 335 trueResult()336 CType trueResult() { return true; } notTrue(CType ct)337 bool notTrue(CType ct) { return !ct; } 338 compareIntegers(unsigned i,unsigned j)339 bool compareIntegers(unsigned i, unsigned j) { return i == j; } compareStrings(StringRef s,StringRef r)340 bool compareStrings (StringRef s, StringRef r) { return s == r; } comparePointers(const void * P,const void * Q)341 bool comparePointers(const void* P, const void* Q) { return P == Q; } 342 343 // TODO -- handle alpha-renaming of variables enterScope(const Variable * V1,const Variable * V2)344 void enterScope(const Variable *V1, const Variable *V2) {} leaveScope()345 void leaveScope() {} 346 compareVariableRefs(const Variable * V1,const Variable * V2)347 bool compareVariableRefs(const Variable *V1, const Variable *V2) { 348 return V1 == V2; 349 } 350 compareExprs(const SExpr * E1,const SExpr * E2)351 static bool compareExprs(const SExpr *E1, const SExpr* E2) { 352 EqualsComparator Eq; 353 return Eq.compare(E1, E2); 354 } 355 }; 356 357 class MatchComparator : public Comparator<MatchComparator> { 358 public: 359 // Result type for the comparison, e.g. bool for simple equality, 360 // or int for lexigraphic comparison (-1, 0, 1). Must have one value which 361 // denotes "true". 362 using CType = bool; 363 trueResult()364 CType trueResult() { return true; } notTrue(CType ct)365 bool notTrue(CType ct) { return !ct; } 366 compareIntegers(unsigned i,unsigned j)367 bool compareIntegers(unsigned i, unsigned j) { return i == j; } compareStrings(StringRef s,StringRef r)368 bool compareStrings (StringRef s, StringRef r) { return s == r; } comparePointers(const void * P,const void * Q)369 bool comparePointers(const void *P, const void *Q) { return P == Q; } 370 compare(const SExpr * E1,const SExpr * E2)371 bool compare(const SExpr *E1, const SExpr *E2) { 372 // Wildcards match anything. 373 if (E1->opcode() == COP_Wildcard || E2->opcode() == COP_Wildcard) 374 return true; 375 // otherwise normal equality. 376 return Comparator::compare(E1, E2); 377 } 378 379 // TODO -- handle alpha-renaming of variables enterScope(const Variable * V1,const Variable * V2)380 void enterScope(const Variable* V1, const Variable* V2) {} leaveScope()381 void leaveScope() {} 382 compareVariableRefs(const Variable * V1,const Variable * V2)383 bool compareVariableRefs(const Variable* V1, const Variable* V2) { 384 return V1 == V2; 385 } 386 compareExprs(const SExpr * E1,const SExpr * E2)387 static bool compareExprs(const SExpr *E1, const SExpr* E2) { 388 MatchComparator Matcher; 389 return Matcher.compare(E1, E2); 390 } 391 }; 392 393 // inline std::ostream& operator<<(std::ostream& SS, StringRef R) { 394 // return SS.write(R.data(), R.size()); 395 // } 396 397 // Pretty printer for TIL expressions 398 template <typename Self, typename StreamType> 399 class PrettyPrinter { 400 private: 401 // Print out additional information. 402 bool Verbose; 403 404 // Omit redundant decls. 405 bool Cleanup; 406 407 // Print exprs in C-like syntax. 408 bool CStyle; 409 410 public: 411 PrettyPrinter(bool V = false, bool C = true, bool CS = true) Verbose(V)412 : Verbose(V), Cleanup(C), CStyle(CS) {} 413 print(const SExpr * E,StreamType & SS)414 static void print(const SExpr *E, StreamType &SS) { 415 Self printer; 416 printer.printSExpr(E, SS, Prec_MAX); 417 } 418 419 protected: self()420 Self *self() { return reinterpret_cast<Self *>(this); } 421 newline(StreamType & SS)422 void newline(StreamType &SS) { 423 SS << "\n"; 424 } 425 426 // TODO: further distinguish between binary operations. 427 static const unsigned Prec_Atom = 0; 428 static const unsigned Prec_Postfix = 1; 429 static const unsigned Prec_Unary = 2; 430 static const unsigned Prec_Binary = 3; 431 static const unsigned Prec_Other = 4; 432 static const unsigned Prec_Decl = 5; 433 static const unsigned Prec_MAX = 6; 434 435 // Return the precedence of a given node, for use in pretty printing. precedence(const SExpr * E)436 unsigned precedence(const SExpr *E) { 437 switch (E->opcode()) { 438 case COP_Future: return Prec_Atom; 439 case COP_Undefined: return Prec_Atom; 440 case COP_Wildcard: return Prec_Atom; 441 442 case COP_Literal: return Prec_Atom; 443 case COP_LiteralPtr: return Prec_Atom; 444 case COP_Variable: return Prec_Atom; 445 case COP_Function: return Prec_Decl; 446 case COP_SFunction: return Prec_Decl; 447 case COP_Code: return Prec_Decl; 448 case COP_Field: return Prec_Decl; 449 450 case COP_Apply: return Prec_Postfix; 451 case COP_SApply: return Prec_Postfix; 452 case COP_Project: return Prec_Postfix; 453 454 case COP_Call: return Prec_Postfix; 455 case COP_Alloc: return Prec_Other; 456 case COP_Load: return Prec_Postfix; 457 case COP_Store: return Prec_Other; 458 case COP_ArrayIndex: return Prec_Postfix; 459 case COP_ArrayAdd: return Prec_Postfix; 460 461 case COP_UnaryOp: return Prec_Unary; 462 case COP_BinaryOp: return Prec_Binary; 463 case COP_Cast: return Prec_Atom; 464 465 case COP_SCFG: return Prec_Decl; 466 case COP_BasicBlock: return Prec_MAX; 467 case COP_Phi: return Prec_Atom; 468 case COP_Goto: return Prec_Atom; 469 case COP_Branch: return Prec_Atom; 470 case COP_Return: return Prec_Other; 471 472 case COP_Identifier: return Prec_Atom; 473 case COP_IfThenElse: return Prec_Other; 474 case COP_Let: return Prec_Decl; 475 } 476 return Prec_MAX; 477 } 478 printBlockLabel(StreamType & SS,const BasicBlock * BB,int index)479 void printBlockLabel(StreamType & SS, const BasicBlock *BB, int index) { 480 if (!BB) { 481 SS << "BB_null"; 482 return; 483 } 484 SS << "BB_"; 485 SS << BB->blockID(); 486 if (index >= 0) { 487 SS << ":"; 488 SS << index; 489 } 490 } 491 492 void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true) { 493 if (!E) { 494 self()->printNull(SS); 495 return; 496 } 497 if (Sub && E->block() && E->opcode() != COP_Variable) { 498 SS << "_x" << E->id(); 499 return; 500 } 501 if (self()->precedence(E) > P) { 502 // Wrap expr in () if necessary. 503 SS << "("; 504 self()->printSExpr(E, SS, Prec_MAX); 505 SS << ")"; 506 return; 507 } 508 509 switch (E->opcode()) { 510 #define TIL_OPCODE_DEF(X) \ 511 case COP_##X: \ 512 self()->print##X(cast<X>(E), SS); \ 513 return; 514 #include "ThreadSafetyOps.def" 515 #undef TIL_OPCODE_DEF 516 } 517 } 518 printNull(StreamType & SS)519 void printNull(StreamType &SS) { 520 SS << "#null"; 521 } 522 printFuture(const Future * E,StreamType & SS)523 void printFuture(const Future *E, StreamType &SS) { 524 self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom); 525 } 526 printUndefined(const Undefined * E,StreamType & SS)527 void printUndefined(const Undefined *E, StreamType &SS) { 528 SS << "#undefined"; 529 } 530 printWildcard(const Wildcard * E,StreamType & SS)531 void printWildcard(const Wildcard *E, StreamType &SS) { 532 SS << "*"; 533 } 534 535 template<class T> printLiteralT(const LiteralT<T> * E,StreamType & SS)536 void printLiteralT(const LiteralT<T> *E, StreamType &SS) { 537 SS << E->value(); 538 } 539 printLiteralT(const LiteralT<uint8_t> * E,StreamType & SS)540 void printLiteralT(const LiteralT<uint8_t> *E, StreamType &SS) { 541 SS << "'" << E->value() << "'"; 542 } 543 printLiteral(const Literal * E,StreamType & SS)544 void printLiteral(const Literal *E, StreamType &SS) { 545 if (E->clangExpr()) { 546 SS << getSourceLiteralString(E->clangExpr()); 547 return; 548 } 549 else { 550 ValueType VT = E->valueType(); 551 switch (VT.Base) { 552 case ValueType::BT_Void: 553 SS << "void"; 554 return; 555 case ValueType::BT_Bool: 556 if (E->as<bool>().value()) 557 SS << "true"; 558 else 559 SS << "false"; 560 return; 561 case ValueType::BT_Int: 562 switch (VT.Size) { 563 case ValueType::ST_8: 564 if (VT.Signed) 565 printLiteralT(&E->as<int8_t>(), SS); 566 else 567 printLiteralT(&E->as<uint8_t>(), SS); 568 return; 569 case ValueType::ST_16: 570 if (VT.Signed) 571 printLiteralT(&E->as<int16_t>(), SS); 572 else 573 printLiteralT(&E->as<uint16_t>(), SS); 574 return; 575 case ValueType::ST_32: 576 if (VT.Signed) 577 printLiteralT(&E->as<int32_t>(), SS); 578 else 579 printLiteralT(&E->as<uint32_t>(), SS); 580 return; 581 case ValueType::ST_64: 582 if (VT.Signed) 583 printLiteralT(&E->as<int64_t>(), SS); 584 else 585 printLiteralT(&E->as<uint64_t>(), SS); 586 return; 587 default: 588 break; 589 } 590 break; 591 case ValueType::BT_Float: 592 switch (VT.Size) { 593 case ValueType::ST_32: 594 printLiteralT(&E->as<float>(), SS); 595 return; 596 case ValueType::ST_64: 597 printLiteralT(&E->as<double>(), SS); 598 return; 599 default: 600 break; 601 } 602 break; 603 case ValueType::BT_String: 604 SS << "\""; 605 printLiteralT(&E->as<StringRef>(), SS); 606 SS << "\""; 607 return; 608 case ValueType::BT_Pointer: 609 SS << "#ptr"; 610 return; 611 case ValueType::BT_ValueRef: 612 SS << "#vref"; 613 return; 614 } 615 } 616 SS << "#lit"; 617 } 618 printLiteralPtr(const LiteralPtr * E,StreamType & SS)619 void printLiteralPtr(const LiteralPtr *E, StreamType &SS) { 620 if (const NamedDecl *D = E->clangDecl()) 621 SS << D->getNameAsString(); 622 else 623 SS << "<temporary>"; 624 } 625 626 void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) { 627 if (CStyle && V->kind() == Variable::VK_SFun) 628 SS << "this"; 629 else 630 SS << V->name() << V->id(); 631 } 632 633 void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) { 634 switch (sugared) { 635 default: 636 SS << "\\("; // Lambda 637 break; 638 case 1: 639 SS << "("; // Slot declarations 640 break; 641 case 2: 642 SS << ", "; // Curried functions 643 break; 644 } 645 self()->printVariable(E->variableDecl(), SS, true); 646 SS << ": "; 647 self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX); 648 649 const SExpr *B = E->body(); 650 if (B && B->opcode() == COP_Function) 651 self()->printFunction(cast<Function>(B), SS, 2); 652 else { 653 SS << ")"; 654 self()->printSExpr(B, SS, Prec_Decl); 655 } 656 } 657 printSFunction(const SFunction * E,StreamType & SS)658 void printSFunction(const SFunction *E, StreamType &SS) { 659 SS << "@"; 660 self()->printVariable(E->variableDecl(), SS, true); 661 SS << " "; 662 self()->printSExpr(E->body(), SS, Prec_Decl); 663 } 664 printCode(const Code * E,StreamType & SS)665 void printCode(const Code *E, StreamType &SS) { 666 SS << ": "; 667 self()->printSExpr(E->returnType(), SS, Prec_Decl-1); 668 SS << " -> "; 669 self()->printSExpr(E->body(), SS, Prec_Decl); 670 } 671 printField(const Field * E,StreamType & SS)672 void printField(const Field *E, StreamType &SS) { 673 SS << ": "; 674 self()->printSExpr(E->range(), SS, Prec_Decl-1); 675 SS << " = "; 676 self()->printSExpr(E->body(), SS, Prec_Decl); 677 } 678 679 void printApply(const Apply *E, StreamType &SS, bool sugared = false) { 680 const SExpr *F = E->fun(); 681 if (F->opcode() == COP_Apply) { 682 printApply(cast<Apply>(F), SS, true); 683 SS << ", "; 684 } else { 685 self()->printSExpr(F, SS, Prec_Postfix); 686 SS << "("; 687 } 688 self()->printSExpr(E->arg(), SS, Prec_MAX); 689 if (!sugared) 690 SS << ")$"; 691 } 692 printSApply(const SApply * E,StreamType & SS)693 void printSApply(const SApply *E, StreamType &SS) { 694 self()->printSExpr(E->sfun(), SS, Prec_Postfix); 695 if (E->isDelegation()) { 696 SS << "@("; 697 self()->printSExpr(E->arg(), SS, Prec_MAX); 698 SS << ")"; 699 } 700 } 701 printProject(const Project * E,StreamType & SS)702 void printProject(const Project *E, StreamType &SS) { 703 if (CStyle) { 704 // Omit the this-> 705 if (const auto *SAP = dyn_cast<SApply>(E->record())) { 706 if (const auto *V = dyn_cast<Variable>(SAP->sfun())) { 707 if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) { 708 SS << E->slotName(); 709 return; 710 } 711 } 712 } 713 if (isa<Wildcard>(E->record())) { 714 // handle existentials 715 SS << "&"; 716 SS << E->clangDecl()->getQualifiedNameAsString(); 717 return; 718 } 719 } 720 self()->printSExpr(E->record(), SS, Prec_Postfix); 721 if (CStyle && E->isArrow()) 722 SS << "->"; 723 else 724 SS << "."; 725 SS << E->slotName(); 726 } 727 printCall(const Call * E,StreamType & SS)728 void printCall(const Call *E, StreamType &SS) { 729 const SExpr *T = E->target(); 730 if (T->opcode() == COP_Apply) { 731 self()->printApply(cast<Apply>(T), SS, true); 732 SS << ")"; 733 } 734 else { 735 self()->printSExpr(T, SS, Prec_Postfix); 736 SS << "()"; 737 } 738 } 739 printAlloc(const Alloc * E,StreamType & SS)740 void printAlloc(const Alloc *E, StreamType &SS) { 741 SS << "new "; 742 self()->printSExpr(E->dataType(), SS, Prec_Other-1); 743 } 744 printLoad(const Load * E,StreamType & SS)745 void printLoad(const Load *E, StreamType &SS) { 746 self()->printSExpr(E->pointer(), SS, Prec_Postfix); 747 if (!CStyle) 748 SS << "^"; 749 } 750 printStore(const Store * E,StreamType & SS)751 void printStore(const Store *E, StreamType &SS) { 752 self()->printSExpr(E->destination(), SS, Prec_Other-1); 753 SS << " := "; 754 self()->printSExpr(E->source(), SS, Prec_Other-1); 755 } 756 printArrayIndex(const ArrayIndex * E,StreamType & SS)757 void printArrayIndex(const ArrayIndex *E, StreamType &SS) { 758 self()->printSExpr(E->array(), SS, Prec_Postfix); 759 SS << "["; 760 self()->printSExpr(E->index(), SS, Prec_MAX); 761 SS << "]"; 762 } 763 printArrayAdd(const ArrayAdd * E,StreamType & SS)764 void printArrayAdd(const ArrayAdd *E, StreamType &SS) { 765 self()->printSExpr(E->array(), SS, Prec_Postfix); 766 SS << " + "; 767 self()->printSExpr(E->index(), SS, Prec_Atom); 768 } 769 printUnaryOp(const UnaryOp * E,StreamType & SS)770 void printUnaryOp(const UnaryOp *E, StreamType &SS) { 771 SS << getUnaryOpcodeString(E->unaryOpcode()); 772 self()->printSExpr(E->expr(), SS, Prec_Unary); 773 } 774 printBinaryOp(const BinaryOp * E,StreamType & SS)775 void printBinaryOp(const BinaryOp *E, StreamType &SS) { 776 self()->printSExpr(E->expr0(), SS, Prec_Binary-1); 777 SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " "; 778 self()->printSExpr(E->expr1(), SS, Prec_Binary-1); 779 } 780 printCast(const Cast * E,StreamType & SS)781 void printCast(const Cast *E, StreamType &SS) { 782 if (!CStyle) { 783 SS << "cast["; 784 switch (E->castOpcode()) { 785 case CAST_none: 786 SS << "none"; 787 break; 788 case CAST_extendNum: 789 SS << "extendNum"; 790 break; 791 case CAST_truncNum: 792 SS << "truncNum"; 793 break; 794 case CAST_toFloat: 795 SS << "toFloat"; 796 break; 797 case CAST_toInt: 798 SS << "toInt"; 799 break; 800 case CAST_objToPtr: 801 SS << "objToPtr"; 802 break; 803 } 804 SS << "]("; 805 self()->printSExpr(E->expr(), SS, Prec_Unary); 806 SS << ")"; 807 return; 808 } 809 self()->printSExpr(E->expr(), SS, Prec_Unary); 810 } 811 printSCFG(const SCFG * E,StreamType & SS)812 void printSCFG(const SCFG *E, StreamType &SS) { 813 SS << "CFG {\n"; 814 for (const auto *BBI : *E) 815 printBasicBlock(BBI, SS); 816 SS << "}"; 817 newline(SS); 818 } 819 printBBInstr(const SExpr * E,StreamType & SS)820 void printBBInstr(const SExpr *E, StreamType &SS) { 821 bool Sub = false; 822 if (E->opcode() == COP_Variable) { 823 const auto *V = cast<Variable>(E); 824 SS << "let " << V->name() << V->id() << " = "; 825 E = V->definition(); 826 Sub = true; 827 } 828 else if (E->opcode() != COP_Store) { 829 SS << "let _x" << E->id() << " = "; 830 } 831 self()->printSExpr(E, SS, Prec_MAX, Sub); 832 SS << ";"; 833 newline(SS); 834 } 835 printBasicBlock(const BasicBlock * E,StreamType & SS)836 void printBasicBlock(const BasicBlock *E, StreamType &SS) { 837 SS << "BB_" << E->blockID() << ":"; 838 if (E->parent()) 839 SS << " BB_" << E->parent()->blockID(); 840 newline(SS); 841 842 for (const auto *A : E->arguments()) 843 printBBInstr(A, SS); 844 845 for (const auto *I : E->instructions()) 846 printBBInstr(I, SS); 847 848 const SExpr *T = E->terminator(); 849 if (T) { 850 self()->printSExpr(T, SS, Prec_MAX, false); 851 SS << ";"; 852 newline(SS); 853 } 854 newline(SS); 855 } 856 printPhi(const Phi * E,StreamType & SS)857 void printPhi(const Phi *E, StreamType &SS) { 858 SS << "phi("; 859 if (E->status() == Phi::PH_SingleVal) 860 self()->printSExpr(E->values()[0], SS, Prec_MAX); 861 else { 862 unsigned i = 0; 863 for (const auto *V : E->values()) { 864 if (i++ > 0) 865 SS << ", "; 866 self()->printSExpr(V, SS, Prec_MAX); 867 } 868 } 869 SS << ")"; 870 } 871 printGoto(const Goto * E,StreamType & SS)872 void printGoto(const Goto *E, StreamType &SS) { 873 SS << "goto "; 874 printBlockLabel(SS, E->targetBlock(), E->index()); 875 } 876 printBranch(const Branch * E,StreamType & SS)877 void printBranch(const Branch *E, StreamType &SS) { 878 SS << "branch ("; 879 self()->printSExpr(E->condition(), SS, Prec_MAX); 880 SS << ") "; 881 printBlockLabel(SS, E->thenBlock(), -1); 882 SS << " "; 883 printBlockLabel(SS, E->elseBlock(), -1); 884 } 885 printReturn(const Return * E,StreamType & SS)886 void printReturn(const Return *E, StreamType &SS) { 887 SS << "return "; 888 self()->printSExpr(E->returnValue(), SS, Prec_Other); 889 } 890 printIdentifier(const Identifier * E,StreamType & SS)891 void printIdentifier(const Identifier *E, StreamType &SS) { 892 SS << E->name(); 893 } 894 printIfThenElse(const IfThenElse * E,StreamType & SS)895 void printIfThenElse(const IfThenElse *E, StreamType &SS) { 896 if (CStyle) { 897 printSExpr(E->condition(), SS, Prec_Unary); 898 SS << " ? "; 899 printSExpr(E->thenExpr(), SS, Prec_Unary); 900 SS << " : "; 901 printSExpr(E->elseExpr(), SS, Prec_Unary); 902 return; 903 } 904 SS << "if ("; 905 printSExpr(E->condition(), SS, Prec_MAX); 906 SS << ") then "; 907 printSExpr(E->thenExpr(), SS, Prec_Other); 908 SS << " else "; 909 printSExpr(E->elseExpr(), SS, Prec_Other); 910 } 911 printLet(const Let * E,StreamType & SS)912 void printLet(const Let *E, StreamType &SS) { 913 SS << "let "; 914 printVariable(E->variableDecl(), SS, true); 915 SS << " = "; 916 printSExpr(E->variableDecl()->definition(), SS, Prec_Decl-1); 917 SS << "; "; 918 printSExpr(E->body(), SS, Prec_Decl-1); 919 } 920 }; 921 922 class StdPrinter : public PrettyPrinter<StdPrinter, std::ostream> {}; 923 924 } // namespace til 925 } // namespace threadSafety 926 } // namespace clang 927 928 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H 929