clang 23.0.0git
ThreadSafetyTraverse.h
Go to the documentation of this file.
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/AST/Expr.h"
23#include "clang/Basic/LLVM.h"
24#include "llvm/ADT/StringRef.h"
25#include "llvm/Support/Casting.h"
26#include <cstdint>
27#include <ostream>
28
29namespace clang {
30namespace threadSafety {
31namespace til {
32
33// Defines an interface used to traverse SExprs. Traversals have been made as
34// generic as possible, and are intended to handle any kind of pass over the
35// AST, e.g. visitors, copying, non-destructive rewriting, destructive
36// (in-place) rewriting, hashing, typing, etc.
37//
38// Traversals implement the functional notion of a "fold" operation on SExprs.
39// Each SExpr class provides a traverse method, which does the following:
40// * e->traverse(v):
41// // compute a result r_i for each subexpression e_i
42// for (i = 1..n) r_i = v.traverse(e_i);
43// // combine results into a result for e, where X is the class of e
44// return v.reduceX(*e, r_1, .. r_n).
45//
46// A visitor can control the traversal by overriding the following methods:
47// * v.traverse(e):
48// return v.traverseByCase(e), which returns v.traverseX(e)
49// * v.traverseX(e): (X is the class of e)
50// return e->traverse(v).
51// * v.reduceX(*e, r_1, .. r_n):
52// compute a result for a node of type X
53//
54// The reduceX methods control the kind of traversal (visitor, copy, etc.).
55// They are defined in derived classes.
56//
57// Class R defines the basic interface types (R_SExpr).
58template <class Self, class R>
59class Traversal {
60public:
61 Self *self() { return static_cast<Self *>(this); }
62
63 // Traverse an expression -- returning a result of type R_SExpr.
64 // Override this method to do something for every expression, regardless
65 // of which kind it is.
66 // E is a reference, so this can be use for in-place updates.
67 // The type T must be a subclass of SExpr.
68 template <class T>
69 typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) {
70 return traverseSExpr(E, Ctx);
71 }
72
73 // Override this method to do something for every expression.
74 // Does not allow in-place updates.
75 typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) {
76 return traverseByCase(E, Ctx);
77 }
78
79 // Helper method to call traverseX(e) on the appropriate type.
80 typename R::R_SExpr traverseByCase(SExpr *E, typename R::R_Ctx Ctx) {
81 switch (E->opcode()) {
82#define TIL_OPCODE_DEF(X) \
83 case COP_##X: \
84 return self()->traverse##X(cast<X>(E), Ctx);
85#include "ThreadSafetyOps.def"
86#undef TIL_OPCODE_DEF
87 }
88 return self()->reduceNull();
89 }
90
91// Traverse e, by static dispatch on the type "X" of e.
92// Override these methods to do something for a particular kind of term.
93#define TIL_OPCODE_DEF(X) \
94 typename R::R_SExpr traverse##X(X *e, typename R::R_Ctx Ctx) { \
95 return e->traverse(*self(), Ctx); \
96 }
97#include "ThreadSafetyOps.def"
98#undef TIL_OPCODE_DEF
99};
100
101// Base class for simple reducers that don't much care about the context.
103public:
105 // Ordinary subexpressions.
107
108 // Declarations (e.g. function bodies).
110
111 // Expressions that require lazy evaluation.
113
114 // Type expressions.
116 };
117
118 // R_Ctx defines a "context" for the traversal, which encodes information
119 // about where a term appears. This can be used to encoding the
120 // "current continuation" for CPS transforms, or other information.
122
123 // Create context for an ordinary subexpression.
125
126 // Create context for a subexpression that occurs in a declaration position
127 // (e.g. function body).
128 R_Ctx declCtx(R_Ctx Ctx) { return TRV_Decl; }
129
130 // Create context for a subexpression that occurs in a position that
131 // should be reduced lazily. (e.g. code body).
132 R_Ctx lazyCtx(R_Ctx Ctx) { return TRV_Lazy; }
133
134 // Create context for a subexpression that occurs in a type position.
135 R_Ctx typeCtx(R_Ctx Ctx) { return TRV_Type; }
136};
137
138// Base class for traversals that rewrite an SExpr to another SExpr.
140public:
141 // R_SExpr is the result type for a traversal.
142 // A copy or non-destructive rewrite returns a newly allocated term.
143 using R_SExpr = SExpr *;
145
146 // Container is a minimal interface used to store results when traversing
147 // SExprs of variable arity, such as Phi, Goto, and SCFG.
148 template <class T> class Container {
149 public:
150 // Allocate a new container with a capacity for n elements.
151 Container(CopyReducerBase &S, unsigned N) : Elems(S.Arena, N) {}
152
153 // Push a new element onto the container.
154 void push_back(T E) { Elems.push_back(E); }
155
157 };
158
160
161protected:
163};
164
165// Base class for visit traversals.
167public:
168 // A visitor returns a bool, representing success or failure.
169 using R_SExpr = bool;
171
172 // A visitor "container" is a single bool, which accumulates success.
173 template <class T> class Container {
174 public:
175 bool Success = true;
176
177 Container(VisitReducerBase &S, unsigned N) {}
178
179 void push_back(bool E) { Success = Success && E; }
180 };
181};
182
183// Implements a traversal that visits each subexpression, and returns either
184// true or false.
185template <class Self>
186class VisitReducer : public Traversal<Self, VisitReducerBase>,
187 public VisitReducerBase {
188public:
189 VisitReducer() = default;
190
191public:
192 R_SExpr reduceNull() { return true; }
193 R_SExpr reduceUndefined(Undefined &Orig) { return true; }
194 R_SExpr reduceWildcard(Wildcard &Orig) { return true; }
195
196 template<class T>
197 R_SExpr reduceLiteralT(LiteralT<T> &Orig) { return true; }
198 R_SExpr reduceLiteralPtr(Literal &Orig) { return true; }
199
201 return Nvd && E0;
202 }
203
205 return Nvd && E0;
206 }
207
209 return E0 && E1;
210 }
211
213 return E0 && E1;
214 }
215
217 return E0 && E1;
218 }
219
221 return E0 && E1;
222 }
223
224 R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; }
225 R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; }
226 R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; }
227 R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; }
228 R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; }
229
231 return E0 && E1;
232 }
233
235 return E0 && E1;
236 }
237
238 R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; }
239
241 return E0 && E1;
242 }
243
244 R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; }
245
247 return Bbs.Success;
248 }
249
252 return (As.Success && Is.Success && T);
253 }
254
256 return As.Success;
257 }
258
260 return true;
261 }
262
264 return C;
265 }
266
268 return E;
269 }
270
272 return true;
273 }
274
276 return C && T && E;
277 }
278
280 return Nvd && B;
281 }
282
283 Variable *enterScope(Variable &Orig, R_SExpr E0) { return &Orig; }
284 void exitScope(const Variable &Orig) {}
285 void enterCFG(SCFG &Cfg) {}
286 void exitCFG(SCFG &Cfg) {}
289
290 Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
292
293public:
295 Success = Success && this->traverseByCase(E);
296 return Success;
297 }
298
299 static bool visit(SExpr *E) {
300 Self Visitor;
301 return Visitor.traverse(E, TRV_Normal);
302 }
303
304private:
305 bool Success;
306};
307
308// Basic class for comparison operations over expressions.
309template <typename Self>
311protected:
312 Self *self() { return reinterpret_cast<Self *>(this); }
313
314public:
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
329class EqualsComparator : public Comparator<EqualsComparator> {
330public:
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
336 CType trueResult() { return true; }
337 bool notTrue(CType ct) { return !ct; }
338
339 bool compareIntegers(uint64_t i, uint64_t j) { return i == j; }
340 bool compareStrings (StringRef s, StringRef r) { return s == r; }
341 bool comparePointers(const void* P, const void* Q) { return P == Q; }
342
343 // TODO -- handle alpha-renaming of variables
344 void enterScope(const Variable *V1, const Variable *V2) {}
345 void leaveScope() {}
346
347 bool compareVariableRefs(const Variable *V1, const Variable *V2) {
348 return V1 == V2;
349 }
350
351 static bool compareExprs(const SExpr *E1, const SExpr* E2) {
353 return Eq.compare(E1, E2);
354 }
355};
356
357class MatchComparator : public Comparator<MatchComparator> {
358public:
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
364 CType trueResult() { return true; }
365 bool notTrue(CType ct) { return !ct; }
366
367 bool compareIntegers(uint64_t i, uint64_t j) { return i == j; }
368 bool compareStrings (StringRef s, StringRef r) { return s == r; }
369 bool comparePointers(const void *P, const void *Q) { return P == Q; }
370
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
380 void enterScope(const Variable* V1, const Variable* V2) {}
381 void leaveScope() {}
382
383 bool compareVariableRefs(const Variable* V1, const Variable* V2) {
384 return V1 == V2;
385 }
386
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
398template <typename Self, typename StreamType>
400private:
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
410public:
411 PrettyPrinter(bool V = false, bool C = true, bool CS = true)
412 : Verbose(V), Cleanup(C), CStyle(CS) {}
413
414 static void print(const SExpr *E, StreamType &SS) {
415 Self printer;
416 printer.printSExpr(E, SS, Prec_MAX);
417 }
418
419protected:
420 Self *self() { return reinterpret_cast<Self *>(this); }
421
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.
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
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
519 void printNull(StreamType &SS) {
520 SS << "#null";
521 }
522
523 void printFuture(const Future *E, StreamType &SS) {
524 self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom);
525 }
526
527 void printUndefined(const Undefined *E, StreamType &SS) {
528 SS << "#undefined";
529 }
530
531 void printWildcard(const Wildcard *E, StreamType &SS) {
532 SS << "*";
533 }
534
535 void printLiteral(const Literal *E, StreamType &SS) {
536 ValueType VT = E->valueType();
537 switch (VT.Base) {
539 if (E->as<bool>().value())
540 SS << "true";
541 else
542 SS << "false";
543 return;
545 CharacterLiteral::print(E->as<char32_t>().value(),
547 return;
549 SS << E->as<int64_t>().value();
550 return;
552 SS << E->as<uint64_t>().value();
553 return;
555 SS << '\"' << E->as<StringRef>().value() << '\"';
556 return;
558 assert(E->as<std::nullptr_t>().value() == nullptr);
559 SS << "nullptr";
560 return;
561 }
562 llvm_unreachable("Invalid BaseType");
563 }
564
565 void printLiteralPtr(const LiteralPtr *E, StreamType &SS) {
566 if (const NamedDecl *D = E->clangDecl())
567 SS << D->getNameAsString();
568 else
569 SS << "<temporary>";
570 }
571
572 void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) {
573 if (CStyle && V->kind() == Variable::VK_SFun)
574 SS << "this";
575 else
576 SS << V->name() << V->id();
577 }
578
579 void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) {
580 switch (sugared) {
581 default:
582 SS << "\\("; // Lambda
583 break;
584 case 1:
585 SS << "("; // Slot declarations
586 break;
587 case 2:
588 SS << ", "; // Curried functions
589 break;
590 }
591 self()->printVariable(E->variableDecl(), SS, true);
592 SS << ": ";
593 self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX);
594
595 const SExpr *B = E->body();
596 if (B && B->opcode() == COP_Function)
597 self()->printFunction(cast<Function>(B), SS, 2);
598 else {
599 SS << ")";
600 self()->printSExpr(B, SS, Prec_Decl);
601 }
602 }
603
604 void printSFunction(const SFunction *E, StreamType &SS) {
605 SS << "@";
606 self()->printVariable(E->variableDecl(), SS, true);
607 SS << " ";
608 self()->printSExpr(E->body(), SS, Prec_Decl);
609 }
610
611 void printCode(const Code *E, StreamType &SS) {
612 SS << ": ";
613 self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
614 SS << " -> ";
615 self()->printSExpr(E->body(), SS, Prec_Decl);
616 }
617
618 void printField(const Field *E, StreamType &SS) {
619 SS << ": ";
620 self()->printSExpr(E->range(), SS, Prec_Decl-1);
621 SS << " = ";
622 self()->printSExpr(E->body(), SS, Prec_Decl);
623 }
624
625 void printApply(const Apply *E, StreamType &SS, bool sugared = false) {
626 const SExpr *F = E->fun();
627 if (F->opcode() == COP_Apply) {
628 printApply(cast<Apply>(F), SS, true);
629 SS << ", ";
630 } else {
631 self()->printSExpr(F, SS, Prec_Postfix);
632 SS << "(";
633 }
634 self()->printSExpr(E->arg(), SS, Prec_MAX);
635 if (!sugared)
636 SS << ")$";
637 }
638
639 void printSApply(const SApply *E, StreamType &SS) {
640 self()->printSExpr(E->sfun(), SS, Prec_Postfix);
641 if (E->isDelegation()) {
642 SS << "@(";
643 self()->printSExpr(E->arg(), SS, Prec_MAX);
644 SS << ")";
645 }
646 }
647
648 void printProject(const Project *E, StreamType &SS) {
649 if (CStyle) {
650 // Omit the this->
651 if (const auto *SAP = dyn_cast<SApply>(E->record())) {
652 if (const auto *V = dyn_cast<Variable>(SAP->sfun())) {
653 if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) {
654 SS << E->slotName();
655 return;
656 }
657 }
658 }
659 if (isa<Wildcard>(E->record())) {
660 // handle existentials
661 SS << "&";
663 return;
664 }
665 }
666 self()->printSExpr(E->record(), SS, Prec_Postfix);
667 if (CStyle && E->isArrow())
668 SS << "->";
669 else
670 SS << ".";
671 SS << E->slotName();
672 }
673
674 void printCall(const Call *E, StreamType &SS) {
675 const SExpr *T = E->target();
676 if (T->opcode() == COP_Apply) {
677 self()->printApply(cast<Apply>(T), SS, true);
678 SS << ")";
679 }
680 else {
681 self()->printSExpr(T, SS, Prec_Postfix);
682 SS << "()";
683 }
684 }
685
686 void printAlloc(const Alloc *E, StreamType &SS) {
687 SS << "new ";
688 self()->printSExpr(E->dataType(), SS, Prec_Other-1);
689 }
690
691 void printLoad(const Load *E, StreamType &SS) {
692 self()->printSExpr(E->pointer(), SS, Prec_Postfix);
693 if (!CStyle)
694 SS << "^";
695 }
696
697 void printStore(const Store *E, StreamType &SS) {
698 self()->printSExpr(E->destination(), SS, Prec_Other-1);
699 SS << " := ";
700 self()->printSExpr(E->source(), SS, Prec_Other-1);
701 }
702
703 void printArrayIndex(const ArrayIndex *E, StreamType &SS) {
704 self()->printSExpr(E->array(), SS, Prec_Postfix);
705 SS << "[";
706 self()->printSExpr(E->index(), SS, Prec_MAX);
707 SS << "]";
708 }
709
710 void printArrayAdd(const ArrayAdd *E, StreamType &SS) {
711 self()->printSExpr(E->array(), SS, Prec_Postfix);
712 SS << " + ";
713 self()->printSExpr(E->index(), SS, Prec_Atom);
714 }
715
716 void printUnaryOp(const UnaryOp *E, StreamType &SS) {
718 self()->printSExpr(E->expr(), SS, Prec_Unary);
719 }
720
721 void printBinaryOp(const BinaryOp *E, StreamType &SS) {
722 self()->printSExpr(E->expr0(), SS, Prec_Binary-1);
723 SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " ";
724 self()->printSExpr(E->expr1(), SS, Prec_Binary-1);
725 }
726
727 void printCast(const Cast *E, StreamType &SS) {
728 if (!CStyle) {
729 SS << "cast[";
730 switch (E->castOpcode()) {
731 case CAST_none:
732 SS << "none";
733 break;
734 case CAST_extendNum:
735 SS << "extendNum";
736 break;
737 case CAST_truncNum:
738 SS << "truncNum";
739 break;
740 case CAST_toFloat:
741 SS << "toFloat";
742 break;
743 case CAST_toInt:
744 SS << "toInt";
745 break;
746 case CAST_objToPtr:
747 SS << "objToPtr";
748 break;
749 }
750 SS << "](";
751 self()->printSExpr(E->expr(), SS, Prec_Unary);
752 SS << ")";
753 return;
754 }
755 self()->printSExpr(E->expr(), SS, Prec_Unary);
756 }
757
758 void printSCFG(const SCFG *E, StreamType &SS) {
759 SS << "CFG {\n";
760 for (const auto *BBI : *E)
761 printBasicBlock(BBI, SS);
762 SS << "}";
763 newline(SS);
764 }
765
766 void printBBInstr(const SExpr *E, StreamType &SS) {
767 bool Sub = false;
768 if (E->opcode() == COP_Variable) {
769 const auto *V = cast<Variable>(E);
770 SS << "let " << V->name() << V->id() << " = ";
771 E = V->definition();
772 Sub = true;
773 }
774 else if (E->opcode() != COP_Store) {
775 SS << "let _x" << E->id() << " = ";
776 }
777 self()->printSExpr(E, SS, Prec_MAX, Sub);
778 SS << ";";
779 newline(SS);
780 }
781
782 void printBasicBlock(const BasicBlock *E, StreamType &SS) {
783 SS << "BB_" << E->blockID() << ":";
784 if (E->parent())
785 SS << " BB_" << E->parent()->blockID();
786 newline(SS);
787
788 for (const auto *A : E->arguments())
789 printBBInstr(A, SS);
790
791 for (const auto *I : E->instructions())
792 printBBInstr(I, SS);
793
794 const SExpr *T = E->terminator();
795 if (T) {
796 self()->printSExpr(T, SS, Prec_MAX, false);
797 SS << ";";
798 newline(SS);
799 }
800 newline(SS);
801 }
802
803 void printPhi(const Phi *E, StreamType &SS) {
804 SS << "phi(";
805 if (E->status() == Phi::PH_SingleVal)
806 self()->printSExpr(E->values()[0], SS, Prec_MAX);
807 else {
808 unsigned i = 0;
809 for (const auto *V : E->values()) {
810 if (i++ > 0)
811 SS << ", ";
812 self()->printSExpr(V, SS, Prec_MAX);
813 }
814 }
815 SS << ")";
816 }
817
818 void printGoto(const Goto *E, StreamType &SS) {
819 SS << "goto ";
820 printBlockLabel(SS, E->targetBlock(), E->index());
821 }
822
823 void printBranch(const Branch *E, StreamType &SS) {
824 SS << "branch (";
825 self()->printSExpr(E->condition(), SS, Prec_MAX);
826 SS << ") ";
827 printBlockLabel(SS, E->thenBlock(), -1);
828 SS << " ";
829 printBlockLabel(SS, E->elseBlock(), -1);
830 }
831
832 void printReturn(const Return *E, StreamType &SS) {
833 SS << "return ";
834 self()->printSExpr(E->returnValue(), SS, Prec_Other);
835 }
836
837 void printIdentifier(const Identifier *E, StreamType &SS) {
838 SS << E->name();
839 }
840
841 void printIfThenElse(const IfThenElse *E, StreamType &SS) {
842 if (CStyle) {
844 SS << " ? ";
845 printSExpr(E->thenExpr(), SS, Prec_Unary);
846 SS << " : ";
847 printSExpr(E->elseExpr(), SS, Prec_Unary);
848 return;
849 }
850 SS << "if (";
851 printSExpr(E->condition(), SS, Prec_MAX);
852 SS << ") then ";
853 printSExpr(E->thenExpr(), SS, Prec_Other);
854 SS << " else ";
855 printSExpr(E->elseExpr(), SS, Prec_Other);
856 }
857
858 void printLet(const Let *E, StreamType &SS) {
859 SS << "let ";
860 printVariable(E->variableDecl(), SS, true);
861 SS << " = ";
863 SS << "; ";
864 printSExpr(E->body(), SS, Prec_Decl-1);
865 }
866};
867
868class StdPrinter : public PrettyPrinter<StdPrinter, llvm::raw_ostream> {};
869
870} // namespace til
871} // namespace threadSafety
872} // namespace clang
873
874#endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
#define V(N, I)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
__device__ __2f16 float __ockl_bool s
static void print(unsigned val, CharacterLiteralKind Kind, raw_ostream &OS)
Definition Expr.cpp:1020
This represents a decl that may have a name.
Definition Decl.h:274
std::string getQualifiedNameAsString() const
Definition Decl.cpp:1680
Allocate memory for a new value on the heap or stack.
Apply an argument to a function.
Pointer arithmetic, restricted to arrays only.
If p is a reference to an array, then p[i] is a reference to the i'th element of the array.
A basic block is part of an SCFG.
int blockID() const
Returns the block ID. Every block has a unique ID in the CFG.
const InstrArray & arguments() const
const Terminator * terminator() const
const BasicBlock * parent() const
Simple arithmetic binary operations, e.g.
TIL_BinaryOpcode binaryOpcode() const
A conditional branch to two other blocks.
const BasicBlock * elseBlock() const
const BasicBlock * thenBlock() const
Call a function (after all arguments have been applied).
TIL_CastOpcode castOpcode() const
A block of code – e.g. the body of a function.
bool compare(const SExpr *E1, const SExpr *E2)
bool comparePointers(const void *P, const void *Q)
bool compareStrings(StringRef s, StringRef r)
void enterScope(const Variable *V1, const Variable *V2)
bool compareVariableRefs(const Variable *V1, const Variable *V2)
static bool compareExprs(const SExpr *E1, const SExpr *E2)
A typed, writable location in memory.
A function – a.k.a.
Placeholder for an expression that has not yet been created.
Jump to another basic block.
unsigned index() const
Returns the index into the.
const BasicBlock * targetBlock() const
A Literal pointer to an object allocated in memory.
const ValueDecl * clangDecl() const
const LiteralT< T > & as() const
Load a value from memory.
bool compareVariableRefs(const Variable *V1, const Variable *V2)
bool comparePointers(const void *P, const void *Q)
static bool compareExprs(const SExpr *E1, const SExpr *E2)
bool compare(const SExpr *E1, const SExpr *E2)
bool compareStrings(StringRef s, StringRef r)
void enterScope(const Variable *V1, const Variable *V2)
Phi Node, for code in SSA form.
const ValArray & values() const
void printFuture(const Future *E, StreamType &SS)
void printCall(const Call *E, StreamType &SS)
void printApply(const Apply *E, StreamType &SS, bool sugared=false)
void printProject(const Project *E, StreamType &SS)
void printWildcard(const Wildcard *E, StreamType &SS)
void printBranch(const Branch *E, StreamType &SS)
void printLet(const Let *E, StreamType &SS)
void printLiteral(const Literal *E, StreamType &SS)
void printField(const Field *E, StreamType &SS)
void printUnaryOp(const UnaryOp *E, StreamType &SS)
void printUndefined(const Undefined *E, StreamType &SS)
void printIdentifier(const Identifier *E, StreamType &SS)
static void print(const SExpr *E, StreamType &SS)
void printReturn(const Return *E, StreamType &SS)
void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false)
void printCode(const Code *E, StreamType &SS)
void printStore(const Store *E, StreamType &SS)
void printCast(const Cast *E, StreamType &SS)
void printIfThenElse(const IfThenElse *E, StreamType &SS)
void printBasicBlock(const BasicBlock *E, StreamType &SS)
void printLiteralPtr(const LiteralPtr *E, StreamType &SS)
void printGoto(const Goto *E, StreamType &SS)
void printBBInstr(const SExpr *E, StreamType &SS)
void printAlloc(const Alloc *E, StreamType &SS)
void printPhi(const Phi *E, StreamType &SS)
void printSCFG(const SCFG *E, StreamType &SS)
void printFunction(const Function *E, StreamType &SS, unsigned sugared=0)
void printBinaryOp(const BinaryOp *E, StreamType &SS)
void printArrayAdd(const ArrayAdd *E, StreamType &SS)
void printSFunction(const SFunction *E, StreamType &SS)
void printArrayIndex(const ArrayIndex *E, StreamType &SS)
void printSApply(const SApply *E, StreamType &SS)
void printLoad(const Load *E, StreamType &SS)
PrettyPrinter(bool V=false, bool C=true, bool CS=true)
void printBlockLabel(StreamType &SS, const BasicBlock *BB, int index)
void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true)
Project a named slot from a C++ struct or class.
const ValueDecl * clangDecl() const
Return from the enclosing function, passing the return value to the caller.
Apply a self-argument to a self-applicable function.
An SCFG is a control-flow graph.
Base class for AST nodes in the typed intermediate language.
BasicBlock * block() const
Returns the block, if this is an instruction in a basic block, otherwise returns null.
unsigned id() const
Returns the instruction ID for this expression.
A self-applicable function.
Store a value to memory.
R::R_SExpr traverse(T *&E, typename R::R_Ctx Ctx)
R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx)
R::R_SExpr traverseByCase(SExpr *E, typename R::R_Ctx Ctx)
Simple arithmetic unary operations, e.g.
TIL_UnaryOpcode unaryOpcode() const
Placeholder for expressions that cannot be represented in the TIL.
SExpr * definition()
Return the definition of the variable.
@ VK_SFun
SFunction (self) parameter.
Variable * enterScope(Variable &Orig, R_SExpr E0)
R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1)
R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1)
R_SExpr reduceProject(Project &Orig, R_SExpr E0)
R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B)
R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1)
R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0)
R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0)
R_SExpr reduceSCFG(SCFG &Orig, Container< BasicBlock * > Bbs)
R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1)
R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container< R_SExpr > &As, Container< R_SExpr > &Is, R_SExpr T)
BasicBlock * reduceBasicBlockRef(BasicBlock *Obb)
R_SExpr reduceGoto(Goto &Orig, BasicBlock *B)
bool traverse(SExpr *E, TraversalKind K=TRV_Normal)
R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1)
R_SExpr reducePhi(Phi &Orig, Container< R_SExpr > &As)
R_SExpr reduceLoad(Load &Orig, R_SExpr E0)
R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1)
R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0)
R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1)
R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0)
R_SExpr reduceLiteralT(LiteralT< T > &Orig)
R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1)
R_SExpr reduceReturn(Return &O, R_SExpr E)
R_SExpr reduceCast(Cast &Orig, R_SExpr E0)
R_SExpr reduceCall(Call &Orig, R_SExpr E0)
R_SExpr reduceArrayIndex(Store &Orig, R_SExpr E0, R_SExpr E1)
R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E)
Placeholder for a wildcard that matches any other expression.
#define bool
Definition gpuintrin.h:32
StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op)
Return the name of a binary opcode.
StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op)
Return the name of a unary opcode.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Success
Annotation was successful.
Definition Parser.h:65
@ Self
'self' clause, allowed on Compute and Combined Constructs, plus 'update'.
U cast(CodeGen::Address addr)
Definition Address.h:327
ValueTypes are data types that can actually be held in registers.