clang 23.0.0git
ThreadSafetyTIL.h
Go to the documentation of this file.
1//===- ThreadSafetyTIL.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 simple Typed Intermediate Language, or TIL, that is used
10// by the thread safety analysis (See ThreadSafety.cpp). The TIL is intended
11// to be largely independent of clang, in the hope that the analysis can be
12// reused for other non-C++ languages. All dependencies on clang/llvm should
13// go in ThreadSafetyUtil.h.
14//
15// Thread safety analysis works by comparing mutex expressions, e.g.
16//
17// class A { Mutex mu; int dat GUARDED_BY(this->mu); }
18// class B { A a; }
19//
20// void foo(B* b) {
21// (*b).a.mu.lock(); // locks (*b).a.mu
22// b->a.dat = 0; // substitute &b->a for 'this';
23// // requires lock on (&b->a)->mu
24// (b->a.mu).unlock(); // unlocks (b->a.mu)
25// }
26//
27// As illustrated by the above example, clang Exprs are not well-suited to
28// represent mutex expressions directly, since there is no easy way to compare
29// Exprs for equivalence. The thread safety analysis thus lowers clang Exprs
30// into a simple intermediate language (IL). The IL supports:
31//
32// (1) comparisons for semantic equality of expressions
33// (2) SSA renaming of variables
34// (3) wildcards and pattern matching over expressions
35// (4) hash-based expression lookup
36//
37// The TIL is currently very experimental, is intended only for use within
38// the thread safety analysis, and is subject to change without notice.
39// After the API stabilizes and matures, it may be appropriate to make this
40// more generally available to other analyses.
41//
42// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
43//
44//===----------------------------------------------------------------------===//
45
46#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
47#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
48
49#include "clang/AST/Decl.h"
51#include "clang/Basic/LLVM.h"
52#include "llvm/ADT/ArrayRef.h"
53#include "llvm/ADT/StringRef.h"
54#include "llvm/Support/Casting.h"
55#include "llvm/Support/Compiler.h"
56#include "llvm/Support/raw_ostream.h"
57#include <algorithm>
58#include <cassert>
59#include <cstddef>
60#include <cstdint>
61#include <iterator>
62#include <optional>
63#include <string>
64#include <utility>
65
66namespace clang {
67
68class CallExpr;
69class Expr;
70class Stmt;
71
72namespace threadSafety {
73namespace til {
74
75class BasicBlock;
76
77/// Enum for the different distinct classes of SExpr
78enum TIL_Opcode : unsigned char {
79#define TIL_OPCODE_DEF(X) COP_##X,
80#include "ThreadSafetyOps.def"
81#undef TIL_OPCODE_DEF
82};
83
84/// Opcode for unary arithmetic operations.
85enum TIL_UnaryOpcode : unsigned char {
89};
90
91/// Opcode for binary arithmetic operations.
92enum TIL_BinaryOpcode : unsigned char {
93 BOP_Add, // +
94 BOP_Sub, // -
95 BOP_Mul, // *
96 BOP_Div, // /
97 BOP_Rem, // %
98 BOP_Shl, // <<
99 BOP_Shr, // >>
103 BOP_Eq, // ==
104 BOP_Neq, // !=
105 BOP_Lt, // <
106 BOP_Leq, // <=
107 BOP_Cmp, // <=>
108 BOP_LogicAnd, // && (no short-circuit)
109 BOP_LogicOr // || (no short-circuit)
110};
111
112/// Opcode for cast operations.
113enum TIL_CastOpcode : unsigned char {
115
116 // Extend precision of numeric type
118
119 // Truncate precision of numeric type
121
122 // Convert to floating point type
124
125 // Convert to integer type
127
128 // Convert smart pointer to pointer (C++ only)
130};
131
132const TIL_Opcode COP_Min = COP_Future;
133const TIL_Opcode COP_Max = COP_Branch;
140
141/// Return the name of a unary opcode.
143
144/// Return the name of a binary opcode.
146
147/// ValueTypes are data types that can actually be held in registers.
148/// All variables and expressions must have a value type.
149/// Pointer types are further subdivided into the various heap-allocated
150/// types, such as functions, records, etc.
151struct ValueType {
152 enum BaseType : unsigned char {
157 BT_String, // String literals
159 };
160
162
163 template <class T>
164 inline static ValueType getValueType();
165
167};
168
169inline bool operator==(const ValueType &a, const ValueType &b) {
170 return a.Base == b.Base;
171}
172
173template<>
177
179 return ValueType(BT_Char);
180}
181
182template<>
186
187template<>
191
192template<>
196
198 return ValueType(BT_NullPointer);
199}
200
201/// Base class for AST nodes in the typed intermediate language.
202class SExpr {
203public:
204 SExpr() = delete;
205
206 TIL_Opcode opcode() const { return Opcode; }
207
208 // Subclasses of SExpr must define the following:
209 //
210 // This(const This& E, ...) {
211 // copy constructor: construct copy of E, with some additional arguments.
212 // }
213 //
214 // template <class V>
215 // typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
216 // traverse all subexpressions, following the traversal/rewriter interface.
217 // }
218 //
219 // template <class C> typename C::CType compare(CType* E, C& Cmp) {
220 // compare all subexpressions, following the comparator interface
221 // }
222 void *operator new(size_t S, MemRegionRef &R) {
223 return ::operator new(S, R);
224 }
225
226 /// SExpr objects must be created in an arena.
227 void *operator new(size_t) = delete;
228
229 /// SExpr objects cannot be deleted.
230 // This declaration is public to workaround a gcc bug that breaks building
231 // with REQUIRES_EH=1.
232 void operator delete(void *) = delete;
233
234 /// Returns the instruction ID for this expression.
235 /// All basic block instructions have a unique ID (i.e. virtual register).
236 unsigned id() const { return SExprID; }
237
238 /// Returns the block, if this is an instruction in a basic block,
239 /// otherwise returns null.
240 BasicBlock *block() const { return Block; }
241
242 /// Set the basic block and instruction ID for this expression.
243 void setID(BasicBlock *B, unsigned id) { Block = B; SExprID = id; }
244
245protected:
247 SExpr(const SExpr &E) : Opcode(E.Opcode), Flags(E.Flags) {}
248 SExpr &operator=(const SExpr &) = delete;
249
251 unsigned char Reserved = 0;
252 unsigned short Flags = 0;
253 unsigned SExprID = 0;
254 BasicBlock *Block = nullptr;
255};
256
257// Contains various helper functions for SExprs.
259
260inline bool isTrivial(const SExpr *E) {
261 TIL_Opcode Op = E->opcode();
262 return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
263}
264
265} // namespace ThreadSafetyTIL
266
267// Nodes which declare variables
268
269/// A named variable, e.g. "x".
270///
271/// There are two distinct places in which a Variable can appear in the AST.
272/// A variable declaration introduces a new variable, and can occur in 3 places:
273/// Let-expressions: (Let (x = t) u)
274/// Functions: (Function (x : t) u)
275/// Self-applicable functions (SFunction (x) t)
276///
277/// If a variable occurs in any other location, it is a reference to an existing
278/// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't
279/// allocate a separate AST node for variable references; a reference is just a
280/// pointer to the original declaration.
281class Variable : public SExpr {
282public:
284 /// Let-variable
286
287 /// Function parameter
289
290 /// SFunction (self) parameter
292 };
293
294 Variable(StringRef s, SExpr *D = nullptr)
295 : SExpr(COP_Variable), Name(s), Definition(D) {
296 Flags = VK_Let;
297 }
298
299 Variable(SExpr *D, const ValueDecl *Cvd = nullptr)
300 : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"),
301 Definition(D), Cvdecl(Cvd) {
302 Flags = VK_Let;
303 }
304
305 Variable(const Variable &Vd, SExpr *D) // rewrite constructor
306 : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl) {
307 Flags = Vd.kind();
308 }
309
310 static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; }
311
312 /// Return the kind of variable (let, function param, or self)
313 VariableKind kind() const { return static_cast<VariableKind>(Flags); }
314
315 /// Return the name of the variable, if any.
316 StringRef name() const { return Name; }
317
318 /// Return the clang declaration for this variable, if any.
319 const ValueDecl *clangDecl() const { return Cvdecl; }
320
321 /// Return the definition of the variable.
322 /// For let-vars, this is the setting expression.
323 /// For function and self parameters, it is the type of the variable.
324 SExpr *definition() { return Definition; }
325 const SExpr *definition() const { return Definition; }
326
327 void setName(StringRef S) { Name = S; }
328 void setKind(VariableKind K) { Flags = K; }
329 void setDefinition(SExpr *E) { Definition = E; }
330 void setClangDecl(const ValueDecl *VD) { Cvdecl = VD; }
331
332 template <class V>
333 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
334 // This routine is only called for variable references.
335 return Vs.reduceVariableRef(this);
336 }
337
338 template <class C>
339 typename C::CType compare(const Variable* E, C& Cmp) const {
340 return Cmp.compareVariableRefs(this, E);
341 }
342
343private:
344 friend class BasicBlock;
345 friend class Function;
346 friend class Let;
347 friend class SFunction;
348
349 // The name of the variable.
350 StringRef Name;
351
352 // The TIL type or definition.
353 SExpr *Definition;
354
355 // The clang declaration for this variable.
356 const ValueDecl *Cvdecl = nullptr;
357};
358
359/// Placeholder for an expression that has not yet been created.
360/// Used to implement lazy copy and rewriting strategies.
361class Future : public SExpr {
362public:
368
369 Future() : SExpr(COP_Future) {}
370 virtual ~Future() = delete;
371
372 static bool classof(const SExpr *E) { return E->opcode() == COP_Future; }
373
374 // A lazy rewriting strategy should subclass Future and override this method.
375 virtual SExpr *compute() { return nullptr; }
376
377 // Return the result of this future if it exists, otherwise return null.
378 SExpr *maybeGetResult() const { return Result; }
379
380 // Return the result of this future; forcing it if necessary.
382 switch (Status) {
383 case FS_pending:
384 return force();
385 case FS_evaluating:
386 return nullptr; // infinite loop; illegal recursion.
387 case FS_done:
388 return Result;
389 }
390 }
391
392 template <class V>
393 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
394 assert(Result && "Cannot traverse Future that has not been forced.");
395 return Vs.traverse(Result, Ctx);
396 }
397
398 template <class C>
399 typename C::CType compare(const Future* E, C& Cmp) const {
400 if (!Result || !E->Result)
401 return Cmp.comparePointers(this, E);
402 return Cmp.compare(Result, E->Result);
403 }
404
405private:
406 SExpr* force();
407
408 FutureStatus Status = FS_pending;
409 SExpr *Result = nullptr;
410};
411
412/// Placeholder for expressions that cannot be represented in the TIL.
413class Undefined : public SExpr {
414public:
415 Undefined(const Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {}
416 Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {}
417
418 // The copy assignment operator is defined as deleted pending further
419 // motivation.
420 Undefined &operator=(const Undefined &) = delete;
421
422 static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; }
423
424 template <class V>
425 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
426 return Vs.reduceUndefined(*this);
427 }
428
429 template <class C>
430 typename C::CType compare(const Undefined* E, C& Cmp) const {
431 return Cmp.trueResult();
432 }
433
434private:
435 const Stmt *Cstmt;
436};
437
438/// Placeholder for a wildcard that matches any other expression.
439class Wildcard : public SExpr {
440public:
441 Wildcard() : SExpr(COP_Wildcard) {}
442 Wildcard(const Wildcard &) = default;
443
444 static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; }
445
446 template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
447 return Vs.reduceWildcard(*this);
448 }
449
450 template <class C>
451 typename C::CType compare(const Wildcard* E, C& Cmp) const {
452 return Cmp.trueResult();
453 }
454};
455
456template <class T> class LiteralT;
457
458// Base class for literal values.
459class Literal : public SExpr {
460protected:
461 Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT) {}
462
463public:
464 static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; }
465
466 ValueType valueType() const { return ValType; }
467
468 template<class T> const LiteralT<T>& as() const {
469 assert(ValType == ValueType::getValueType<T>());
470 return *static_cast<const LiteralT<T>*>(this);
471 }
472 template<class T> LiteralT<T>& as() {
473 assert(ValType == ValueType::getValueType<T>());
474 return *static_cast<LiteralT<T>*>(this);
475 }
476
477 template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx);
478
479 template <class C> typename C::CType compare(const Literal *E, C &Cmp) const;
480
481private:
482 const ValueType ValType;
483};
484
485// Derived class for literal values, which stores the actual value.
486template<class T>
487class LiteralT : public Literal {
488public:
489 LiteralT(T Dat) : Literal(ValueType::getValueType<T>()), Val(Dat) {}
490 LiteralT(const LiteralT<T> &L) : Literal(L), Val(L.Val) {}
491
492 // The copy assignment operator is defined as deleted pending further
493 // motivation.
494 LiteralT &operator=(const LiteralT<T> &) = delete;
495
496 T value() const { return Val;}
497 T& value() { return Val; }
498
499private:
500 T Val;
501};
502
503template <class T> LiteralT(T) -> LiteralT<T>;
504
505template <class V>
506typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) {
507 switch (ValType.Base) {
509 return Vs.reduceLiteralT(as<bool>());
511 return Vs.reduceLiteralT(as<char32_t>());
513 return Vs.reduceLiteralT(as<int64_t>());
515 return Vs.reduceLiteralT(as<uint64_t>());
517 return Vs.reduceLiteralT(as<StringRef>());
519 return Vs.reduceLiteralT(as<std::nullptr_t>());
520 }
521 llvm_unreachable("Invalid BaseType");
522}
523
524template <class C>
525typename C::CType Literal::compare(const Literal *E, C &Cmp) const {
526 typename C::CType Ct = Cmp.compareIntegers(ValType.Base, E->ValType.Base);
527 if (Cmp.notTrue(Ct))
528 return Ct;
529 switch (ValType.Base) {
531 return Cmp.compareIntegers(as<bool>().value(), E->as<bool>().value());
533 return Cmp.compareIntegers(as<char32_t>().value(),
534 E->as<char32_t>().value());
536 return Cmp.compareIntegers(as<int64_t>().value(), E->as<int64_t>().value());
538 return Cmp.compareIntegers(as<uint64_t>().value(),
539 E->as<uint64_t>().value());
541 return Cmp.compareStrings(as<StringRef>().value(),
542 E->as<StringRef>().value());
544 return Cmp.trueResult();
545 }
546 llvm_unreachable("Invalid BaseType");
547}
548
549/// A Literal pointer to an object allocated in memory.
550/// At compile time, pointer literals are represented by symbolic names.
551class LiteralPtr : public SExpr {
552public:
553 LiteralPtr(const ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {}
554 LiteralPtr(const LiteralPtr &) = default;
555
556 static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; }
557
558 // The clang declaration for the value that this pointer points to.
559 const ValueDecl *clangDecl() const { return Cvdecl; }
560 void setClangDecl(const ValueDecl *VD) { Cvdecl = VD; }
561
562 template <class V>
563 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
564 return Vs.reduceLiteralPtr(*this);
565 }
566
567 template <class C>
568 typename C::CType compare(const LiteralPtr* E, C& Cmp) const {
569 if (!Cvdecl || !E->Cvdecl)
570 return Cmp.comparePointers(this, E);
571 return Cmp.comparePointers(Cvdecl, E->Cvdecl);
572 }
573
574private:
575 const ValueDecl *Cvdecl;
576};
577
578/// A function -- a.k.a. lambda abstraction.
579/// Functions with multiple arguments are created by currying,
580/// e.g. (Function (x: Int) (Function (y: Int) (Code { return x + y })))
581class Function : public SExpr {
582public:
584 : SExpr(COP_Function), VarDecl(Vd), Body(Bd) {
586 }
587
588 Function(const Function &F, Variable *Vd, SExpr *Bd) // rewrite constructor
589 : SExpr(F), VarDecl(Vd), Body(Bd) {
591 }
592
593 static bool classof(const SExpr *E) { return E->opcode() == COP_Function; }
594
595 Variable *variableDecl() { return VarDecl; }
596 const Variable *variableDecl() const { return VarDecl; }
597
598 SExpr *body() { return Body; }
599 const SExpr *body() const { return Body; }
600
601 template <class V>
602 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
603 // This is a variable declaration, so traverse the definition.
604 auto E0 = Vs.traverse(VarDecl->Definition, Vs.typeCtx(Ctx));
605 // Tell the rewriter to enter the scope of the function.
606 Variable *Nvd = Vs.enterScope(*VarDecl, E0);
607 auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx));
608 Vs.exitScope(*VarDecl);
609 return Vs.reduceFunction(*this, Nvd, E1);
610 }
611
612 template <class C>
613 typename C::CType compare(const Function* E, C& Cmp) const {
614 typename C::CType Ct =
615 Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
616 if (Cmp.notTrue(Ct))
617 return Ct;
618 Cmp.enterScope(variableDecl(), E->variableDecl());
619 Ct = Cmp.compare(body(), E->body());
620 Cmp.leaveScope();
621 return Ct;
622 }
623
624private:
626 SExpr* Body;
627};
628
629/// A self-applicable function.
630/// A self-applicable function can be applied to itself. It's useful for
631/// implementing objects and late binding.
632class SFunction : public SExpr {
633public:
635 : SExpr(COP_SFunction), VarDecl(Vd), Body(B) {
636 assert(Vd->Definition == nullptr);
638 Vd->Definition = this;
639 }
640
641 SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor
642 : SExpr(F), VarDecl(Vd), Body(B) {
643 assert(Vd->Definition == nullptr);
645 Vd->Definition = this;
646 }
647
648 static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; }
649
650 Variable *variableDecl() { return VarDecl; }
651 const Variable *variableDecl() const { return VarDecl; }
652
653 SExpr *body() { return Body; }
654 const SExpr *body() const { return Body; }
655
656 template <class V>
657 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
658 // A self-variable points to the SFunction itself.
659 // A rewrite must introduce the variable with a null definition, and update
660 // it after 'this' has been rewritten.
661 Variable *Nvd = Vs.enterScope(*VarDecl, nullptr);
662 auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx));
663 Vs.exitScope(*VarDecl);
664 // A rewrite operation will call SFun constructor to set Vvd->Definition.
665 return Vs.reduceSFunction(*this, Nvd, E1);
666 }
667
668 template <class C>
669 typename C::CType compare(const SFunction* E, C& Cmp) const {
670 Cmp.enterScope(variableDecl(), E->variableDecl());
671 typename C::CType Ct = Cmp.compare(body(), E->body());
672 Cmp.leaveScope();
673 return Ct;
674 }
675
676private:
678 SExpr* Body;
679};
680
681/// A block of code -- e.g. the body of a function.
682class Code : public SExpr {
683public:
684 Code(SExpr *T, SExpr *B) : SExpr(COP_Code), ReturnType(T), Body(B) {}
685 Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor
686 : SExpr(C), ReturnType(T), Body(B) {}
687
688 static bool classof(const SExpr *E) { return E->opcode() == COP_Code; }
689
690 SExpr *returnType() { return ReturnType; }
691 const SExpr *returnType() const { return ReturnType; }
692
693 SExpr *body() { return Body; }
694 const SExpr *body() const { return Body; }
695
696 template <class V>
697 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
698 auto Nt = Vs.traverse(ReturnType, Vs.typeCtx(Ctx));
699 auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx));
700 return Vs.reduceCode(*this, Nt, Nb);
701 }
702
703 template <class C>
704 typename C::CType compare(const Code* E, C& Cmp) const {
705 typename C::CType Ct = Cmp.compare(returnType(), E->returnType());
706 if (Cmp.notTrue(Ct))
707 return Ct;
708 return Cmp.compare(body(), E->body());
709 }
710
711private:
712 SExpr* ReturnType;
713 SExpr* Body;
714};
715
716/// A typed, writable location in memory
717class Field : public SExpr {
718public:
719 Field(SExpr *R, SExpr *B) : SExpr(COP_Field), Range(R), Body(B) {}
720 Field(const Field &C, SExpr *R, SExpr *B) // rewrite constructor
721 : SExpr(C), Range(R), Body(B) {}
722
723 static bool classof(const SExpr *E) { return E->opcode() == COP_Field; }
724
725 SExpr *range() { return Range; }
726 const SExpr *range() const { return Range; }
727
728 SExpr *body() { return Body; }
729 const SExpr *body() const { return Body; }
730
731 template <class V>
732 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
733 auto Nr = Vs.traverse(Range, Vs.typeCtx(Ctx));
734 auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx));
735 return Vs.reduceField(*this, Nr, Nb);
736 }
737
738 template <class C>
739 typename C::CType compare(const Field* E, C& Cmp) const {
740 typename C::CType Ct = Cmp.compare(range(), E->range());
741 if (Cmp.notTrue(Ct))
742 return Ct;
743 return Cmp.compare(body(), E->body());
744 }
745
746private:
747 SExpr* Range;
748 SExpr* Body;
749};
750
751/// Apply an argument to a function.
752/// Note that this does not actually call the function. Functions are curried,
753/// so this returns a closure in which the first parameter has been applied.
754/// Once all parameters have been applied, Call can be used to invoke the
755/// function.
756class Apply : public SExpr {
757public:
758 Apply(SExpr *F, SExpr *A) : SExpr(COP_Apply), Fun(F), Arg(A) {}
759 Apply(const Apply &A, SExpr *F, SExpr *Ar) // rewrite constructor
760 : SExpr(A), Fun(F), Arg(Ar) {}
761
762 static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; }
763
764 SExpr *fun() { return Fun; }
765 const SExpr *fun() const { return Fun; }
766
767 SExpr *arg() { return Arg; }
768 const SExpr *arg() const { return Arg; }
769
770 template <class V>
771 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
772 auto Nf = Vs.traverse(Fun, Vs.subExprCtx(Ctx));
773 auto Na = Vs.traverse(Arg, Vs.subExprCtx(Ctx));
774 return Vs.reduceApply(*this, Nf, Na);
775 }
776
777 template <class C>
778 typename C::CType compare(const Apply* E, C& Cmp) const {
779 typename C::CType Ct = Cmp.compare(fun(), E->fun());
780 if (Cmp.notTrue(Ct))
781 return Ct;
782 return Cmp.compare(arg(), E->arg());
783 }
784
785private:
786 SExpr* Fun;
787 SExpr* Arg;
788};
789
790/// Apply a self-argument to a self-applicable function.
791class SApply : public SExpr {
792public:
793 SApply(SExpr *Sf, SExpr *A = nullptr) : SExpr(COP_SApply), Sfun(Sf), Arg(A) {}
794 SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr) // rewrite constructor
795 : SExpr(A), Sfun(Sf), Arg(Ar) {}
796
797 static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; }
798
799 SExpr *sfun() { return Sfun; }
800 const SExpr *sfun() const { return Sfun; }
801
802 SExpr *arg() { return Arg ? Arg : Sfun; }
803 const SExpr *arg() const { return Arg ? Arg : Sfun; }
804
805 bool isDelegation() const { return Arg != nullptr; }
806
807 template <class V>
808 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
809 auto Nf = Vs.traverse(Sfun, Vs.subExprCtx(Ctx));
810 typename V::R_SExpr Na = Arg ? Vs.traverse(Arg, Vs.subExprCtx(Ctx))
811 : nullptr;
812 return Vs.reduceSApply(*this, Nf, Na);
813 }
814
815 template <class C>
816 typename C::CType compare(const SApply* E, C& Cmp) const {
817 typename C::CType Ct = Cmp.compare(sfun(), E->sfun());
818 if (Cmp.notTrue(Ct) || (!arg() && !E->arg()))
819 return Ct;
820 return Cmp.compare(arg(), E->arg());
821 }
822
823private:
824 SExpr* Sfun;
825 SExpr* Arg;
826};
827
828/// Project a named slot from a C++ struct or class.
829class Project : public SExpr {
830public:
831 Project(SExpr *R, const ValueDecl *Cvd)
832 : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) {
833 assert(Cvd && "ValueDecl must not be null");
834 }
835
836 static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
837
838 SExpr *record() { return Rec; }
839 const SExpr *record() const { return Rec; }
840
841 const ValueDecl *clangDecl() const { return Cvdecl; }
842
843 bool isArrow() const { return (Flags & 0x01) != 0; }
844
845 void setArrow(bool b) {
846 if (b) Flags |= 0x01;
847 else Flags &= 0xFFFE;
848 }
849
850 StringRef slotName() const {
851 if (Cvdecl->getDeclName().isIdentifier())
852 return Cvdecl->getName();
853 if (!SlotName) {
854 SlotName = "";
855 llvm::raw_string_ostream OS(*SlotName);
856 Cvdecl->printName(OS);
857 }
858 return *SlotName;
859 }
860
861 template <class V>
862 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
863 auto Nr = Vs.traverse(Rec, Vs.subExprCtx(Ctx));
864 return Vs.reduceProject(*this, Nr);
865 }
866
867 template <class C>
868 typename C::CType compare(const Project* E, C& Cmp) const {
869 typename C::CType Ct = Cmp.compare(record(), E->record());
870 if (Cmp.notTrue(Ct))
871 return Ct;
872 return Cmp.comparePointers(Cvdecl, E->Cvdecl);
873 }
874
875private:
876 SExpr* Rec;
877 mutable std::optional<std::string> SlotName;
878 const ValueDecl *Cvdecl;
879};
880
881/// Call a function (after all arguments have been applied).
882class Call : public SExpr {
883public:
884 Call(SExpr *T, const CallExpr *Ce = nullptr)
885 : SExpr(COP_Call), Target(T), Cexpr(Ce) {}
886 Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {}
887
888 static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
889
890 SExpr *target() { return Target; }
891 const SExpr *target() const { return Target; }
892
893 const CallExpr *clangCallExpr() const { return Cexpr; }
894
895 template <class V>
896 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
897 auto Nt = Vs.traverse(Target, Vs.subExprCtx(Ctx));
898 return Vs.reduceCall(*this, Nt);
899 }
900
901 template <class C>
902 typename C::CType compare(const Call* E, C& Cmp) const {
903 return Cmp.compare(target(), E->target());
904 }
905
906private:
907 SExpr* Target;
908 const CallExpr *Cexpr;
909};
910
911/// Allocate memory for a new value on the heap or stack.
912class Alloc : public SExpr {
913public:
918
919 Alloc(SExpr *D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) { Flags = K; }
920 Alloc(const Alloc &A, SExpr *Dt) : SExpr(A), Dtype(Dt) { Flags = A.kind(); }
921
922 static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
923
924 AllocKind kind() const { return static_cast<AllocKind>(Flags); }
925
926 SExpr *dataType() { return Dtype; }
927 const SExpr *dataType() const { return Dtype; }
928
929 template <class V>
930 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
931 auto Nd = Vs.traverse(Dtype, Vs.declCtx(Ctx));
932 return Vs.reduceAlloc(*this, Nd);
933 }
934
935 template <class C>
936 typename C::CType compare(const Alloc* E, C& Cmp) const {
937 typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind());
938 if (Cmp.notTrue(Ct))
939 return Ct;
940 return Cmp.compare(dataType(), E->dataType());
941 }
942
943private:
944 SExpr* Dtype;
945};
946
947/// Load a value from memory.
948class Load : public SExpr {
949public:
950 Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {}
951 Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {}
952
953 static bool classof(const SExpr *E) { return E->opcode() == COP_Load; }
954
955 SExpr *pointer() { return Ptr; }
956 const SExpr *pointer() const { return Ptr; }
957
958 template <class V>
959 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
960 auto Np = Vs.traverse(Ptr, Vs.subExprCtx(Ctx));
961 return Vs.reduceLoad(*this, Np);
962 }
963
964 template <class C>
965 typename C::CType compare(const Load* E, C& Cmp) const {
966 return Cmp.compare(pointer(), E->pointer());
967 }
968
969private:
970 SExpr* Ptr;
971};
972
973/// Store a value to memory.
974/// The destination is a pointer to a field, the source is the value to store.
975class Store : public SExpr {
976public:
977 Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {}
978 Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {}
979
980 static bool classof(const SExpr *E) { return E->opcode() == COP_Store; }
981
982 SExpr *destination() { return Dest; } // Address to store to
983 const SExpr *destination() const { return Dest; }
984
985 SExpr *source() { return Source; } // Value to store
986 const SExpr *source() const { return Source; }
987
988 template <class V>
989 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
990 auto Np = Vs.traverse(Dest, Vs.subExprCtx(Ctx));
991 auto Nv = Vs.traverse(Source, Vs.subExprCtx(Ctx));
992 return Vs.reduceStore(*this, Np, Nv);
993 }
994
995 template <class C>
996 typename C::CType compare(const Store* E, C& Cmp) const {
997 typename C::CType Ct = Cmp.compare(destination(), E->destination());
998 if (Cmp.notTrue(Ct))
999 return Ct;
1000 return Cmp.compare(source(), E->source());
1001 }
1002
1003private:
1004 SExpr* Dest;
1005 SExpr* Source;
1006};
1007
1008/// If p is a reference to an array, then p[i] is a reference to the i'th
1009/// element of the array.
1010class ArrayIndex : public SExpr {
1011public:
1012 ArrayIndex(SExpr *A, SExpr *N) : SExpr(COP_ArrayIndex), Array(A), Index(N) {}
1014 : SExpr(E), Array(A), Index(N) {}
1015
1016 static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; }
1017
1018 SExpr *array() { return Array; }
1019 const SExpr *array() const { return Array; }
1020
1021 SExpr *index() { return Index; }
1022 const SExpr *index() const { return Index; }
1023
1024 template <class V>
1025 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1026 auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
1027 auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
1028 return Vs.reduceArrayIndex(*this, Na, Ni);
1029 }
1030
1031 template <class C>
1032 typename C::CType compare(const ArrayIndex* E, C& Cmp) const {
1033 typename C::CType Ct = Cmp.compare(array(), E->array());
1034 if (Cmp.notTrue(Ct))
1035 return Ct;
1036 return Cmp.compare(index(), E->index());
1037 }
1038
1039private:
1040 SExpr* Array;
1041 SExpr* Index;
1042};
1043
1044/// Pointer arithmetic, restricted to arrays only.
1045/// If p is a reference to an array, then p + n, where n is an integer, is
1046/// a reference to a subarray.
1047class ArrayAdd : public SExpr {
1048public:
1049 ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {}
1050 ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N)
1051 : SExpr(E), Array(A), Index(N) {}
1052
1053 static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; }
1054
1055 SExpr *array() { return Array; }
1056 const SExpr *array() const { return Array; }
1057
1058 SExpr *index() { return Index; }
1059 const SExpr *index() const { return Index; }
1060
1061 template <class V>
1062 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1063 auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
1064 auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
1065 return Vs.reduceArrayAdd(*this, Na, Ni);
1066 }
1067
1068 template <class C>
1069 typename C::CType compare(const ArrayAdd* E, C& Cmp) const {
1070 typename C::CType Ct = Cmp.compare(array(), E->array());
1071 if (Cmp.notTrue(Ct))
1072 return Ct;
1073 return Cmp.compare(index(), E->index());
1074 }
1075
1076private:
1077 SExpr* Array;
1078 SExpr* Index;
1079};
1080
1081/// Simple arithmetic unary operations, e.g. negate and not.
1082/// These operations have no side-effects.
1083class UnaryOp : public SExpr {
1084public:
1085 UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) {
1086 Flags = Op;
1087 }
1088
1089 UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U), Expr0(E) { Flags = U.Flags; }
1090
1091 static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; }
1092
1094 return static_cast<TIL_UnaryOpcode>(Flags);
1095 }
1096
1097 SExpr *expr() { return Expr0; }
1098 const SExpr *expr() const { return Expr0; }
1099
1100 template <class V>
1101 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1102 auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1103 return Vs.reduceUnaryOp(*this, Ne);
1104 }
1105
1106 template <class C>
1107 typename C::CType compare(const UnaryOp* E, C& Cmp) const {
1108 typename C::CType Ct =
1109 Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode());
1110 if (Cmp.notTrue(Ct))
1111 return Ct;
1112 return Cmp.compare(expr(), E->expr());
1113 }
1114
1115private:
1116 SExpr* Expr0;
1117};
1118
1119/// Simple arithmetic binary operations, e.g. +, -, etc.
1120/// These operations have no side effects.
1121class BinaryOp : public SExpr {
1122public:
1124 : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) {
1125 Flags = Op;
1126 }
1127
1128 BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1)
1129 : SExpr(B), Expr0(E0), Expr1(E1) {
1130 Flags = B.Flags;
1131 }
1132
1133 static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; }
1134
1136 return static_cast<TIL_BinaryOpcode>(Flags);
1137 }
1138
1139 SExpr *expr0() { return Expr0; }
1140 const SExpr *expr0() const { return Expr0; }
1141
1142 SExpr *expr1() { return Expr1; }
1143 const SExpr *expr1() const { return Expr1; }
1144
1145 template <class V>
1146 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1147 auto Ne0 = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1148 auto Ne1 = Vs.traverse(Expr1, Vs.subExprCtx(Ctx));
1149 return Vs.reduceBinaryOp(*this, Ne0, Ne1);
1150 }
1151
1152 template <class C>
1153 typename C::CType compare(const BinaryOp* E, C& Cmp) const {
1154 typename C::CType Ct =
1155 Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode());
1156 if (Cmp.notTrue(Ct))
1157 return Ct;
1158 Ct = Cmp.compare(expr0(), E->expr0());
1159 if (Cmp.notTrue(Ct))
1160 return Ct;
1161 return Cmp.compare(expr1(), E->expr1());
1162 }
1163
1164private:
1165 SExpr* Expr0;
1166 SExpr* Expr1;
1167};
1168
1169/// Cast expressions.
1170/// Cast expressions are essentially unary operations, but we treat them
1171/// as a distinct AST node because they only change the type of the result.
1172class Cast : public SExpr {
1173public:
1174 Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; }
1175 Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; }
1176
1177 static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; }
1178
1180 return static_cast<TIL_CastOpcode>(Flags);
1181 }
1182
1183 SExpr *expr() { return Expr0; }
1184 const SExpr *expr() const { return Expr0; }
1185
1186 template <class V>
1187 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1188 auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1189 return Vs.reduceCast(*this, Ne);
1190 }
1191
1192 template <class C>
1193 typename C::CType compare(const Cast* E, C& Cmp) const {
1194 typename C::CType Ct =
1195 Cmp.compareIntegers(castOpcode(), E->castOpcode());
1196 if (Cmp.notTrue(Ct))
1197 return Ct;
1198 return Cmp.compare(expr(), E->expr());
1199 }
1200
1201private:
1202 SExpr* Expr0;
1203};
1204
1205class SCFG;
1206
1207/// Phi Node, for code in SSA form.
1208/// Each Phi node has an array of possible values that it can take,
1209/// depending on where control flow comes from.
1210class Phi : public SExpr {
1211public:
1213
1214 // In minimal SSA form, all Phi nodes are MultiVal.
1215 // During conversion to SSA, incomplete Phi nodes may be introduced, which
1216 // are later determined to be SingleVal, and are thus redundant.
1217 enum Status {
1218 PH_MultiVal = 0, // Phi node has multiple distinct values. (Normal)
1219 PH_SingleVal, // Phi node has one distinct value, and can be eliminated
1220 PH_Incomplete // Phi node is incomplete
1221 };
1222
1223 Phi() : SExpr(COP_Phi) {}
1224 Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
1225 Phi(const Phi &P, ValArray &&Vs) : SExpr(P), Values(std::move(Vs)) {}
1226
1227 static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
1228
1229 const ValArray &values() const { return Values; }
1230 ValArray &values() { return Values; }
1231
1232 Status status() const { return static_cast<Status>(Flags); }
1233 void setStatus(Status s) { Flags = s; }
1234
1235 /// Return the clang declaration of the variable for this Phi node, if any.
1236 const ValueDecl *clangDecl() const { return Cvdecl; }
1237
1238 /// Set the clang variable associated with this Phi node.
1239 void setClangDecl(const ValueDecl *Cvd) { Cvdecl = Cvd; }
1240
1241 template <class V>
1242 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1243 typename V::template Container<typename V::R_SExpr>
1244 Nvs(Vs, Values.size());
1245
1246 for (const auto *Val : Values)
1247 Nvs.push_back( Vs.traverse(Val, Vs.subExprCtx(Ctx)) );
1248 return Vs.reducePhi(*this, Nvs);
1249 }
1250
1251 template <class C>
1252 typename C::CType compare(const Phi *E, C &Cmp) const {
1253 // TODO: implement CFG comparisons
1254 return Cmp.comparePointers(this, E);
1255 }
1256
1257private:
1258 ValArray Values;
1259 const ValueDecl* Cvdecl = nullptr;
1260};
1261
1262/// Base class for basic block terminators: Branch, Goto, and Return.
1263class Terminator : public SExpr {
1264protected:
1266 Terminator(const SExpr &E) : SExpr(E) {}
1267
1268public:
1269 static bool classof(const SExpr *E) {
1270 return E->opcode() >= COP_Goto && E->opcode() <= COP_Return;
1271 }
1272
1273 /// Return the list of basic blocks that this terminator can branch to.
1275};
1276
1277/// Jump to another basic block.
1278/// A goto instruction is essentially a tail-recursive call into another
1279/// block. In addition to the block pointer, it specifies an index into the
1280/// phi nodes of that block. The index can be used to retrieve the "arguments"
1281/// of the call.
1282class Goto : public Terminator {
1283public:
1284 Goto(BasicBlock *B, unsigned I)
1285 : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
1286 Goto(const Goto &G, BasicBlock *B, unsigned I)
1287 : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
1288
1289 static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
1290
1291 const BasicBlock *targetBlock() const { return TargetBlock; }
1292 BasicBlock *targetBlock() { return TargetBlock; }
1293
1294 /// Returns the index into the
1295 unsigned index() const { return Index; }
1296
1297 /// Return the list of basic blocks that this terminator can branch to.
1298 ArrayRef<BasicBlock *> successors() const { return TargetBlock; }
1299
1300 template <class V>
1301 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1302 BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock);
1303 return Vs.reduceGoto(*this, Ntb);
1304 }
1305
1306 template <class C>
1307 typename C::CType compare(const Goto *E, C &Cmp) const {
1308 // TODO: implement CFG comparisons
1309 return Cmp.comparePointers(this, E);
1310 }
1311
1312private:
1313 BasicBlock *TargetBlock;
1314 unsigned Index;
1315};
1316
1317/// A conditional branch to two other blocks.
1318/// Note that unlike Goto, Branch does not have an index. The target blocks
1319/// must be child-blocks, and cannot have Phi nodes.
1320class Branch : public Terminator {
1321public:
1323 : Terminator(COP_Branch), Condition(C) {
1324 Branches[0] = T;
1325 Branches[1] = E;
1326 }
1327
1329 : Terminator(Br), Condition(C) {
1330 Branches[0] = T;
1331 Branches[1] = E;
1332 }
1333
1334 static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
1335
1336 const SExpr *condition() const { return Condition; }
1337 SExpr *condition() { return Condition; }
1338
1339 const BasicBlock *thenBlock() const { return Branches[0]; }
1340 BasicBlock *thenBlock() { return Branches[0]; }
1341
1342 const BasicBlock *elseBlock() const { return Branches[1]; }
1343 BasicBlock *elseBlock() { return Branches[1]; }
1344
1345 /// Return the list of basic blocks that this terminator can branch to.
1347
1348 template <class V>
1349 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1350 auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
1351 BasicBlock *Ntb = Vs.reduceBasicBlockRef(Branches[0]);
1352 BasicBlock *Nte = Vs.reduceBasicBlockRef(Branches[1]);
1353 return Vs.reduceBranch(*this, Nc, Ntb, Nte);
1354 }
1355
1356 template <class C>
1357 typename C::CType compare(const Branch *E, C &Cmp) const {
1358 // TODO: implement CFG comparisons
1359 return Cmp.comparePointers(this, E);
1360 }
1361
1362private:
1364 BasicBlock *Branches[2];
1365};
1366
1367/// Return from the enclosing function, passing the return value to the caller.
1368/// Only the exit block should end with a return statement.
1369class Return : public Terminator {
1370public:
1371 Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {}
1372 Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {}
1373
1374 static bool classof(const SExpr *E) { return E->opcode() == COP_Return; }
1375
1376 /// Return an empty list.
1377 ArrayRef<BasicBlock *> successors() const { return {}; }
1378
1379 SExpr *returnValue() { return Retval; }
1380 const SExpr *returnValue() const { return Retval; }
1381
1382 template <class V>
1383 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1384 auto Ne = Vs.traverse(Retval, Vs.subExprCtx(Ctx));
1385 return Vs.reduceReturn(*this, Ne);
1386 }
1387
1388 template <class C>
1389 typename C::CType compare(const Return *E, C &Cmp) const {
1390 return Cmp.compare(Retval, E->Retval);
1391 }
1392
1393private:
1394 SExpr* Retval;
1395};
1396
1398 switch (opcode()) {
1399 case COP_Goto: return cast<Goto>(this)->successors();
1400 case COP_Branch: return cast<Branch>(this)->successors();
1401 case COP_Return: return cast<Return>(this)->successors();
1402 default:
1403 return {};
1404 }
1405}
1406
1407/// A basic block is part of an SCFG. It can be treated as a function in
1408/// continuation passing style. A block consists of a sequence of phi nodes,
1409/// which are "arguments" to the function, followed by a sequence of
1410/// instructions. It ends with a Terminator, which is a Branch or Goto to
1411/// another basic block in the same SCFG.
1412class BasicBlock : public SExpr {
1413public:
1416
1417 // TopologyNodes are used to overlay tree structures on top of the CFG,
1418 // such as dominator and postdominator trees. Each block is assigned an
1419 // ID in the tree according to a depth-first search. Tree traversals are
1420 // always up, towards the parents.
1422 int NodeID = 0;
1423
1424 // Includes this node, so must be > 1.
1426
1427 // Pointer to parent.
1428 BasicBlock *Parent = nullptr;
1429
1430 TopologyNode() = default;
1431
1432 bool isParentOf(const TopologyNode& OtherNode) {
1433 return OtherNode.NodeID > NodeID &&
1434 OtherNode.NodeID < NodeID + SizeOfSubTree;
1435 }
1436
1437 bool isParentOfOrEqual(const TopologyNode& OtherNode) {
1438 return OtherNode.NodeID >= NodeID &&
1439 OtherNode.NodeID < NodeID + SizeOfSubTree;
1440 }
1441 };
1442
1444 : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false) {}
1446 Terminator *T)
1447 : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false),
1448 Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {}
1449
1450 static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; }
1451
1452 /// Returns the block ID. Every block has a unique ID in the CFG.
1453 int blockID() const { return BlockID; }
1454
1455 /// Returns the number of predecessors.
1456 size_t numPredecessors() const { return Predecessors.size(); }
1457 size_t numSuccessors() const { return successors().size(); }
1458
1459 const SCFG* cfg() const { return CFGPtr; }
1460 SCFG* cfg() { return CFGPtr; }
1461
1462 const BasicBlock *parent() const { return DominatorNode.Parent; }
1463 BasicBlock *parent() { return DominatorNode.Parent; }
1464
1465 const InstrArray &arguments() const { return Args; }
1466 InstrArray &arguments() { return Args; }
1467
1468 InstrArray &instructions() { return Instrs; }
1469 const InstrArray &instructions() const { return Instrs; }
1470
1471 /// Returns a list of predecessors.
1472 /// The order of predecessors in the list is important; each phi node has
1473 /// exactly one argument for each precessor, in the same order.
1474 BlockArray &predecessors() { return Predecessors; }
1475 const BlockArray &predecessors() const { return Predecessors; }
1476
1477 ArrayRef<BasicBlock*> successors() { return TermInstr->successors(); }
1478 ArrayRef<BasicBlock*> successors() const { return TermInstr->successors(); }
1479
1480 const Terminator *terminator() const { return TermInstr; }
1481 Terminator *terminator() { return TermInstr; }
1482
1483 void setTerminator(Terminator *E) { TermInstr = E; }
1484
1486 return DominatorNode.isParentOfOrEqual(Other.DominatorNode);
1487 }
1488
1490 return PostDominatorNode.isParentOfOrEqual(Other.PostDominatorNode);
1491 }
1492
1493 /// Add a new argument.
1495 Args.reserveCheck(1, Arena);
1496 Args.push_back(V);
1497 }
1498
1499 /// Add a new instruction.
1501 Instrs.reserveCheck(1, Arena);
1502 Instrs.push_back(V);
1503 }
1504
1505 // Add a new predecessor, and return the phi-node index for it.
1506 // Will add an argument to all phi-nodes, initialized to nullptr.
1507 unsigned addPredecessor(BasicBlock *Pred);
1508
1509 // Reserve space for Nargs arguments.
1510 void reserveArguments(unsigned Nargs) { Args.reserve(Nargs, Arena); }
1511
1512 // Reserve space for Nins instructions.
1513 void reserveInstructions(unsigned Nins) { Instrs.reserve(Nins, Arena); }
1514
1515 // Reserve space for NumPreds predecessors, including space in phi nodes.
1516 void reservePredecessors(unsigned NumPreds);
1517
1518 /// Return the index of BB, or Predecessors.size if BB is not a predecessor.
1519 unsigned findPredecessorIndex(const BasicBlock *BB) const {
1520 auto I = llvm::find(Predecessors, BB);
1521 return std::distance(Predecessors.cbegin(), I);
1522 }
1523
1524 template <class V>
1525 typename V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx) {
1526 typename V::template Container<SExpr*> Nas(Vs, Args.size());
1527 typename V::template Container<SExpr*> Nis(Vs, Instrs.size());
1528
1529 // Entering the basic block should do any scope initialization.
1530 Vs.enterBasicBlock(*this);
1531
1532 for (const auto *E : Args) {
1533 auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
1534 Nas.push_back(Ne);
1535 }
1536 for (const auto *E : Instrs) {
1537 auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
1538 Nis.push_back(Ne);
1539 }
1540 auto Nt = Vs.traverse(TermInstr, Ctx);
1541
1542 // Exiting the basic block should handle any scope cleanup.
1543 Vs.exitBasicBlock(*this);
1544
1545 return Vs.reduceBasicBlock(*this, Nas, Nis, Nt);
1546 }
1547
1548 template <class C>
1549 typename C::CType compare(const BasicBlock *E, C &Cmp) const {
1550 // TODO: implement CFG comparisons
1551 return Cmp.comparePointers(this, E);
1552 }
1553
1554private:
1555 friend class SCFG;
1556
1557 // assign unique ids to all instructions
1558 unsigned renumberInstrs(unsigned id);
1559
1560 unsigned topologicalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
1561 unsigned topologicalFinalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
1562 void computeDominator();
1563 void computePostDominator();
1564
1565 // The arena used to allocate this block.
1566 MemRegionRef Arena;
1567
1568 // The CFG that contains this block.
1569 SCFG *CFGPtr = nullptr;
1570
1571 // Unique ID for this BB in the containing CFG. IDs are in topological order.
1572 unsigned BlockID : 31;
1573
1574 // Bit to determine if a block has been visited during a traversal.
1575 LLVM_PREFERRED_TYPE(bool)
1576 unsigned Visited : 1;
1577
1578 // Predecessor blocks in the CFG.
1579 BlockArray Predecessors;
1580
1581 // Phi nodes. One argument per predecessor.
1582 InstrArray Args;
1583
1584 // Instructions.
1585 InstrArray Instrs;
1586
1587 // Terminating instruction.
1588 Terminator *TermInstr = nullptr;
1589
1590 // The dominator tree.
1591 TopologyNode DominatorNode;
1592
1593 // The post-dominator tree.
1594 TopologyNode PostDominatorNode;
1595};
1596
1597/// An SCFG is a control-flow graph. It consists of a set of basic blocks,
1598/// each of which terminates in a branch to another basic block. There is one
1599/// entry point, and one exit point.
1600class SCFG : public SExpr {
1601public:
1605
1606 SCFG(MemRegionRef A, unsigned Nblocks)
1607 : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks) {
1608 Entry = new (A) BasicBlock(A);
1609 Exit = new (A) BasicBlock(A);
1610 auto *V = new (A) Phi();
1611 Exit->addArgument(V);
1612 Exit->setTerminator(new (A) Return(V));
1613 add(Entry);
1614 add(Exit);
1615 }
1616
1617 SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba
1618 : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)) {
1619 // TODO: set entry and exit!
1620 }
1621
1622 static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
1623
1624 /// Return true if this CFG is valid.
1625 bool valid() const { return Entry && Exit && Blocks.size() > 0; }
1626
1627 /// Return true if this CFG has been normalized.
1628 /// After normalization, blocks are in topological order, and block and
1629 /// instruction IDs have been assigned.
1630 bool normal() const { return Normal; }
1631
1632 iterator begin() { return Blocks.begin(); }
1633 iterator end() { return Blocks.end(); }
1634
1635 const_iterator begin() const { return cbegin(); }
1636 const_iterator end() const { return cend(); }
1637
1638 const_iterator cbegin() const { return Blocks.cbegin(); }
1639 const_iterator cend() const { return Blocks.cend(); }
1640
1641 const BasicBlock *entry() const { return Entry; }
1642 BasicBlock *entry() { return Entry; }
1643 const BasicBlock *exit() const { return Exit; }
1644 BasicBlock *exit() { return Exit; }
1645
1646 /// Return the number of blocks in the CFG.
1647 /// Block::blockID() will return a number less than numBlocks();
1648 size_t numBlocks() const { return Blocks.size(); }
1649
1650 /// Return the total number of instructions in the CFG.
1651 /// This is useful for building instruction side-tables;
1652 /// A call to SExpr::id() will return a number less than numInstructions().
1653 unsigned numInstructions() { return NumInstructions; }
1654
1655 inline void add(BasicBlock *BB) {
1656 assert(BB->CFGPtr == nullptr);
1657 BB->CFGPtr = this;
1658 Blocks.reserveCheck(1, Arena);
1659 Blocks.push_back(BB);
1660 }
1661
1662 void setEntry(BasicBlock *BB) { Entry = BB; }
1663 void setExit(BasicBlock *BB) { Exit = BB; }
1664
1665 void computeNormalForm();
1666
1667 template <class V>
1668 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1669 Vs.enterCFG(*this);
1670 typename V::template Container<BasicBlock *> Bbs(Vs, Blocks.size());
1671
1672 for (const auto *B : Blocks) {
1673 Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) );
1674 }
1675 Vs.exitCFG(*this);
1676 return Vs.reduceSCFG(*this, Bbs);
1677 }
1678
1679 template <class C>
1680 typename C::CType compare(const SCFG *E, C &Cmp) const {
1681 // TODO: implement CFG comparisons
1682 return Cmp.comparePointers(this, E);
1683 }
1684
1685private:
1686 // assign unique ids to all instructions
1687 void renumberInstrs();
1688
1689 MemRegionRef Arena;
1690 BlockArray Blocks;
1691 BasicBlock *Entry = nullptr;
1692 BasicBlock *Exit = nullptr;
1693 unsigned NumInstructions = 0;
1694 bool Normal = false;
1695};
1696
1697/// An identifier, e.g. 'foo' or 'x'.
1698/// This is a pseduo-term; it will be lowered to a variable or projection.
1699class Identifier : public SExpr {
1700public:
1701 Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) {}
1702 Identifier(const Identifier &) = default;
1703
1704 static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; }
1705
1706 StringRef name() const { return Name; }
1707
1708 template <class V>
1709 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1710 return Vs.reduceIdentifier(*this);
1711 }
1712
1713 template <class C>
1714 typename C::CType compare(const Identifier* E, C& Cmp) const {
1715 return Cmp.compareStrings(name(), E->name());
1716 }
1717
1718private:
1719 StringRef Name;
1720};
1721
1722/// An if-then-else expression.
1723/// This is a pseduo-term; it will be lowered to a branch in a CFG.
1724class IfThenElse : public SExpr {
1725public:
1727 : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E) {}
1729 : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) {}
1730
1731 static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; }
1732
1733 SExpr *condition() { return Condition; } // Address to store to
1734 const SExpr *condition() const { return Condition; }
1735
1736 SExpr *thenExpr() { return ThenExpr; } // Value to store
1737 const SExpr *thenExpr() const { return ThenExpr; }
1738
1739 SExpr *elseExpr() { return ElseExpr; } // Value to store
1740 const SExpr *elseExpr() const { return ElseExpr; }
1741
1742 template <class V>
1743 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1744 auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
1745 auto Nt = Vs.traverse(ThenExpr, Vs.subExprCtx(Ctx));
1746 auto Ne = Vs.traverse(ElseExpr, Vs.subExprCtx(Ctx));
1747 return Vs.reduceIfThenElse(*this, Nc, Nt, Ne);
1748 }
1749
1750 template <class C>
1751 typename C::CType compare(const IfThenElse* E, C& Cmp) const {
1752 typename C::CType Ct = Cmp.compare(condition(), E->condition());
1753 if (Cmp.notTrue(Ct))
1754 return Ct;
1755 Ct = Cmp.compare(thenExpr(), E->thenExpr());
1756 if (Cmp.notTrue(Ct))
1757 return Ct;
1758 return Cmp.compare(elseExpr(), E->elseExpr());
1759 }
1760
1761private:
1763 SExpr* ThenExpr;
1764 SExpr* ElseExpr;
1765};
1766
1767/// A let-expression, e.g. let x=t; u.
1768/// This is a pseduo-term; it will be lowered to instructions in a CFG.
1769class Let : public SExpr {
1770public:
1771 Let(Variable *Vd, SExpr *Bd) : SExpr(COP_Let), VarDecl(Vd), Body(Bd) {
1773 }
1774
1775 Let(const Let &L, Variable *Vd, SExpr *Bd) : SExpr(L), VarDecl(Vd), Body(Bd) {
1777 }
1778
1779 static bool classof(const SExpr *E) { return E->opcode() == COP_Let; }
1780
1781 Variable *variableDecl() { return VarDecl; }
1782 const Variable *variableDecl() const { return VarDecl; }
1783
1784 SExpr *body() { return Body; }
1785 const SExpr *body() const { return Body; }
1786
1787 template <class V>
1788 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1789 // This is a variable declaration, so traverse the definition.
1790 auto E0 = Vs.traverse(VarDecl->Definition, Vs.subExprCtx(Ctx));
1791 // Tell the rewriter to enter the scope of the let variable.
1792 Variable *Nvd = Vs.enterScope(*VarDecl, E0);
1793 auto E1 = Vs.traverse(Body, Ctx);
1794 Vs.exitScope(*VarDecl);
1795 return Vs.reduceLet(*this, Nvd, E1);
1796 }
1797
1798 template <class C>
1799 typename C::CType compare(const Let* E, C& Cmp) const {
1800 typename C::CType Ct =
1801 Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
1802 if (Cmp.notTrue(Ct))
1803 return Ct;
1804 Cmp.enterScope(variableDecl(), E->variableDecl());
1805 Ct = Cmp.compare(body(), E->body());
1806 Cmp.leaveScope();
1807 return Ct;
1808 }
1809
1810private:
1812 SExpr* Body;
1813};
1814
1815const SExpr *getCanonicalVal(const SExpr *E);
1816SExpr* simplifyToCanonicalVal(SExpr *E);
1818
1819} // namespace til
1820} // namespace threadSafety
1821
1822} // namespace clang
1823
1824#endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
#define V(N, I)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
__device__ __2f16 b
__device__ __2f16 float __ockl_bool s
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2946
This represents one expression.
Definition Expr.h:112
Stmt - This represents one statement.
Definition Stmt.h:86
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
Represents a variable declaration or definition.
Definition Decl.h:926
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
Alloc(const Alloc &A, SExpr *Dt)
C::CType compare(const Alloc *E, C &Cmp) const
Apply(const Apply &A, SExpr *F, SExpr *Ar)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
C::CType compare(const Apply *E, C &Cmp) const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N)
C::CType compare(const ArrayAdd *E, C &Cmp) const
static bool classof(const SExpr *E)
ArrayIndex(const ArrayIndex &E, SExpr *A, SExpr *N)
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
C::CType compare(const ArrayIndex *E, C &Cmp) const
A basic block is part of an SCFG.
unsigned addPredecessor(BasicBlock *Pred)
BasicBlock(BasicBlock &B, MemRegionRef A, InstrArray &&As, InstrArray &&Is, Terminator *T)
int blockID() const
Returns the block ID. Every block has a unique ID in the CFG.
const InstrArray & arguments() const
const InstrArray & instructions() const
bool Dominates(const BasicBlock &Other)
SimpleArray< BasicBlock * > BlockArray
const Terminator * terminator() const
const BlockArray & predecessors() const
ArrayRef< BasicBlock * > successors() const
C::CType compare(const BasicBlock *E, C &Cmp) const
ArrayRef< BasicBlock * > successors()
void addArgument(Phi *V)
Add a new argument.
size_t numPredecessors() const
Returns the number of predecessors.
bool PostDominates(const BasicBlock &Other)
V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
void reservePredecessors(unsigned NumPreds)
unsigned findPredecessorIndex(const BasicBlock *BB) const
Return the index of BB, or Predecessors.size if BB is not a predecessor.
BlockArray & predecessors()
Returns a list of predecessors.
const BasicBlock * parent() const
void addInstruction(SExpr *V)
Add a new instruction.
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
BinaryOp(TIL_BinaryOpcode Op, SExpr *E0, SExpr *E1)
static bool classof(const SExpr *E)
BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1)
TIL_BinaryOpcode binaryOpcode() const
C::CType compare(const BinaryOp *E, C &Cmp) const
Branch(SExpr *C, BasicBlock *T, BasicBlock *E)
const BasicBlock * elseBlock() const
C::CType compare(const Branch *E, C &Cmp) const
Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E)
static bool classof(const SExpr *E)
ArrayRef< BasicBlock * > successors() const
Return the list of basic blocks that this terminator can branch to.
const BasicBlock * thenBlock() const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
Call(const Call &C, SExpr *T)
Call(SExpr *T, const CallExpr *Ce=nullptr)
C::CType compare(const Call *E, C &Cmp) const
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
const CallExpr * clangCallExpr() const
C::CType compare(const Cast *E, C &Cmp) const
Cast(TIL_CastOpcode Op, SExpr *E)
static bool classof(const SExpr *E)
Cast(const Cast &C, SExpr *E)
TIL_CastOpcode castOpcode() const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
const SExpr * returnType() const
C::CType compare(const Code *E, C &Cmp) const
Code(const Code &C, SExpr *T, SExpr *B)
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
C::CType compare(const Field *E, C &Cmp) const
Field(const Field &C, SExpr *R, SExpr *B)
Function(const Function &F, Variable *Vd, SExpr *Bd)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
const Variable * variableDecl() const
C::CType compare(const Function *E, C &Cmp) const
static bool classof(const SExpr *E)
Function(Variable *Vd, SExpr *Bd)
C::CType compare(const Future *E, C &Cmp) const
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
ArrayRef< BasicBlock * > successors() const
Return the list of basic blocks that this terminator can branch to.
Goto(const Goto &G, BasicBlock *B, unsigned I)
C::CType compare(const Goto *E, C &Cmp) const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
Goto(BasicBlock *B, unsigned I)
unsigned index() const
Returns the index into the.
static bool classof(const SExpr *E)
const BasicBlock * targetBlock() const
C::CType compare(const Identifier *E, C &Cmp) const
Identifier(const Identifier &)=default
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
IfThenElse(const IfThenElse &I, SExpr *C, SExpr *T, SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
C::CType compare(const IfThenElse *E, C &Cmp) const
static bool classof(const SExpr *E)
IfThenElse(SExpr *C, SExpr *T, SExpr *E)
Let(const Let &L, Variable *Vd, SExpr *Bd)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
const Variable * variableDecl() const
C::CType compare(const Let *E, C &Cmp) const
Let(Variable *Vd, SExpr *Bd)
static bool classof(const SExpr *E)
const ValueDecl * clangDecl() const
C::CType compare(const LiteralPtr *E, C &Cmp) const
LiteralPtr(const LiteralPtr &)=default
void setClangDecl(const ValueDecl *VD)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
LiteralT & operator=(const LiteralT< T > &)=delete
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
const LiteralT< T > & as() const
C::CType compare(const Literal *E, C &Cmp) const
const SExpr * pointer() const
C::CType compare(const Load *E, C &Cmp) const
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
Load(const Load &L, SExpr *P)
Phi Node, for code in SSA form.
SimpleArray< SExpr * > ValArray
static bool classof(const SExpr *E)
C::CType compare(const Phi *E, C &Cmp) const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
const ValueDecl * clangDecl() const
Return the clang declaration of the variable for this Phi node, if any.
void setClangDecl(const ValueDecl *Cvd)
Set the clang variable associated with this Phi node.
Phi(MemRegionRef A, unsigned Nvals)
Phi(const Phi &P, ValArray &&Vs)
const ValArray & values() const
const ValueDecl * clangDecl() const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
C::CType compare(const Project *E, C &Cmp) const
Project(SExpr *R, const ValueDecl *Cvd)
Return from the enclosing function, passing the return value to the caller.
Return(const Return &R, SExpr *Rval)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
ArrayRef< BasicBlock * > successors() const
Return an empty list.
static bool classof(const SExpr *E)
C::CType compare(const Return *E, C &Cmp) const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
SApply(SExpr *Sf, SExpr *A=nullptr)
C::CType compare(const SApply *E, C &Cmp) const
SApply(SApply &A, SExpr *Sf, SExpr *Ar=nullptr)
static bool classof(const SExpr *E)
An SCFG is a control-flow graph.
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
const BasicBlock * entry() const
C::CType compare(const SCFG *E, C &Cmp) const
bool normal() const
Return true if this CFG has been normalized.
static bool classof(const SExpr *E)
SCFG(MemRegionRef A, unsigned Nblocks)
const BasicBlock * exit() const
BlockArray::const_iterator const_iterator
const_iterator cbegin() const
unsigned numInstructions()
Return the total number of instructions in the CFG.
size_t numBlocks() const
Return the number of blocks in the CFG.
bool valid() const
Return true if this CFG is valid.
SimpleArray< BasicBlock * > BlockArray
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.
void setID(BasicBlock *B, unsigned id)
Set the basic block and instruction ID for this expression.
SExpr & operator=(const SExpr &)=delete
unsigned id() const
Returns the instruction ID for this expression.
static bool classof(const SExpr *E)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
SFunction(const SFunction &F, Variable *Vd, SExpr *B)
const Variable * variableDecl() const
C::CType compare(const SFunction *E, C &Cmp) const
C::CType compare(const Store *E, C &Cmp) const
const SExpr * destination() const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
Store(const Store &S, SExpr *P, SExpr *V)
static bool classof(const SExpr *E)
Base class for basic block terminators: Branch, Goto, and Return.
ArrayRef< BasicBlock * > successors() const
Return the list of basic blocks that this terminator can branch to.
static bool classof(const SExpr *E)
static bool classof(const SExpr *E)
UnaryOp(const UnaryOp &U, SExpr *E)
TIL_UnaryOpcode unaryOpcode() const
C::CType compare(const UnaryOp *E, C &Cmp) const
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
UnaryOp(TIL_UnaryOpcode Op, SExpr *E)
C::CType compare(const Undefined *E, C &Cmp) const
Undefined & operator=(const Undefined &)=delete
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
Variable(SExpr *D, const ValueDecl *Cvd=nullptr)
Variable(const Variable &Vd, SExpr *D)
C::CType compare(const Variable *E, C &Cmp) const
StringRef name() const
Return the name of the variable, if any.
static bool classof(const SExpr *E)
Variable(StringRef s, SExpr *D=nullptr)
SExpr * definition()
Return the definition of the variable.
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
const ValueDecl * clangDecl() const
Return the clang declaration for this variable, if any.
void setClangDecl(const ValueDecl *VD)
@ VK_SFun
SFunction (self) parameter.
VariableKind kind() const
Return the kind of variable (let, function param, or self)
V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx)
static bool classof(const SExpr *E)
C::CType compare(const Wildcard *E, C &Cmp) const
Wildcard(const Wildcard &)=default
TIL_UnaryOpcode
Opcode for unary arithmetic operations.
bool operator==(const ValueType &a, const ValueType &b)
void simplifyIncompleteArg(til::Phi *Ph)
const TIL_BinaryOpcode BOP_Min
const TIL_UnaryOpcode UOP_Min
StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op)
Return the name of a binary opcode.
StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op)
Return the name of a unary opcode.
TIL_CastOpcode
Opcode for cast operations.
const TIL_CastOpcode CAST_Max
TIL_BinaryOpcode
Opcode for binary arithmetic operations.
SExpr * simplifyToCanonicalVal(SExpr *E)
const TIL_BinaryOpcode BOP_Max
const TIL_CastOpcode CAST_Min
const TIL_UnaryOpcode UOP_Max
const SExpr * getCanonicalVal(const SExpr *E)
LiteralT(T) -> LiteralT< T >
TIL_Opcode
Enum for the different distinct classes of SExpr.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Other
Other implicit parameter.
Definition Decl.h:1746
#define false
Definition stdbool.h:26
bool isParentOf(const TopologyNode &OtherNode)
bool isParentOfOrEqual(const TopologyNode &OtherNode)
ValueTypes are data types that can actually be held in registers.