clang 24.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 /// Set when the record is not the field's record, nor derived from it: the
851 /// owning object could not be reached (that would take a `container_of`).
852 /// The field is then printed qualified with its record, `inner->Outer::mu`.
853 bool isQualified() const { return (Flags & 0x02) != 0; }
854
855 void setQualified(bool b) {
856 if (b)
857 Flags |= 0x02;
858 else
859 Flags &= 0xFFFD;
860 }
861
862 StringRef slotName() const {
863 if (Cvdecl->getDeclName().isIdentifier())
864 return Cvdecl->getName();
865 if (!SlotName) {
866 SlotName = "";
867 llvm::raw_string_ostream OS(*SlotName);
868 Cvdecl->printName(OS);
869 }
870 return *SlotName;
871 }
872
873 template <class V>
874 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
875 auto Nr = Vs.traverse(Rec, Vs.subExprCtx(Ctx));
876 return Vs.reduceProject(*this, Nr);
877 }
878
879 template <class C>
880 typename C::CType compare(const Project* E, C& Cmp) const {
881 typename C::CType Ct = Cmp.compare(record(), E->record());
882 if (Cmp.notTrue(Ct))
883 return Ct;
884 return Cmp.comparePointers(Cvdecl, E->Cvdecl);
885 }
886
887private:
888 SExpr* Rec;
889 mutable std::optional<std::string> SlotName;
890 const ValueDecl *Cvdecl;
891};
892
893/// Call a function (after all arguments have been applied).
894class Call : public SExpr {
895public:
896 Call(SExpr *T, const CallExpr *Ce = nullptr)
897 : SExpr(COP_Call), Target(T), Cexpr(Ce) {}
898 Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {}
899
900 static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
901
902 SExpr *target() { return Target; }
903 const SExpr *target() const { return Target; }
904
905 const CallExpr *clangCallExpr() const { return Cexpr; }
906
907 template <class V>
908 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
909 auto Nt = Vs.traverse(Target, Vs.subExprCtx(Ctx));
910 return Vs.reduceCall(*this, Nt);
911 }
912
913 template <class C>
914 typename C::CType compare(const Call* E, C& Cmp) const {
915 return Cmp.compare(target(), E->target());
916 }
917
918private:
919 SExpr* Target;
920 const CallExpr *Cexpr;
921};
922
923/// Allocate memory for a new value on the heap or stack.
924class Alloc : public SExpr {
925public:
930
931 Alloc(SExpr *D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) { Flags = K; }
932 Alloc(const Alloc &A, SExpr *Dt) : SExpr(A), Dtype(Dt) { Flags = A.kind(); }
933
934 static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
935
936 AllocKind kind() const { return static_cast<AllocKind>(Flags); }
937
938 SExpr *dataType() { return Dtype; }
939 const SExpr *dataType() const { return Dtype; }
940
941 template <class V>
942 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
943 auto Nd = Vs.traverse(Dtype, Vs.declCtx(Ctx));
944 return Vs.reduceAlloc(*this, Nd);
945 }
946
947 template <class C>
948 typename C::CType compare(const Alloc* E, C& Cmp) const {
949 typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind());
950 if (Cmp.notTrue(Ct))
951 return Ct;
952 return Cmp.compare(dataType(), E->dataType());
953 }
954
955private:
956 SExpr* Dtype;
957};
958
959/// Load a value from memory.
960class Load : public SExpr {
961public:
962 Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {}
963 Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {}
964
965 static bool classof(const SExpr *E) { return E->opcode() == COP_Load; }
966
967 SExpr *pointer() { return Ptr; }
968 const SExpr *pointer() const { return Ptr; }
969
970 template <class V>
971 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
972 auto Np = Vs.traverse(Ptr, Vs.subExprCtx(Ctx));
973 return Vs.reduceLoad(*this, Np);
974 }
975
976 template <class C>
977 typename C::CType compare(const Load* E, C& Cmp) const {
978 return Cmp.compare(pointer(), E->pointer());
979 }
980
981private:
982 SExpr* Ptr;
983};
984
985/// Store a value to memory.
986/// The destination is a pointer to a field, the source is the value to store.
987class Store : public SExpr {
988public:
989 Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {}
990 Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {}
991
992 static bool classof(const SExpr *E) { return E->opcode() == COP_Store; }
993
994 SExpr *destination() { return Dest; } // Address to store to
995 const SExpr *destination() const { return Dest; }
996
997 SExpr *source() { return Source; } // Value to store
998 const SExpr *source() const { return Source; }
999
1000 template <class V>
1001 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1002 auto Np = Vs.traverse(Dest, Vs.subExprCtx(Ctx));
1003 auto Nv = Vs.traverse(Source, Vs.subExprCtx(Ctx));
1004 return Vs.reduceStore(*this, Np, Nv);
1005 }
1006
1007 template <class C>
1008 typename C::CType compare(const Store* E, C& Cmp) const {
1009 typename C::CType Ct = Cmp.compare(destination(), E->destination());
1010 if (Cmp.notTrue(Ct))
1011 return Ct;
1012 return Cmp.compare(source(), E->source());
1013 }
1014
1015private:
1016 SExpr* Dest;
1017 SExpr* Source;
1018};
1019
1020/// If p is a reference to an array, then p[i] is a reference to the i'th
1021/// element of the array.
1022class ArrayIndex : public SExpr {
1023public:
1024 ArrayIndex(SExpr *A, SExpr *N) : SExpr(COP_ArrayIndex), Array(A), Index(N) {}
1026 : SExpr(E), Array(A), Index(N) {}
1027
1028 static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; }
1029
1030 SExpr *array() { return Array; }
1031 const SExpr *array() const { return Array; }
1032
1033 SExpr *index() { return Index; }
1034 const SExpr *index() const { return Index; }
1035
1036 template <class V>
1037 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1038 auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
1039 auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
1040 return Vs.reduceArrayIndex(*this, Na, Ni);
1041 }
1042
1043 template <class C>
1044 typename C::CType compare(const ArrayIndex* E, C& Cmp) const {
1045 typename C::CType Ct = Cmp.compare(array(), E->array());
1046 if (Cmp.notTrue(Ct))
1047 return Ct;
1048 return Cmp.compare(index(), E->index());
1049 }
1050
1051private:
1052 SExpr* Array;
1053 SExpr* Index;
1054};
1055
1056/// Pointer arithmetic, restricted to arrays only.
1057/// If p is a reference to an array, then p + n, where n is an integer, is
1058/// a reference to a subarray.
1059class ArrayAdd : public SExpr {
1060public:
1061 ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {}
1062 ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N)
1063 : SExpr(E), Array(A), Index(N) {}
1064
1065 static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; }
1066
1067 SExpr *array() { return Array; }
1068 const SExpr *array() const { return Array; }
1069
1070 SExpr *index() { return Index; }
1071 const SExpr *index() const { return Index; }
1072
1073 template <class V>
1074 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1075 auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
1076 auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
1077 return Vs.reduceArrayAdd(*this, Na, Ni);
1078 }
1079
1080 template <class C>
1081 typename C::CType compare(const ArrayAdd* E, C& Cmp) const {
1082 typename C::CType Ct = Cmp.compare(array(), E->array());
1083 if (Cmp.notTrue(Ct))
1084 return Ct;
1085 return Cmp.compare(index(), E->index());
1086 }
1087
1088private:
1089 SExpr* Array;
1090 SExpr* Index;
1091};
1092
1093/// Simple arithmetic unary operations, e.g. negate and not.
1094/// These operations have no side-effects.
1095class UnaryOp : public SExpr {
1096public:
1097 UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) {
1098 Flags = Op;
1099 }
1100
1101 UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U), Expr0(E) { Flags = U.Flags; }
1102
1103 static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; }
1104
1106 return static_cast<TIL_UnaryOpcode>(Flags);
1107 }
1108
1109 SExpr *expr() { return Expr0; }
1110 const SExpr *expr() const { return Expr0; }
1111
1112 template <class V>
1113 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1114 auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1115 return Vs.reduceUnaryOp(*this, Ne);
1116 }
1117
1118 template <class C>
1119 typename C::CType compare(const UnaryOp* E, C& Cmp) const {
1120 typename C::CType Ct =
1121 Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode());
1122 if (Cmp.notTrue(Ct))
1123 return Ct;
1124 return Cmp.compare(expr(), E->expr());
1125 }
1126
1127private:
1128 SExpr* Expr0;
1129};
1130
1131/// Simple arithmetic binary operations, e.g. +, -, etc.
1132/// These operations have no side effects.
1133class BinaryOp : public SExpr {
1134public:
1136 : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) {
1137 Flags = Op;
1138 }
1139
1140 BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1)
1141 : SExpr(B), Expr0(E0), Expr1(E1) {
1142 Flags = B.Flags;
1143 }
1144
1145 static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; }
1146
1148 return static_cast<TIL_BinaryOpcode>(Flags);
1149 }
1150
1151 SExpr *expr0() { return Expr0; }
1152 const SExpr *expr0() const { return Expr0; }
1153
1154 SExpr *expr1() { return Expr1; }
1155 const SExpr *expr1() const { return Expr1; }
1156
1157 template <class V>
1158 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1159 auto Ne0 = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1160 auto Ne1 = Vs.traverse(Expr1, Vs.subExprCtx(Ctx));
1161 return Vs.reduceBinaryOp(*this, Ne0, Ne1);
1162 }
1163
1164 template <class C>
1165 typename C::CType compare(const BinaryOp* E, C& Cmp) const {
1166 typename C::CType Ct =
1167 Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode());
1168 if (Cmp.notTrue(Ct))
1169 return Ct;
1170 Ct = Cmp.compare(expr0(), E->expr0());
1171 if (Cmp.notTrue(Ct))
1172 return Ct;
1173 return Cmp.compare(expr1(), E->expr1());
1174 }
1175
1176private:
1177 SExpr* Expr0;
1178 SExpr* Expr1;
1179};
1180
1181/// Cast expressions.
1182/// Cast expressions are essentially unary operations, but we treat them
1183/// as a distinct AST node because they only change the type of the result.
1184class Cast : public SExpr {
1185public:
1186 Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; }
1187 Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; }
1188
1189 static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; }
1190
1192 return static_cast<TIL_CastOpcode>(Flags);
1193 }
1194
1195 SExpr *expr() { return Expr0; }
1196 const SExpr *expr() const { return Expr0; }
1197
1198 template <class V>
1199 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1200 auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1201 return Vs.reduceCast(*this, Ne);
1202 }
1203
1204 template <class C>
1205 typename C::CType compare(const Cast* E, C& Cmp) const {
1206 typename C::CType Ct =
1207 Cmp.compareIntegers(castOpcode(), E->castOpcode());
1208 if (Cmp.notTrue(Ct))
1209 return Ct;
1210 return Cmp.compare(expr(), E->expr());
1211 }
1212
1213private:
1214 SExpr* Expr0;
1215};
1216
1217class SCFG;
1218
1219/// Phi Node, for code in SSA form.
1220/// Each Phi node has an array of possible values that it can take,
1221/// depending on where control flow comes from.
1222class Phi : public SExpr {
1223public:
1225
1226 // In minimal SSA form, all Phi nodes are MultiVal.
1227 // During conversion to SSA, incomplete Phi nodes may be introduced, which
1228 // are later determined to be SingleVal, and are thus redundant.
1229 enum Status {
1230 PH_MultiVal = 0, // Phi node has multiple distinct values. (Normal)
1231 PH_SingleVal, // Phi node has one distinct value, and can be eliminated
1232 PH_Incomplete // Phi node is incomplete
1233 };
1234
1235 Phi() : SExpr(COP_Phi) {}
1236 Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
1237 Phi(const Phi &P, ValArray &&Vs) : SExpr(P), Values(std::move(Vs)) {}
1238
1239 static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
1240
1241 const ValArray &values() const { return Values; }
1242 ValArray &values() { return Values; }
1243
1244 Status status() const { return static_cast<Status>(Flags); }
1245 void setStatus(Status s) { Flags = s; }
1246
1247 /// Return the clang declaration of the variable for this Phi node, if any.
1248 const ValueDecl *clangDecl() const { return Cvdecl; }
1249
1250 /// Set the clang variable associated with this Phi node.
1251 void setClangDecl(const ValueDecl *Cvd) { Cvdecl = Cvd; }
1252
1253 template <class V>
1254 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1255 typename V::template Container<typename V::R_SExpr>
1256 Nvs(Vs, Values.size());
1257
1258 for (const auto *Val : Values)
1259 Nvs.push_back( Vs.traverse(Val, Vs.subExprCtx(Ctx)) );
1260 return Vs.reducePhi(*this, Nvs);
1261 }
1262
1263 template <class C>
1264 typename C::CType compare(const Phi *E, C &Cmp) const {
1265 // TODO: implement CFG comparisons
1266 return Cmp.comparePointers(this, E);
1267 }
1268
1269private:
1270 ValArray Values;
1271 const ValueDecl* Cvdecl = nullptr;
1272};
1273
1274/// Base class for basic block terminators: Branch, Goto, and Return.
1275class Terminator : public SExpr {
1276protected:
1278 Terminator(const SExpr &E) : SExpr(E) {}
1279
1280public:
1281 static bool classof(const SExpr *E) {
1282 return E->opcode() >= COP_Goto && E->opcode() <= COP_Return;
1283 }
1284
1285 /// Return the list of basic blocks that this terminator can branch to.
1287};
1288
1289/// Jump to another basic block.
1290/// A goto instruction is essentially a tail-recursive call into another
1291/// block. In addition to the block pointer, it specifies an index into the
1292/// phi nodes of that block. The index can be used to retrieve the "arguments"
1293/// of the call.
1294class Goto : public Terminator {
1295public:
1296 Goto(BasicBlock *B, unsigned I)
1297 : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
1298 Goto(const Goto &G, BasicBlock *B, unsigned I)
1299 : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
1300
1301 static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
1302
1303 const BasicBlock *targetBlock() const { return TargetBlock; }
1304 BasicBlock *targetBlock() { return TargetBlock; }
1305
1306 /// Returns the index into the
1307 unsigned index() const { return Index; }
1308
1309 /// Return the list of basic blocks that this terminator can branch to.
1310 ArrayRef<BasicBlock *> successors() const { return TargetBlock; }
1311
1312 template <class V>
1313 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1314 BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock);
1315 return Vs.reduceGoto(*this, Ntb);
1316 }
1317
1318 template <class C>
1319 typename C::CType compare(const Goto *E, C &Cmp) const {
1320 // TODO: implement CFG comparisons
1321 return Cmp.comparePointers(this, E);
1322 }
1323
1324private:
1325 BasicBlock *TargetBlock;
1326 unsigned Index;
1327};
1328
1329/// A conditional branch to two other blocks.
1330/// Note that unlike Goto, Branch does not have an index. The target blocks
1331/// must be child-blocks, and cannot have Phi nodes.
1332class Branch : public Terminator {
1333public:
1335 : Terminator(COP_Branch), Condition(C) {
1336 Branches[0] = T;
1337 Branches[1] = E;
1338 }
1339
1341 : Terminator(Br), Condition(C) {
1342 Branches[0] = T;
1343 Branches[1] = E;
1344 }
1345
1346 static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
1347
1348 const SExpr *condition() const { return Condition; }
1349 SExpr *condition() { return Condition; }
1350
1351 const BasicBlock *thenBlock() const { return Branches[0]; }
1352 BasicBlock *thenBlock() { return Branches[0]; }
1353
1354 const BasicBlock *elseBlock() const { return Branches[1]; }
1355 BasicBlock *elseBlock() { return Branches[1]; }
1356
1357 /// Return the list of basic blocks that this terminator can branch to.
1359
1360 template <class V>
1361 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1362 auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
1363 BasicBlock *Ntb = Vs.reduceBasicBlockRef(Branches[0]);
1364 BasicBlock *Nte = Vs.reduceBasicBlockRef(Branches[1]);
1365 return Vs.reduceBranch(*this, Nc, Ntb, Nte);
1366 }
1367
1368 template <class C>
1369 typename C::CType compare(const Branch *E, C &Cmp) const {
1370 // TODO: implement CFG comparisons
1371 return Cmp.comparePointers(this, E);
1372 }
1373
1374private:
1376 BasicBlock *Branches[2];
1377};
1378
1379/// Return from the enclosing function, passing the return value to the caller.
1380/// Only the exit block should end with a return statement.
1381class Return : public Terminator {
1382public:
1383 Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {}
1384 Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {}
1385
1386 static bool classof(const SExpr *E) { return E->opcode() == COP_Return; }
1387
1388 /// Return an empty list.
1389 ArrayRef<BasicBlock *> successors() const { return {}; }
1390
1391 SExpr *returnValue() { return Retval; }
1392 const SExpr *returnValue() const { return Retval; }
1393
1394 template <class V>
1395 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1396 auto Ne = Vs.traverse(Retval, Vs.subExprCtx(Ctx));
1397 return Vs.reduceReturn(*this, Ne);
1398 }
1399
1400 template <class C>
1401 typename C::CType compare(const Return *E, C &Cmp) const {
1402 return Cmp.compare(Retval, E->Retval);
1403 }
1404
1405private:
1406 SExpr* Retval;
1407};
1408
1410 switch (opcode()) {
1411 case COP_Goto: return cast<Goto>(this)->successors();
1412 case COP_Branch: return cast<Branch>(this)->successors();
1413 case COP_Return: return cast<Return>(this)->successors();
1414 default:
1415 return {};
1416 }
1417}
1418
1419/// A basic block is part of an SCFG. It can be treated as a function in
1420/// continuation passing style. A block consists of a sequence of phi nodes,
1421/// which are "arguments" to the function, followed by a sequence of
1422/// instructions. It ends with a Terminator, which is a Branch or Goto to
1423/// another basic block in the same SCFG.
1424class BasicBlock : public SExpr {
1425public:
1428
1429 // TopologyNodes are used to overlay tree structures on top of the CFG,
1430 // such as dominator and postdominator trees. Each block is assigned an
1431 // ID in the tree according to a depth-first search. Tree traversals are
1432 // always up, towards the parents.
1434 int NodeID = 0;
1435
1436 // Includes this node, so must be > 1.
1438
1439 // Pointer to parent.
1440 BasicBlock *Parent = nullptr;
1441
1442 TopologyNode() = default;
1443
1444 bool isParentOf(const TopologyNode& OtherNode) {
1445 return OtherNode.NodeID > NodeID &&
1446 OtherNode.NodeID < NodeID + SizeOfSubTree;
1447 }
1448
1449 bool isParentOfOrEqual(const TopologyNode& OtherNode) {
1450 return OtherNode.NodeID >= NodeID &&
1451 OtherNode.NodeID < NodeID + SizeOfSubTree;
1452 }
1453 };
1454
1456 : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false) {}
1458 Terminator *T)
1459 : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false),
1460 Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {}
1461
1462 static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; }
1463
1464 /// Returns the block ID. Every block has a unique ID in the CFG.
1465 int blockID() const { return BlockID; }
1466
1467 /// Returns the number of predecessors.
1468 size_t numPredecessors() const { return Predecessors.size(); }
1469 size_t numSuccessors() const { return successors().size(); }
1470
1471 const SCFG* cfg() const { return CFGPtr; }
1472 SCFG* cfg() { return CFGPtr; }
1473
1474 const BasicBlock *parent() const { return DominatorNode.Parent; }
1475 BasicBlock *parent() { return DominatorNode.Parent; }
1476
1477 const InstrArray &arguments() const { return Args; }
1478 InstrArray &arguments() { return Args; }
1479
1480 InstrArray &instructions() { return Instrs; }
1481 const InstrArray &instructions() const { return Instrs; }
1482
1483 /// Returns a list of predecessors.
1484 /// The order of predecessors in the list is important; each phi node has
1485 /// exactly one argument for each precessor, in the same order.
1486 BlockArray &predecessors() { return Predecessors; }
1487 const BlockArray &predecessors() const { return Predecessors; }
1488
1489 ArrayRef<BasicBlock*> successors() { return TermInstr->successors(); }
1490 ArrayRef<BasicBlock*> successors() const { return TermInstr->successors(); }
1491
1492 const Terminator *terminator() const { return TermInstr; }
1493 Terminator *terminator() { return TermInstr; }
1494
1495 void setTerminator(Terminator *E) { TermInstr = E; }
1496
1498 return DominatorNode.isParentOfOrEqual(Other.DominatorNode);
1499 }
1500
1502 return PostDominatorNode.isParentOfOrEqual(Other.PostDominatorNode);
1503 }
1504
1505 /// Add a new argument.
1507 Args.reserveCheck(1, Arena);
1508 Args.push_back(V);
1509 }
1510
1511 /// Add a new instruction.
1513 Instrs.reserveCheck(1, Arena);
1514 Instrs.push_back(V);
1515 }
1516
1517 // Add a new predecessor, and return the phi-node index for it.
1518 // Will add an argument to all phi-nodes, initialized to nullptr.
1519 unsigned addPredecessor(BasicBlock *Pred);
1520
1521 // Reserve space for Nargs arguments.
1522 void reserveArguments(unsigned Nargs) { Args.reserve(Nargs, Arena); }
1523
1524 // Reserve space for Nins instructions.
1525 void reserveInstructions(unsigned Nins) { Instrs.reserve(Nins, Arena); }
1526
1527 // Reserve space for NumPreds predecessors, including space in phi nodes.
1528 void reservePredecessors(unsigned NumPreds);
1529
1530 /// Return the index of BB, or Predecessors.size if BB is not a predecessor.
1531 unsigned findPredecessorIndex(const BasicBlock *BB) const {
1532 auto I = llvm::find(Predecessors, BB);
1533 return std::distance(Predecessors.cbegin(), I);
1534 }
1535
1536 template <class V>
1537 typename V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx) {
1538 typename V::template Container<SExpr*> Nas(Vs, Args.size());
1539 typename V::template Container<SExpr*> Nis(Vs, Instrs.size());
1540
1541 // Entering the basic block should do any scope initialization.
1542 Vs.enterBasicBlock(*this);
1543
1544 for (const auto *E : Args) {
1545 auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
1546 Nas.push_back(Ne);
1547 }
1548 for (const auto *E : Instrs) {
1549 auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
1550 Nis.push_back(Ne);
1551 }
1552 auto Nt = Vs.traverse(TermInstr, Ctx);
1553
1554 // Exiting the basic block should handle any scope cleanup.
1555 Vs.exitBasicBlock(*this);
1556
1557 return Vs.reduceBasicBlock(*this, Nas, Nis, Nt);
1558 }
1559
1560 template <class C>
1561 typename C::CType compare(const BasicBlock *E, C &Cmp) const {
1562 // TODO: implement CFG comparisons
1563 return Cmp.comparePointers(this, E);
1564 }
1565
1566private:
1567 friend class SCFG;
1568
1569 // assign unique ids to all instructions
1570 unsigned renumberInstrs(unsigned id);
1571
1572 unsigned topologicalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
1573 unsigned topologicalFinalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
1574 void computeDominator();
1575 void computePostDominator();
1576
1577 // The arena used to allocate this block.
1578 MemRegionRef Arena;
1579
1580 // The CFG that contains this block.
1581 SCFG *CFGPtr = nullptr;
1582
1583 // Unique ID for this BB in the containing CFG. IDs are in topological order.
1584 unsigned BlockID : 31;
1585
1586 // Bit to determine if a block has been visited during a traversal.
1587 LLVM_PREFERRED_TYPE(bool)
1588 unsigned Visited : 1;
1589
1590 // Predecessor blocks in the CFG.
1591 BlockArray Predecessors;
1592
1593 // Phi nodes. One argument per predecessor.
1594 InstrArray Args;
1595
1596 // Instructions.
1597 InstrArray Instrs;
1598
1599 // Terminating instruction.
1600 Terminator *TermInstr = nullptr;
1601
1602 // The dominator tree.
1603 TopologyNode DominatorNode;
1604
1605 // The post-dominator tree.
1606 TopologyNode PostDominatorNode;
1607};
1608
1609/// An SCFG is a control-flow graph. It consists of a set of basic blocks,
1610/// each of which terminates in a branch to another basic block. There is one
1611/// entry point, and one exit point.
1612class SCFG : public SExpr {
1613public:
1617
1618 SCFG(MemRegionRef A, unsigned Nblocks)
1619 : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks) {
1620 Entry = new (A) BasicBlock(A);
1621 Exit = new (A) BasicBlock(A);
1622 auto *V = new (A) Phi();
1623 Exit->addArgument(V);
1624 Exit->setTerminator(new (A) Return(V));
1625 add(Entry);
1626 add(Exit);
1627 }
1628
1629 SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba
1630 : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)) {
1631 // TODO: set entry and exit!
1632 }
1633
1634 static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
1635
1636 /// Return true if this CFG is valid.
1637 bool valid() const { return Entry && Exit && Blocks.size() > 0; }
1638
1639 /// Return true if this CFG has been normalized.
1640 /// After normalization, blocks are in topological order, and block and
1641 /// instruction IDs have been assigned.
1642 bool normal() const { return Normal; }
1643
1644 iterator begin() { return Blocks.begin(); }
1645 iterator end() { return Blocks.end(); }
1646
1647 const_iterator begin() const { return cbegin(); }
1648 const_iterator end() const { return cend(); }
1649
1650 const_iterator cbegin() const { return Blocks.cbegin(); }
1651 const_iterator cend() const { return Blocks.cend(); }
1652
1653 const BasicBlock *entry() const { return Entry; }
1654 BasicBlock *entry() { return Entry; }
1655 const BasicBlock *exit() const { return Exit; }
1656 BasicBlock *exit() { return Exit; }
1657
1658 /// Return the number of blocks in the CFG.
1659 /// Block::blockID() will return a number less than numBlocks();
1660 size_t numBlocks() const { return Blocks.size(); }
1661
1662 /// Return the total number of instructions in the CFG.
1663 /// This is useful for building instruction side-tables;
1664 /// A call to SExpr::id() will return a number less than numInstructions().
1665 unsigned numInstructions() { return NumInstructions; }
1666
1667 inline void add(BasicBlock *BB) {
1668 assert(BB->CFGPtr == nullptr);
1669 BB->CFGPtr = this;
1670 Blocks.reserveCheck(1, Arena);
1671 Blocks.push_back(BB);
1672 }
1673
1674 void setEntry(BasicBlock *BB) { Entry = BB; }
1675 void setExit(BasicBlock *BB) { Exit = BB; }
1676
1677 void computeNormalForm();
1678
1679 template <class V>
1680 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1681 Vs.enterCFG(*this);
1682 typename V::template Container<BasicBlock *> Bbs(Vs, Blocks.size());
1683
1684 for (const auto *B : Blocks) {
1685 Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) );
1686 }
1687 Vs.exitCFG(*this);
1688 return Vs.reduceSCFG(*this, Bbs);
1689 }
1690
1691 template <class C>
1692 typename C::CType compare(const SCFG *E, C &Cmp) const {
1693 // TODO: implement CFG comparisons
1694 return Cmp.comparePointers(this, E);
1695 }
1696
1697private:
1698 // assign unique ids to all instructions
1699 void renumberInstrs();
1700
1701 MemRegionRef Arena;
1702 BlockArray Blocks;
1703 BasicBlock *Entry = nullptr;
1704 BasicBlock *Exit = nullptr;
1705 unsigned NumInstructions = 0;
1706 bool Normal = false;
1707};
1708
1709/// An identifier, e.g. 'foo' or 'x'.
1710/// This is a pseduo-term; it will be lowered to a variable or projection.
1711class Identifier : public SExpr {
1712public:
1713 Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) {}
1714 Identifier(const Identifier &) = default;
1715
1716 static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; }
1717
1718 StringRef name() const { return Name; }
1719
1720 template <class V>
1721 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1722 return Vs.reduceIdentifier(*this);
1723 }
1724
1725 template <class C>
1726 typename C::CType compare(const Identifier* E, C& Cmp) const {
1727 return Cmp.compareStrings(name(), E->name());
1728 }
1729
1730private:
1731 StringRef Name;
1732};
1733
1734/// An if-then-else expression.
1735/// This is a pseduo-term; it will be lowered to a branch in a CFG.
1736class IfThenElse : public SExpr {
1737public:
1739 : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E) {}
1741 : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) {}
1742
1743 static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; }
1744
1745 SExpr *condition() { return Condition; } // Address to store to
1746 const SExpr *condition() const { return Condition; }
1747
1748 SExpr *thenExpr() { return ThenExpr; } // Value to store
1749 const SExpr *thenExpr() const { return ThenExpr; }
1750
1751 SExpr *elseExpr() { return ElseExpr; } // Value to store
1752 const SExpr *elseExpr() const { return ElseExpr; }
1753
1754 template <class V>
1755 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1756 auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
1757 auto Nt = Vs.traverse(ThenExpr, Vs.subExprCtx(Ctx));
1758 auto Ne = Vs.traverse(ElseExpr, Vs.subExprCtx(Ctx));
1759 return Vs.reduceIfThenElse(*this, Nc, Nt, Ne);
1760 }
1761
1762 template <class C>
1763 typename C::CType compare(const IfThenElse* E, C& Cmp) const {
1764 typename C::CType Ct = Cmp.compare(condition(), E->condition());
1765 if (Cmp.notTrue(Ct))
1766 return Ct;
1767 Ct = Cmp.compare(thenExpr(), E->thenExpr());
1768 if (Cmp.notTrue(Ct))
1769 return Ct;
1770 return Cmp.compare(elseExpr(), E->elseExpr());
1771 }
1772
1773private:
1775 SExpr* ThenExpr;
1776 SExpr* ElseExpr;
1777};
1778
1779/// A let-expression, e.g. let x=t; u.
1780/// This is a pseduo-term; it will be lowered to instructions in a CFG.
1781class Let : public SExpr {
1782public:
1783 Let(Variable *Vd, SExpr *Bd) : SExpr(COP_Let), VarDecl(Vd), Body(Bd) {
1785 }
1786
1787 Let(const Let &L, Variable *Vd, SExpr *Bd) : SExpr(L), VarDecl(Vd), Body(Bd) {
1789 }
1790
1791 static bool classof(const SExpr *E) { return E->opcode() == COP_Let; }
1792
1793 Variable *variableDecl() { return VarDecl; }
1794 const Variable *variableDecl() const { return VarDecl; }
1795
1796 SExpr *body() { return Body; }
1797 const SExpr *body() const { return Body; }
1798
1799 template <class V>
1800 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1801 // This is a variable declaration, so traverse the definition.
1802 auto E0 = Vs.traverse(VarDecl->Definition, Vs.subExprCtx(Ctx));
1803 // Tell the rewriter to enter the scope of the let variable.
1804 Variable *Nvd = Vs.enterScope(*VarDecl, E0);
1805 auto E1 = Vs.traverse(Body, Ctx);
1806 Vs.exitScope(*VarDecl);
1807 return Vs.reduceLet(*this, Nvd, E1);
1808 }
1809
1810 template <class C>
1811 typename C::CType compare(const Let* E, C& Cmp) const {
1812 typename C::CType Ct =
1813 Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
1814 if (Cmp.notTrue(Ct))
1815 return Ct;
1816 Cmp.enterScope(variableDecl(), E->variableDecl());
1817 Ct = Cmp.compare(body(), E->body());
1818 Cmp.leaveScope();
1819 return Ct;
1820 }
1821
1822private:
1824 SExpr* Body;
1825};
1826
1827const SExpr *getCanonicalVal(const SExpr *E);
1828SExpr* simplifyToCanonicalVal(SExpr *E);
1830
1831} // namespace til
1832} // namespace threadSafety
1833
1834} // namespace clang
1835
1836#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.
llvm::json::Array Array
__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:3012
This represents one expression.
Definition Expr.h:114
Stmt - This represents one statement.
Definition Stmt.h:85
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:714
Represents a variable declaration or definition.
Definition Decl.h:934
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)
bool isQualified() const
Set when the record is not the field's record, nor derived from it: the owning object could not be re...
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.
Top level wrappers for InstallAPI frontend operations.
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Other
Other implicit parameter.
Definition Decl.h:1787
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 int64_t
#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.