File indexing completed on 2026-05-10 08:36:24
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
0047 #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
0048
0049 #include "clang/AST/Decl.h"
0050 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
0051 #include "clang/Basic/LLVM.h"
0052 #include "llvm/ADT/ArrayRef.h"
0053 #include "llvm/ADT/StringRef.h"
0054 #include "llvm/Support/Casting.h"
0055 #include "llvm/Support/raw_ostream.h"
0056 #include <algorithm>
0057 #include <cassert>
0058 #include <cstddef>
0059 #include <cstdint>
0060 #include <iterator>
0061 #include <optional>
0062 #include <string>
0063 #include <utility>
0064
0065 namespace clang {
0066
0067 class CallExpr;
0068 class Expr;
0069 class Stmt;
0070
0071 namespace threadSafety {
0072 namespace til {
0073
0074 class BasicBlock;
0075
0076
0077 enum TIL_Opcode : unsigned char {
0078 #define TIL_OPCODE_DEF(X) COP_##X,
0079 #include "ThreadSafetyOps.def"
0080 #undef TIL_OPCODE_DEF
0081 };
0082
0083
0084 enum TIL_UnaryOpcode : unsigned char {
0085 UOP_Minus,
0086 UOP_BitNot,
0087 UOP_LogicNot
0088 };
0089
0090
0091 enum TIL_BinaryOpcode : unsigned char {
0092 BOP_Add,
0093 BOP_Sub,
0094 BOP_Mul,
0095 BOP_Div,
0096 BOP_Rem,
0097 BOP_Shl,
0098 BOP_Shr,
0099 BOP_BitAnd,
0100 BOP_BitXor,
0101 BOP_BitOr,
0102 BOP_Eq,
0103 BOP_Neq,
0104 BOP_Lt,
0105 BOP_Leq,
0106 BOP_Cmp,
0107 BOP_LogicAnd,
0108 BOP_LogicOr
0109 };
0110
0111
0112 enum TIL_CastOpcode : unsigned char {
0113 CAST_none = 0,
0114
0115
0116 CAST_extendNum,
0117
0118
0119 CAST_truncNum,
0120
0121
0122 CAST_toFloat,
0123
0124
0125 CAST_toInt,
0126
0127
0128 CAST_objToPtr
0129 };
0130
0131 const TIL_Opcode COP_Min = COP_Future;
0132 const TIL_Opcode COP_Max = COP_Branch;
0133 const TIL_UnaryOpcode UOP_Min = UOP_Minus;
0134 const TIL_UnaryOpcode UOP_Max = UOP_LogicNot;
0135 const TIL_BinaryOpcode BOP_Min = BOP_Add;
0136 const TIL_BinaryOpcode BOP_Max = BOP_LogicOr;
0137 const TIL_CastOpcode CAST_Min = CAST_none;
0138 const TIL_CastOpcode CAST_Max = CAST_toInt;
0139
0140
0141 StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op);
0142
0143
0144 StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op);
0145
0146
0147
0148
0149
0150
0151
0152 struct ValueType {
0153 enum BaseType : unsigned char {
0154 BT_Void = 0,
0155 BT_Bool,
0156 BT_Int,
0157 BT_Float,
0158 BT_String,
0159 BT_Pointer,
0160 BT_ValueRef
0161 };
0162
0163 enum SizeType : unsigned char {
0164 ST_0 = 0,
0165 ST_1,
0166 ST_8,
0167 ST_16,
0168 ST_32,
0169 ST_64,
0170 ST_128
0171 };
0172
0173 ValueType(BaseType B, SizeType Sz, bool S, unsigned char VS)
0174 : Base(B), Size(Sz), Signed(S), VectSize(VS) {}
0175
0176 inline static SizeType getSizeType(unsigned nbytes);
0177
0178 template <class T>
0179 inline static ValueType getValueType();
0180
0181 BaseType Base;
0182 SizeType Size;
0183 bool Signed;
0184
0185
0186 unsigned char VectSize;
0187 };
0188
0189 inline ValueType::SizeType ValueType::getSizeType(unsigned nbytes) {
0190 switch (nbytes) {
0191 case 1: return ST_8;
0192 case 2: return ST_16;
0193 case 4: return ST_32;
0194 case 8: return ST_64;
0195 case 16: return ST_128;
0196 default: return ST_0;
0197 }
0198 }
0199
0200 template<>
0201 inline ValueType ValueType::getValueType<void>() {
0202 return ValueType(BT_Void, ST_0, false, 0);
0203 }
0204
0205 template<>
0206 inline ValueType ValueType::getValueType<bool>() {
0207 return ValueType(BT_Bool, ST_1, false, 0);
0208 }
0209
0210 template<>
0211 inline ValueType ValueType::getValueType<int8_t>() {
0212 return ValueType(BT_Int, ST_8, true, 0);
0213 }
0214
0215 template<>
0216 inline ValueType ValueType::getValueType<uint8_t>() {
0217 return ValueType(BT_Int, ST_8, false, 0);
0218 }
0219
0220 template<>
0221 inline ValueType ValueType::getValueType<int16_t>() {
0222 return ValueType(BT_Int, ST_16, true, 0);
0223 }
0224
0225 template<>
0226 inline ValueType ValueType::getValueType<uint16_t>() {
0227 return ValueType(BT_Int, ST_16, false, 0);
0228 }
0229
0230 template<>
0231 inline ValueType ValueType::getValueType<int32_t>() {
0232 return ValueType(BT_Int, ST_32, true, 0);
0233 }
0234
0235 template<>
0236 inline ValueType ValueType::getValueType<uint32_t>() {
0237 return ValueType(BT_Int, ST_32, false, 0);
0238 }
0239
0240 template<>
0241 inline ValueType ValueType::getValueType<int64_t>() {
0242 return ValueType(BT_Int, ST_64, true, 0);
0243 }
0244
0245 template<>
0246 inline ValueType ValueType::getValueType<uint64_t>() {
0247 return ValueType(BT_Int, ST_64, false, 0);
0248 }
0249
0250 template<>
0251 inline ValueType ValueType::getValueType<float>() {
0252 return ValueType(BT_Float, ST_32, true, 0);
0253 }
0254
0255 template<>
0256 inline ValueType ValueType::getValueType<double>() {
0257 return ValueType(BT_Float, ST_64, true, 0);
0258 }
0259
0260 template<>
0261 inline ValueType ValueType::getValueType<long double>() {
0262 return ValueType(BT_Float, ST_128, true, 0);
0263 }
0264
0265 template<>
0266 inline ValueType ValueType::getValueType<StringRef>() {
0267 return ValueType(BT_String, getSizeType(sizeof(StringRef)), false, 0);
0268 }
0269
0270 template<>
0271 inline ValueType ValueType::getValueType<void*>() {
0272 return ValueType(BT_Pointer, getSizeType(sizeof(void*)), false, 0);
0273 }
0274
0275
0276 class SExpr {
0277 public:
0278 SExpr() = delete;
0279
0280 TIL_Opcode opcode() const { return Opcode; }
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296 void *operator new(size_t S, MemRegionRef &R) {
0297 return ::operator new(S, R);
0298 }
0299
0300
0301 void *operator new(size_t) = delete;
0302
0303
0304
0305
0306 void operator delete(void *) = delete;
0307
0308
0309
0310 unsigned id() const { return SExprID; }
0311
0312
0313
0314 BasicBlock *block() const { return Block; }
0315
0316
0317 void setID(BasicBlock *B, unsigned id) { Block = B; SExprID = id; }
0318
0319 protected:
0320 SExpr(TIL_Opcode Op) : Opcode(Op) {}
0321 SExpr(const SExpr &E) : Opcode(E.Opcode), Flags(E.Flags) {}
0322 SExpr &operator=(const SExpr &) = delete;
0323
0324 const TIL_Opcode Opcode;
0325 unsigned char Reserved = 0;
0326 unsigned short Flags = 0;
0327 unsigned SExprID = 0;
0328 BasicBlock *Block = nullptr;
0329 };
0330
0331
0332 namespace ThreadSafetyTIL {
0333
0334 inline bool isTrivial(const SExpr *E) {
0335 TIL_Opcode Op = E->opcode();
0336 return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
0337 }
0338
0339 }
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355 class Variable : public SExpr {
0356 public:
0357 enum VariableKind {
0358
0359 VK_Let,
0360
0361
0362 VK_Fun,
0363
0364
0365 VK_SFun
0366 };
0367
0368 Variable(StringRef s, SExpr *D = nullptr)
0369 : SExpr(COP_Variable), Name(s), Definition(D) {
0370 Flags = VK_Let;
0371 }
0372
0373 Variable(SExpr *D, const ValueDecl *Cvd = nullptr)
0374 : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"),
0375 Definition(D), Cvdecl(Cvd) {
0376 Flags = VK_Let;
0377 }
0378
0379 Variable(const Variable &Vd, SExpr *D)
0380 : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl) {
0381 Flags = Vd.kind();
0382 }
0383
0384 static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; }
0385
0386
0387 VariableKind kind() const { return static_cast<VariableKind>(Flags); }
0388
0389
0390 StringRef name() const { return Name; }
0391
0392
0393 const ValueDecl *clangDecl() const { return Cvdecl; }
0394
0395
0396
0397
0398 SExpr *definition() { return Definition; }
0399 const SExpr *definition() const { return Definition; }
0400
0401 void setName(StringRef S) { Name = S; }
0402 void setKind(VariableKind K) { Flags = K; }
0403 void setDefinition(SExpr *E) { Definition = E; }
0404 void setClangDecl(const ValueDecl *VD) { Cvdecl = VD; }
0405
0406 template <class V>
0407 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0408
0409 return Vs.reduceVariableRef(this);
0410 }
0411
0412 template <class C>
0413 typename C::CType compare(const Variable* E, C& Cmp) const {
0414 return Cmp.compareVariableRefs(this, E);
0415 }
0416
0417 private:
0418 friend class BasicBlock;
0419 friend class Function;
0420 friend class Let;
0421 friend class SFunction;
0422
0423
0424 StringRef Name;
0425
0426
0427 SExpr *Definition;
0428
0429
0430 const ValueDecl *Cvdecl = nullptr;
0431 };
0432
0433
0434
0435 class Future : public SExpr {
0436 public:
0437 enum FutureStatus {
0438 FS_pending,
0439 FS_evaluating,
0440 FS_done
0441 };
0442
0443 Future() : SExpr(COP_Future) {}
0444 virtual ~Future() = delete;
0445
0446 static bool classof(const SExpr *E) { return E->opcode() == COP_Future; }
0447
0448
0449 virtual SExpr *compute() { return nullptr; }
0450
0451
0452 SExpr *maybeGetResult() const { return Result; }
0453
0454
0455 SExpr *result() {
0456 switch (Status) {
0457 case FS_pending:
0458 return force();
0459 case FS_evaluating:
0460 return nullptr;
0461 case FS_done:
0462 return Result;
0463 }
0464 }
0465
0466 template <class V>
0467 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0468 assert(Result && "Cannot traverse Future that has not been forced.");
0469 return Vs.traverse(Result, Ctx);
0470 }
0471
0472 template <class C>
0473 typename C::CType compare(const Future* E, C& Cmp) const {
0474 if (!Result || !E->Result)
0475 return Cmp.comparePointers(this, E);
0476 return Cmp.compare(Result, E->Result);
0477 }
0478
0479 private:
0480 SExpr* force();
0481
0482 FutureStatus Status = FS_pending;
0483 SExpr *Result = nullptr;
0484 };
0485
0486
0487 class Undefined : public SExpr {
0488 public:
0489 Undefined(const Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {}
0490 Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {}
0491
0492
0493
0494 Undefined &operator=(const Undefined &) = delete;
0495
0496 static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; }
0497
0498 template <class V>
0499 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0500 return Vs.reduceUndefined(*this);
0501 }
0502
0503 template <class C>
0504 typename C::CType compare(const Undefined* E, C& Cmp) const {
0505 return Cmp.trueResult();
0506 }
0507
0508 private:
0509 const Stmt *Cstmt;
0510 };
0511
0512
0513 class Wildcard : public SExpr {
0514 public:
0515 Wildcard() : SExpr(COP_Wildcard) {}
0516 Wildcard(const Wildcard &) = default;
0517
0518 static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; }
0519
0520 template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0521 return Vs.reduceWildcard(*this);
0522 }
0523
0524 template <class C>
0525 typename C::CType compare(const Wildcard* E, C& Cmp) const {
0526 return Cmp.trueResult();
0527 }
0528 };
0529
0530 template <class T> class LiteralT;
0531
0532
0533 class Literal : public SExpr {
0534 public:
0535 Literal(const Expr *C)
0536 : SExpr(COP_Literal), ValType(ValueType::getValueType<void>()), Cexpr(C) {}
0537 Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT) {}
0538 Literal(const Literal &) = default;
0539
0540 static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; }
0541
0542
0543 const Expr *clangExpr() const { return Cexpr; }
0544
0545 ValueType valueType() const { return ValType; }
0546
0547 template<class T> const LiteralT<T>& as() const {
0548 return *static_cast<const LiteralT<T>*>(this);
0549 }
0550 template<class T> LiteralT<T>& as() {
0551 return *static_cast<LiteralT<T>*>(this);
0552 }
0553
0554 template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx);
0555
0556 template <class C>
0557 typename C::CType compare(const Literal* E, C& Cmp) const {
0558
0559 return Cmp.trueResult();
0560 }
0561
0562 private:
0563 const ValueType ValType;
0564 const Expr *Cexpr = nullptr;
0565 };
0566
0567
0568 template<class T>
0569 class LiteralT : public Literal {
0570 public:
0571 LiteralT(T Dat) : Literal(ValueType::getValueType<T>()), Val(Dat) {}
0572 LiteralT(const LiteralT<T> &L) : Literal(L), Val(L.Val) {}
0573
0574
0575
0576 LiteralT &operator=(const LiteralT<T> &) = delete;
0577
0578 T value() const { return Val;}
0579 T& value() { return Val; }
0580
0581 private:
0582 T Val;
0583 };
0584
0585 template <class V>
0586 typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) {
0587 if (Cexpr)
0588 return Vs.reduceLiteral(*this);
0589
0590 switch (ValType.Base) {
0591 case ValueType::BT_Void:
0592 break;
0593 case ValueType::BT_Bool:
0594 return Vs.reduceLiteralT(as<bool>());
0595 case ValueType::BT_Int: {
0596 switch (ValType.Size) {
0597 case ValueType::ST_8:
0598 if (ValType.Signed)
0599 return Vs.reduceLiteralT(as<int8_t>());
0600 else
0601 return Vs.reduceLiteralT(as<uint8_t>());
0602 case ValueType::ST_16:
0603 if (ValType.Signed)
0604 return Vs.reduceLiteralT(as<int16_t>());
0605 else
0606 return Vs.reduceLiteralT(as<uint16_t>());
0607 case ValueType::ST_32:
0608 if (ValType.Signed)
0609 return Vs.reduceLiteralT(as<int32_t>());
0610 else
0611 return Vs.reduceLiteralT(as<uint32_t>());
0612 case ValueType::ST_64:
0613 if (ValType.Signed)
0614 return Vs.reduceLiteralT(as<int64_t>());
0615 else
0616 return Vs.reduceLiteralT(as<uint64_t>());
0617 default:
0618 break;
0619 }
0620 }
0621 case ValueType::BT_Float: {
0622 switch (ValType.Size) {
0623 case ValueType::ST_32:
0624 return Vs.reduceLiteralT(as<float>());
0625 case ValueType::ST_64:
0626 return Vs.reduceLiteralT(as<double>());
0627 default:
0628 break;
0629 }
0630 }
0631 case ValueType::BT_String:
0632 return Vs.reduceLiteralT(as<StringRef>());
0633 case ValueType::BT_Pointer:
0634 return Vs.reduceLiteralT(as<void*>());
0635 case ValueType::BT_ValueRef:
0636 break;
0637 }
0638 return Vs.reduceLiteral(*this);
0639 }
0640
0641
0642
0643 class LiteralPtr : public SExpr {
0644 public:
0645 LiteralPtr(const ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {}
0646 LiteralPtr(const LiteralPtr &) = default;
0647
0648 static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; }
0649
0650
0651 const ValueDecl *clangDecl() const { return Cvdecl; }
0652 void setClangDecl(const ValueDecl *VD) { Cvdecl = VD; }
0653
0654 template <class V>
0655 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0656 return Vs.reduceLiteralPtr(*this);
0657 }
0658
0659 template <class C>
0660 typename C::CType compare(const LiteralPtr* E, C& Cmp) const {
0661 if (!Cvdecl || !E->Cvdecl)
0662 return Cmp.comparePointers(this, E);
0663 return Cmp.comparePointers(Cvdecl, E->Cvdecl);
0664 }
0665
0666 private:
0667 const ValueDecl *Cvdecl;
0668 };
0669
0670
0671
0672
0673 class Function : public SExpr {
0674 public:
0675 Function(Variable *Vd, SExpr *Bd)
0676 : SExpr(COP_Function), VarDecl(Vd), Body(Bd) {
0677 Vd->setKind(Variable::VK_Fun);
0678 }
0679
0680 Function(const Function &F, Variable *Vd, SExpr *Bd)
0681 : SExpr(F), VarDecl(Vd), Body(Bd) {
0682 Vd->setKind(Variable::VK_Fun);
0683 }
0684
0685 static bool classof(const SExpr *E) { return E->opcode() == COP_Function; }
0686
0687 Variable *variableDecl() { return VarDecl; }
0688 const Variable *variableDecl() const { return VarDecl; }
0689
0690 SExpr *body() { return Body; }
0691 const SExpr *body() const { return Body; }
0692
0693 template <class V>
0694 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0695
0696 auto E0 = Vs.traverse(VarDecl->Definition, Vs.typeCtx(Ctx));
0697
0698 Variable *Nvd = Vs.enterScope(*VarDecl, E0);
0699 auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx));
0700 Vs.exitScope(*VarDecl);
0701 return Vs.reduceFunction(*this, Nvd, E1);
0702 }
0703
0704 template <class C>
0705 typename C::CType compare(const Function* E, C& Cmp) const {
0706 typename C::CType Ct =
0707 Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
0708 if (Cmp.notTrue(Ct))
0709 return Ct;
0710 Cmp.enterScope(variableDecl(), E->variableDecl());
0711 Ct = Cmp.compare(body(), E->body());
0712 Cmp.leaveScope();
0713 return Ct;
0714 }
0715
0716 private:
0717 Variable *VarDecl;
0718 SExpr* Body;
0719 };
0720
0721
0722
0723
0724 class SFunction : public SExpr {
0725 public:
0726 SFunction(Variable *Vd, SExpr *B)
0727 : SExpr(COP_SFunction), VarDecl(Vd), Body(B) {
0728 assert(Vd->Definition == nullptr);
0729 Vd->setKind(Variable::VK_SFun);
0730 Vd->Definition = this;
0731 }
0732
0733 SFunction(const SFunction &F, Variable *Vd, SExpr *B)
0734 : SExpr(F), VarDecl(Vd), Body(B) {
0735 assert(Vd->Definition == nullptr);
0736 Vd->setKind(Variable::VK_SFun);
0737 Vd->Definition = this;
0738 }
0739
0740 static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; }
0741
0742 Variable *variableDecl() { return VarDecl; }
0743 const Variable *variableDecl() const { return VarDecl; }
0744
0745 SExpr *body() { return Body; }
0746 const SExpr *body() const { return Body; }
0747
0748 template <class V>
0749 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0750
0751
0752
0753 Variable *Nvd = Vs.enterScope(*VarDecl, nullptr);
0754 auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx));
0755 Vs.exitScope(*VarDecl);
0756
0757 return Vs.reduceSFunction(*this, Nvd, E1);
0758 }
0759
0760 template <class C>
0761 typename C::CType compare(const SFunction* E, C& Cmp) const {
0762 Cmp.enterScope(variableDecl(), E->variableDecl());
0763 typename C::CType Ct = Cmp.compare(body(), E->body());
0764 Cmp.leaveScope();
0765 return Ct;
0766 }
0767
0768 private:
0769 Variable *VarDecl;
0770 SExpr* Body;
0771 };
0772
0773
0774 class Code : public SExpr {
0775 public:
0776 Code(SExpr *T, SExpr *B) : SExpr(COP_Code), ReturnType(T), Body(B) {}
0777 Code(const Code &C, SExpr *T, SExpr *B)
0778 : SExpr(C), ReturnType(T), Body(B) {}
0779
0780 static bool classof(const SExpr *E) { return E->opcode() == COP_Code; }
0781
0782 SExpr *returnType() { return ReturnType; }
0783 const SExpr *returnType() const { return ReturnType; }
0784
0785 SExpr *body() { return Body; }
0786 const SExpr *body() const { return Body; }
0787
0788 template <class V>
0789 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0790 auto Nt = Vs.traverse(ReturnType, Vs.typeCtx(Ctx));
0791 auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx));
0792 return Vs.reduceCode(*this, Nt, Nb);
0793 }
0794
0795 template <class C>
0796 typename C::CType compare(const Code* E, C& Cmp) const {
0797 typename C::CType Ct = Cmp.compare(returnType(), E->returnType());
0798 if (Cmp.notTrue(Ct))
0799 return Ct;
0800 return Cmp.compare(body(), E->body());
0801 }
0802
0803 private:
0804 SExpr* ReturnType;
0805 SExpr* Body;
0806 };
0807
0808
0809 class Field : public SExpr {
0810 public:
0811 Field(SExpr *R, SExpr *B) : SExpr(COP_Field), Range(R), Body(B) {}
0812 Field(const Field &C, SExpr *R, SExpr *B)
0813 : SExpr(C), Range(R), Body(B) {}
0814
0815 static bool classof(const SExpr *E) { return E->opcode() == COP_Field; }
0816
0817 SExpr *range() { return Range; }
0818 const SExpr *range() const { return Range; }
0819
0820 SExpr *body() { return Body; }
0821 const SExpr *body() const { return Body; }
0822
0823 template <class V>
0824 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0825 auto Nr = Vs.traverse(Range, Vs.typeCtx(Ctx));
0826 auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx));
0827 return Vs.reduceField(*this, Nr, Nb);
0828 }
0829
0830 template <class C>
0831 typename C::CType compare(const Field* E, C& Cmp) const {
0832 typename C::CType Ct = Cmp.compare(range(), E->range());
0833 if (Cmp.notTrue(Ct))
0834 return Ct;
0835 return Cmp.compare(body(), E->body());
0836 }
0837
0838 private:
0839 SExpr* Range;
0840 SExpr* Body;
0841 };
0842
0843
0844
0845
0846
0847
0848 class Apply : public SExpr {
0849 public:
0850 Apply(SExpr *F, SExpr *A) : SExpr(COP_Apply), Fun(F), Arg(A) {}
0851 Apply(const Apply &A, SExpr *F, SExpr *Ar)
0852 : SExpr(A), Fun(F), Arg(Ar) {}
0853
0854 static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; }
0855
0856 SExpr *fun() { return Fun; }
0857 const SExpr *fun() const { return Fun; }
0858
0859 SExpr *arg() { return Arg; }
0860 const SExpr *arg() const { return Arg; }
0861
0862 template <class V>
0863 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0864 auto Nf = Vs.traverse(Fun, Vs.subExprCtx(Ctx));
0865 auto Na = Vs.traverse(Arg, Vs.subExprCtx(Ctx));
0866 return Vs.reduceApply(*this, Nf, Na);
0867 }
0868
0869 template <class C>
0870 typename C::CType compare(const Apply* E, C& Cmp) const {
0871 typename C::CType Ct = Cmp.compare(fun(), E->fun());
0872 if (Cmp.notTrue(Ct))
0873 return Ct;
0874 return Cmp.compare(arg(), E->arg());
0875 }
0876
0877 private:
0878 SExpr* Fun;
0879 SExpr* Arg;
0880 };
0881
0882
0883 class SApply : public SExpr {
0884 public:
0885 SApply(SExpr *Sf, SExpr *A = nullptr) : SExpr(COP_SApply), Sfun(Sf), Arg(A) {}
0886 SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr)
0887 : SExpr(A), Sfun(Sf), Arg(Ar) {}
0888
0889 static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; }
0890
0891 SExpr *sfun() { return Sfun; }
0892 const SExpr *sfun() const { return Sfun; }
0893
0894 SExpr *arg() { return Arg ? Arg : Sfun; }
0895 const SExpr *arg() const { return Arg ? Arg : Sfun; }
0896
0897 bool isDelegation() const { return Arg != nullptr; }
0898
0899 template <class V>
0900 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0901 auto Nf = Vs.traverse(Sfun, Vs.subExprCtx(Ctx));
0902 typename V::R_SExpr Na = Arg ? Vs.traverse(Arg, Vs.subExprCtx(Ctx))
0903 : nullptr;
0904 return Vs.reduceSApply(*this, Nf, Na);
0905 }
0906
0907 template <class C>
0908 typename C::CType compare(const SApply* E, C& Cmp) const {
0909 typename C::CType Ct = Cmp.compare(sfun(), E->sfun());
0910 if (Cmp.notTrue(Ct) || (!arg() && !E->arg()))
0911 return Ct;
0912 return Cmp.compare(arg(), E->arg());
0913 }
0914
0915 private:
0916 SExpr* Sfun;
0917 SExpr* Arg;
0918 };
0919
0920
0921 class Project : public SExpr {
0922 public:
0923 Project(SExpr *R, const ValueDecl *Cvd)
0924 : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) {
0925 assert(Cvd && "ValueDecl must not be null");
0926 }
0927
0928 static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
0929
0930 SExpr *record() { return Rec; }
0931 const SExpr *record() const { return Rec; }
0932
0933 const ValueDecl *clangDecl() const { return Cvdecl; }
0934
0935 bool isArrow() const { return (Flags & 0x01) != 0; }
0936
0937 void setArrow(bool b) {
0938 if (b) Flags |= 0x01;
0939 else Flags &= 0xFFFE;
0940 }
0941
0942 StringRef slotName() const {
0943 if (Cvdecl->getDeclName().isIdentifier())
0944 return Cvdecl->getName();
0945 if (!SlotName) {
0946 SlotName = "";
0947 llvm::raw_string_ostream OS(*SlotName);
0948 Cvdecl->printName(OS);
0949 }
0950 return *SlotName;
0951 }
0952
0953 template <class V>
0954 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0955 auto Nr = Vs.traverse(Rec, Vs.subExprCtx(Ctx));
0956 return Vs.reduceProject(*this, Nr);
0957 }
0958
0959 template <class C>
0960 typename C::CType compare(const Project* E, C& Cmp) const {
0961 typename C::CType Ct = Cmp.compare(record(), E->record());
0962 if (Cmp.notTrue(Ct))
0963 return Ct;
0964 return Cmp.comparePointers(Cvdecl, E->Cvdecl);
0965 }
0966
0967 private:
0968 SExpr* Rec;
0969 mutable std::optional<std::string> SlotName;
0970 const ValueDecl *Cvdecl;
0971 };
0972
0973
0974 class Call : public SExpr {
0975 public:
0976 Call(SExpr *T, const CallExpr *Ce = nullptr)
0977 : SExpr(COP_Call), Target(T), Cexpr(Ce) {}
0978 Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {}
0979
0980 static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
0981
0982 SExpr *target() { return Target; }
0983 const SExpr *target() const { return Target; }
0984
0985 const CallExpr *clangCallExpr() const { return Cexpr; }
0986
0987 template <class V>
0988 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
0989 auto Nt = Vs.traverse(Target, Vs.subExprCtx(Ctx));
0990 return Vs.reduceCall(*this, Nt);
0991 }
0992
0993 template <class C>
0994 typename C::CType compare(const Call* E, C& Cmp) const {
0995 return Cmp.compare(target(), E->target());
0996 }
0997
0998 private:
0999 SExpr* Target;
1000 const CallExpr *Cexpr;
1001 };
1002
1003
1004 class Alloc : public SExpr {
1005 public:
1006 enum AllocKind {
1007 AK_Stack,
1008 AK_Heap
1009 };
1010
1011 Alloc(SExpr *D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) { Flags = K; }
1012 Alloc(const Alloc &A, SExpr *Dt) : SExpr(A), Dtype(Dt) { Flags = A.kind(); }
1013
1014 static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
1015
1016 AllocKind kind() const { return static_cast<AllocKind>(Flags); }
1017
1018 SExpr *dataType() { return Dtype; }
1019 const SExpr *dataType() const { return Dtype; }
1020
1021 template <class V>
1022 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1023 auto Nd = Vs.traverse(Dtype, Vs.declCtx(Ctx));
1024 return Vs.reduceAlloc(*this, Nd);
1025 }
1026
1027 template <class C>
1028 typename C::CType compare(const Alloc* E, C& Cmp) const {
1029 typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind());
1030 if (Cmp.notTrue(Ct))
1031 return Ct;
1032 return Cmp.compare(dataType(), E->dataType());
1033 }
1034
1035 private:
1036 SExpr* Dtype;
1037 };
1038
1039
1040 class Load : public SExpr {
1041 public:
1042 Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {}
1043 Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {}
1044
1045 static bool classof(const SExpr *E) { return E->opcode() == COP_Load; }
1046
1047 SExpr *pointer() { return Ptr; }
1048 const SExpr *pointer() const { return Ptr; }
1049
1050 template <class V>
1051 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1052 auto Np = Vs.traverse(Ptr, Vs.subExprCtx(Ctx));
1053 return Vs.reduceLoad(*this, Np);
1054 }
1055
1056 template <class C>
1057 typename C::CType compare(const Load* E, C& Cmp) const {
1058 return Cmp.compare(pointer(), E->pointer());
1059 }
1060
1061 private:
1062 SExpr* Ptr;
1063 };
1064
1065
1066
1067 class Store : public SExpr {
1068 public:
1069 Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {}
1070 Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {}
1071
1072 static bool classof(const SExpr *E) { return E->opcode() == COP_Store; }
1073
1074 SExpr *destination() { return Dest; }
1075 const SExpr *destination() const { return Dest; }
1076
1077 SExpr *source() { return Source; }
1078 const SExpr *source() const { return Source; }
1079
1080 template <class V>
1081 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1082 auto Np = Vs.traverse(Dest, Vs.subExprCtx(Ctx));
1083 auto Nv = Vs.traverse(Source, Vs.subExprCtx(Ctx));
1084 return Vs.reduceStore(*this, Np, Nv);
1085 }
1086
1087 template <class C>
1088 typename C::CType compare(const Store* E, C& Cmp) const {
1089 typename C::CType Ct = Cmp.compare(destination(), E->destination());
1090 if (Cmp.notTrue(Ct))
1091 return Ct;
1092 return Cmp.compare(source(), E->source());
1093 }
1094
1095 private:
1096 SExpr* Dest;
1097 SExpr* Source;
1098 };
1099
1100
1101
1102 class ArrayIndex : public SExpr {
1103 public:
1104 ArrayIndex(SExpr *A, SExpr *N) : SExpr(COP_ArrayIndex), Array(A), Index(N) {}
1105 ArrayIndex(const ArrayIndex &E, SExpr *A, SExpr *N)
1106 : SExpr(E), Array(A), Index(N) {}
1107
1108 static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; }
1109
1110 SExpr *array() { return Array; }
1111 const SExpr *array() const { return Array; }
1112
1113 SExpr *index() { return Index; }
1114 const SExpr *index() const { return Index; }
1115
1116 template <class V>
1117 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1118 auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
1119 auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
1120 return Vs.reduceArrayIndex(*this, Na, Ni);
1121 }
1122
1123 template <class C>
1124 typename C::CType compare(const ArrayIndex* E, C& Cmp) const {
1125 typename C::CType Ct = Cmp.compare(array(), E->array());
1126 if (Cmp.notTrue(Ct))
1127 return Ct;
1128 return Cmp.compare(index(), E->index());
1129 }
1130
1131 private:
1132 SExpr* Array;
1133 SExpr* Index;
1134 };
1135
1136
1137
1138
1139 class ArrayAdd : public SExpr {
1140 public:
1141 ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {}
1142 ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N)
1143 : SExpr(E), Array(A), Index(N) {}
1144
1145 static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; }
1146
1147 SExpr *array() { return Array; }
1148 const SExpr *array() const { return Array; }
1149
1150 SExpr *index() { return Index; }
1151 const SExpr *index() const { return Index; }
1152
1153 template <class V>
1154 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1155 auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
1156 auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
1157 return Vs.reduceArrayAdd(*this, Na, Ni);
1158 }
1159
1160 template <class C>
1161 typename C::CType compare(const ArrayAdd* E, C& Cmp) const {
1162 typename C::CType Ct = Cmp.compare(array(), E->array());
1163 if (Cmp.notTrue(Ct))
1164 return Ct;
1165 return Cmp.compare(index(), E->index());
1166 }
1167
1168 private:
1169 SExpr* Array;
1170 SExpr* Index;
1171 };
1172
1173
1174
1175 class UnaryOp : public SExpr {
1176 public:
1177 UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) {
1178 Flags = Op;
1179 }
1180
1181 UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U), Expr0(E) { Flags = U.Flags; }
1182
1183 static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; }
1184
1185 TIL_UnaryOpcode unaryOpcode() const {
1186 return static_cast<TIL_UnaryOpcode>(Flags);
1187 }
1188
1189 SExpr *expr() { return Expr0; }
1190 const SExpr *expr() const { return Expr0; }
1191
1192 template <class V>
1193 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1194 auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1195 return Vs.reduceUnaryOp(*this, Ne);
1196 }
1197
1198 template <class C>
1199 typename C::CType compare(const UnaryOp* E, C& Cmp) const {
1200 typename C::CType Ct =
1201 Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode());
1202 if (Cmp.notTrue(Ct))
1203 return Ct;
1204 return Cmp.compare(expr(), E->expr());
1205 }
1206
1207 private:
1208 SExpr* Expr0;
1209 };
1210
1211
1212
1213 class BinaryOp : public SExpr {
1214 public:
1215 BinaryOp(TIL_BinaryOpcode Op, SExpr *E0, SExpr *E1)
1216 : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) {
1217 Flags = Op;
1218 }
1219
1220 BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1)
1221 : SExpr(B), Expr0(E0), Expr1(E1) {
1222 Flags = B.Flags;
1223 }
1224
1225 static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; }
1226
1227 TIL_BinaryOpcode binaryOpcode() const {
1228 return static_cast<TIL_BinaryOpcode>(Flags);
1229 }
1230
1231 SExpr *expr0() { return Expr0; }
1232 const SExpr *expr0() const { return Expr0; }
1233
1234 SExpr *expr1() { return Expr1; }
1235 const SExpr *expr1() const { return Expr1; }
1236
1237 template <class V>
1238 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1239 auto Ne0 = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1240 auto Ne1 = Vs.traverse(Expr1, Vs.subExprCtx(Ctx));
1241 return Vs.reduceBinaryOp(*this, Ne0, Ne1);
1242 }
1243
1244 template <class C>
1245 typename C::CType compare(const BinaryOp* E, C& Cmp) const {
1246 typename C::CType Ct =
1247 Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode());
1248 if (Cmp.notTrue(Ct))
1249 return Ct;
1250 Ct = Cmp.compare(expr0(), E->expr0());
1251 if (Cmp.notTrue(Ct))
1252 return Ct;
1253 return Cmp.compare(expr1(), E->expr1());
1254 }
1255
1256 private:
1257 SExpr* Expr0;
1258 SExpr* Expr1;
1259 };
1260
1261
1262
1263
1264 class Cast : public SExpr {
1265 public:
1266 Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; }
1267 Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; }
1268
1269 static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; }
1270
1271 TIL_CastOpcode castOpcode() const {
1272 return static_cast<TIL_CastOpcode>(Flags);
1273 }
1274
1275 SExpr *expr() { return Expr0; }
1276 const SExpr *expr() const { return Expr0; }
1277
1278 template <class V>
1279 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1280 auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
1281 return Vs.reduceCast(*this, Ne);
1282 }
1283
1284 template <class C>
1285 typename C::CType compare(const Cast* E, C& Cmp) const {
1286 typename C::CType Ct =
1287 Cmp.compareIntegers(castOpcode(), E->castOpcode());
1288 if (Cmp.notTrue(Ct))
1289 return Ct;
1290 return Cmp.compare(expr(), E->expr());
1291 }
1292
1293 private:
1294 SExpr* Expr0;
1295 };
1296
1297 class SCFG;
1298
1299
1300
1301
1302 class Phi : public SExpr {
1303 public:
1304 using ValArray = SimpleArray<SExpr *>;
1305
1306
1307
1308
1309 enum Status {
1310 PH_MultiVal = 0,
1311 PH_SingleVal,
1312 PH_Incomplete
1313 };
1314
1315 Phi() : SExpr(COP_Phi) {}
1316 Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
1317 Phi(const Phi &P, ValArray &&Vs) : SExpr(P), Values(std::move(Vs)) {}
1318
1319 static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
1320
1321 const ValArray &values() const { return Values; }
1322 ValArray &values() { return Values; }
1323
1324 Status status() const { return static_cast<Status>(Flags); }
1325 void setStatus(Status s) { Flags = s; }
1326
1327
1328 const ValueDecl *clangDecl() const { return Cvdecl; }
1329
1330
1331 void setClangDecl(const ValueDecl *Cvd) { Cvdecl = Cvd; }
1332
1333 template <class V>
1334 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1335 typename V::template Container<typename V::R_SExpr>
1336 Nvs(Vs, Values.size());
1337
1338 for (const auto *Val : Values)
1339 Nvs.push_back( Vs.traverse(Val, Vs.subExprCtx(Ctx)) );
1340 return Vs.reducePhi(*this, Nvs);
1341 }
1342
1343 template <class C>
1344 typename C::CType compare(const Phi *E, C &Cmp) const {
1345
1346 return Cmp.comparePointers(this, E);
1347 }
1348
1349 private:
1350 ValArray Values;
1351 const ValueDecl* Cvdecl = nullptr;
1352 };
1353
1354
1355 class Terminator : public SExpr {
1356 protected:
1357 Terminator(TIL_Opcode Op) : SExpr(Op) {}
1358 Terminator(const SExpr &E) : SExpr(E) {}
1359
1360 public:
1361 static bool classof(const SExpr *E) {
1362 return E->opcode() >= COP_Goto && E->opcode() <= COP_Return;
1363 }
1364
1365
1366 ArrayRef<BasicBlock *> successors() const;
1367 };
1368
1369
1370
1371
1372
1373
1374 class Goto : public Terminator {
1375 public:
1376 Goto(BasicBlock *B, unsigned I)
1377 : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
1378 Goto(const Goto &G, BasicBlock *B, unsigned I)
1379 : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
1380
1381 static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
1382
1383 const BasicBlock *targetBlock() const { return TargetBlock; }
1384 BasicBlock *targetBlock() { return TargetBlock; }
1385
1386
1387 unsigned index() const { return Index; }
1388
1389
1390 ArrayRef<BasicBlock *> successors() const { return TargetBlock; }
1391
1392 template <class V>
1393 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1394 BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock);
1395 return Vs.reduceGoto(*this, Ntb);
1396 }
1397
1398 template <class C>
1399 typename C::CType compare(const Goto *E, C &Cmp) const {
1400
1401 return Cmp.comparePointers(this, E);
1402 }
1403
1404 private:
1405 BasicBlock *TargetBlock;
1406 unsigned Index;
1407 };
1408
1409
1410
1411
1412 class Branch : public Terminator {
1413 public:
1414 Branch(SExpr *C, BasicBlock *T, BasicBlock *E)
1415 : Terminator(COP_Branch), Condition(C) {
1416 Branches[0] = T;
1417 Branches[1] = E;
1418 }
1419
1420 Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E)
1421 : Terminator(Br), Condition(C) {
1422 Branches[0] = T;
1423 Branches[1] = E;
1424 }
1425
1426 static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
1427
1428 const SExpr *condition() const { return Condition; }
1429 SExpr *condition() { return Condition; }
1430
1431 const BasicBlock *thenBlock() const { return Branches[0]; }
1432 BasicBlock *thenBlock() { return Branches[0]; }
1433
1434 const BasicBlock *elseBlock() const { return Branches[1]; }
1435 BasicBlock *elseBlock() { return Branches[1]; }
1436
1437
1438 ArrayRef<BasicBlock *> successors() const { return llvm::ArrayRef(Branches); }
1439
1440 template <class V>
1441 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1442 auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
1443 BasicBlock *Ntb = Vs.reduceBasicBlockRef(Branches[0]);
1444 BasicBlock *Nte = Vs.reduceBasicBlockRef(Branches[1]);
1445 return Vs.reduceBranch(*this, Nc, Ntb, Nte);
1446 }
1447
1448 template <class C>
1449 typename C::CType compare(const Branch *E, C &Cmp) const {
1450
1451 return Cmp.comparePointers(this, E);
1452 }
1453
1454 private:
1455 SExpr *Condition;
1456 BasicBlock *Branches[2];
1457 };
1458
1459
1460
1461 class Return : public Terminator {
1462 public:
1463 Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {}
1464 Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {}
1465
1466 static bool classof(const SExpr *E) { return E->opcode() == COP_Return; }
1467
1468
1469 ArrayRef<BasicBlock *> successors() const { return {}; }
1470
1471 SExpr *returnValue() { return Retval; }
1472 const SExpr *returnValue() const { return Retval; }
1473
1474 template <class V>
1475 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1476 auto Ne = Vs.traverse(Retval, Vs.subExprCtx(Ctx));
1477 return Vs.reduceReturn(*this, Ne);
1478 }
1479
1480 template <class C>
1481 typename C::CType compare(const Return *E, C &Cmp) const {
1482 return Cmp.compare(Retval, E->Retval);
1483 }
1484
1485 private:
1486 SExpr* Retval;
1487 };
1488
1489 inline ArrayRef<BasicBlock *> Terminator::successors() const {
1490 switch (opcode()) {
1491 case COP_Goto: return cast<Goto>(this)->successors();
1492 case COP_Branch: return cast<Branch>(this)->successors();
1493 case COP_Return: return cast<Return>(this)->successors();
1494 default:
1495 return {};
1496 }
1497 }
1498
1499
1500
1501
1502
1503
1504 class BasicBlock : public SExpr {
1505 public:
1506 using InstrArray = SimpleArray<SExpr *>;
1507 using BlockArray = SimpleArray<BasicBlock *>;
1508
1509
1510
1511
1512
1513 struct TopologyNode {
1514 int NodeID = 0;
1515
1516
1517 int SizeOfSubTree = 0;
1518
1519
1520 BasicBlock *Parent = nullptr;
1521
1522 TopologyNode() = default;
1523
1524 bool isParentOf(const TopologyNode& OtherNode) {
1525 return OtherNode.NodeID > NodeID &&
1526 OtherNode.NodeID < NodeID + SizeOfSubTree;
1527 }
1528
1529 bool isParentOfOrEqual(const TopologyNode& OtherNode) {
1530 return OtherNode.NodeID >= NodeID &&
1531 OtherNode.NodeID < NodeID + SizeOfSubTree;
1532 }
1533 };
1534
1535 explicit BasicBlock(MemRegionRef A)
1536 : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false) {}
1537 BasicBlock(BasicBlock &B, MemRegionRef A, InstrArray &&As, InstrArray &&Is,
1538 Terminator *T)
1539 : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false),
1540 Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {}
1541
1542 static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; }
1543
1544
1545 int blockID() const { return BlockID; }
1546
1547
1548 size_t numPredecessors() const { return Predecessors.size(); }
1549 size_t numSuccessors() const { return successors().size(); }
1550
1551 const SCFG* cfg() const { return CFGPtr; }
1552 SCFG* cfg() { return CFGPtr; }
1553
1554 const BasicBlock *parent() const { return DominatorNode.Parent; }
1555 BasicBlock *parent() { return DominatorNode.Parent; }
1556
1557 const InstrArray &arguments() const { return Args; }
1558 InstrArray &arguments() { return Args; }
1559
1560 InstrArray &instructions() { return Instrs; }
1561 const InstrArray &instructions() const { return Instrs; }
1562
1563
1564
1565
1566 BlockArray &predecessors() { return Predecessors; }
1567 const BlockArray &predecessors() const { return Predecessors; }
1568
1569 ArrayRef<BasicBlock*> successors() { return TermInstr->successors(); }
1570 ArrayRef<BasicBlock*> successors() const { return TermInstr->successors(); }
1571
1572 const Terminator *terminator() const { return TermInstr; }
1573 Terminator *terminator() { return TermInstr; }
1574
1575 void setTerminator(Terminator *E) { TermInstr = E; }
1576
1577 bool Dominates(const BasicBlock &Other) {
1578 return DominatorNode.isParentOfOrEqual(Other.DominatorNode);
1579 }
1580
1581 bool PostDominates(const BasicBlock &Other) {
1582 return PostDominatorNode.isParentOfOrEqual(Other.PostDominatorNode);
1583 }
1584
1585
1586 void addArgument(Phi *V) {
1587 Args.reserveCheck(1, Arena);
1588 Args.push_back(V);
1589 }
1590
1591
1592 void addInstruction(SExpr *V) {
1593 Instrs.reserveCheck(1, Arena);
1594 Instrs.push_back(V);
1595 }
1596
1597
1598
1599 unsigned addPredecessor(BasicBlock *Pred);
1600
1601
1602 void reserveArguments(unsigned Nargs) { Args.reserve(Nargs, Arena); }
1603
1604
1605 void reserveInstructions(unsigned Nins) { Instrs.reserve(Nins, Arena); }
1606
1607
1608 void reservePredecessors(unsigned NumPreds);
1609
1610
1611 unsigned findPredecessorIndex(const BasicBlock *BB) const {
1612 auto I = llvm::find(Predecessors, BB);
1613 return std::distance(Predecessors.cbegin(), I);
1614 }
1615
1616 template <class V>
1617 typename V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx) {
1618 typename V::template Container<SExpr*> Nas(Vs, Args.size());
1619 typename V::template Container<SExpr*> Nis(Vs, Instrs.size());
1620
1621
1622 Vs.enterBasicBlock(*this);
1623
1624 for (const auto *E : Args) {
1625 auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
1626 Nas.push_back(Ne);
1627 }
1628 for (const auto *E : Instrs) {
1629 auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
1630 Nis.push_back(Ne);
1631 }
1632 auto Nt = Vs.traverse(TermInstr, Ctx);
1633
1634
1635 Vs.exitBasicBlock(*this);
1636
1637 return Vs.reduceBasicBlock(*this, Nas, Nis, Nt);
1638 }
1639
1640 template <class C>
1641 typename C::CType compare(const BasicBlock *E, C &Cmp) const {
1642
1643 return Cmp.comparePointers(this, E);
1644 }
1645
1646 private:
1647 friend class SCFG;
1648
1649
1650 unsigned renumberInstrs(unsigned id);
1651
1652 unsigned topologicalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
1653 unsigned topologicalFinalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
1654 void computeDominator();
1655 void computePostDominator();
1656
1657
1658 MemRegionRef Arena;
1659
1660
1661 SCFG *CFGPtr = nullptr;
1662
1663
1664 unsigned BlockID : 31;
1665
1666
1667 bool Visited : 1;
1668
1669
1670 BlockArray Predecessors;
1671
1672
1673 InstrArray Args;
1674
1675
1676 InstrArray Instrs;
1677
1678
1679 Terminator *TermInstr = nullptr;
1680
1681
1682 TopologyNode DominatorNode;
1683
1684
1685 TopologyNode PostDominatorNode;
1686 };
1687
1688
1689
1690
1691 class SCFG : public SExpr {
1692 public:
1693 using BlockArray = SimpleArray<BasicBlock *>;
1694 using iterator = BlockArray::iterator;
1695 using const_iterator = BlockArray::const_iterator;
1696
1697 SCFG(MemRegionRef A, unsigned Nblocks)
1698 : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks) {
1699 Entry = new (A) BasicBlock(A);
1700 Exit = new (A) BasicBlock(A);
1701 auto *V = new (A) Phi();
1702 Exit->addArgument(V);
1703 Exit->setTerminator(new (A) Return(V));
1704 add(Entry);
1705 add(Exit);
1706 }
1707
1708 SCFG(const SCFG &Cfg, BlockArray &&Ba)
1709 : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)) {
1710
1711 }
1712
1713 static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
1714
1715
1716 bool valid() const { return Entry && Exit && Blocks.size() > 0; }
1717
1718
1719
1720
1721 bool normal() const { return Normal; }
1722
1723 iterator begin() { return Blocks.begin(); }
1724 iterator end() { return Blocks.end(); }
1725
1726 const_iterator begin() const { return cbegin(); }
1727 const_iterator end() const { return cend(); }
1728
1729 const_iterator cbegin() const { return Blocks.cbegin(); }
1730 const_iterator cend() const { return Blocks.cend(); }
1731
1732 const BasicBlock *entry() const { return Entry; }
1733 BasicBlock *entry() { return Entry; }
1734 const BasicBlock *exit() const { return Exit; }
1735 BasicBlock *exit() { return Exit; }
1736
1737
1738
1739 size_t numBlocks() const { return Blocks.size(); }
1740
1741
1742
1743
1744 unsigned numInstructions() { return NumInstructions; }
1745
1746 inline void add(BasicBlock *BB) {
1747 assert(BB->CFGPtr == nullptr);
1748 BB->CFGPtr = this;
1749 Blocks.reserveCheck(1, Arena);
1750 Blocks.push_back(BB);
1751 }
1752
1753 void setEntry(BasicBlock *BB) { Entry = BB; }
1754 void setExit(BasicBlock *BB) { Exit = BB; }
1755
1756 void computeNormalForm();
1757
1758 template <class V>
1759 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1760 Vs.enterCFG(*this);
1761 typename V::template Container<BasicBlock *> Bbs(Vs, Blocks.size());
1762
1763 for (const auto *B : Blocks) {
1764 Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) );
1765 }
1766 Vs.exitCFG(*this);
1767 return Vs.reduceSCFG(*this, Bbs);
1768 }
1769
1770 template <class C>
1771 typename C::CType compare(const SCFG *E, C &Cmp) const {
1772
1773 return Cmp.comparePointers(this, E);
1774 }
1775
1776 private:
1777
1778 void renumberInstrs();
1779
1780 MemRegionRef Arena;
1781 BlockArray Blocks;
1782 BasicBlock *Entry = nullptr;
1783 BasicBlock *Exit = nullptr;
1784 unsigned NumInstructions = 0;
1785 bool Normal = false;
1786 };
1787
1788
1789
1790 class Identifier : public SExpr {
1791 public:
1792 Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) {}
1793 Identifier(const Identifier &) = default;
1794
1795 static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; }
1796
1797 StringRef name() const { return Name; }
1798
1799 template <class V>
1800 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1801 return Vs.reduceIdentifier(*this);
1802 }
1803
1804 template <class C>
1805 typename C::CType compare(const Identifier* E, C& Cmp) const {
1806 return Cmp.compareStrings(name(), E->name());
1807 }
1808
1809 private:
1810 StringRef Name;
1811 };
1812
1813
1814
1815 class IfThenElse : public SExpr {
1816 public:
1817 IfThenElse(SExpr *C, SExpr *T, SExpr *E)
1818 : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E) {}
1819 IfThenElse(const IfThenElse &I, SExpr *C, SExpr *T, SExpr *E)
1820 : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) {}
1821
1822 static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; }
1823
1824 SExpr *condition() { return Condition; }
1825 const SExpr *condition() const { return Condition; }
1826
1827 SExpr *thenExpr() { return ThenExpr; }
1828 const SExpr *thenExpr() const { return ThenExpr; }
1829
1830 SExpr *elseExpr() { return ElseExpr; }
1831 const SExpr *elseExpr() const { return ElseExpr; }
1832
1833 template <class V>
1834 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1835 auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
1836 auto Nt = Vs.traverse(ThenExpr, Vs.subExprCtx(Ctx));
1837 auto Ne = Vs.traverse(ElseExpr, Vs.subExprCtx(Ctx));
1838 return Vs.reduceIfThenElse(*this, Nc, Nt, Ne);
1839 }
1840
1841 template <class C>
1842 typename C::CType compare(const IfThenElse* E, C& Cmp) const {
1843 typename C::CType Ct = Cmp.compare(condition(), E->condition());
1844 if (Cmp.notTrue(Ct))
1845 return Ct;
1846 Ct = Cmp.compare(thenExpr(), E->thenExpr());
1847 if (Cmp.notTrue(Ct))
1848 return Ct;
1849 return Cmp.compare(elseExpr(), E->elseExpr());
1850 }
1851
1852 private:
1853 SExpr* Condition;
1854 SExpr* ThenExpr;
1855 SExpr* ElseExpr;
1856 };
1857
1858
1859
1860 class Let : public SExpr {
1861 public:
1862 Let(Variable *Vd, SExpr *Bd) : SExpr(COP_Let), VarDecl(Vd), Body(Bd) {
1863 Vd->setKind(Variable::VK_Let);
1864 }
1865
1866 Let(const Let &L, Variable *Vd, SExpr *Bd) : SExpr(L), VarDecl(Vd), Body(Bd) {
1867 Vd->setKind(Variable::VK_Let);
1868 }
1869
1870 static bool classof(const SExpr *E) { return E->opcode() == COP_Let; }
1871
1872 Variable *variableDecl() { return VarDecl; }
1873 const Variable *variableDecl() const { return VarDecl; }
1874
1875 SExpr *body() { return Body; }
1876 const SExpr *body() const { return Body; }
1877
1878 template <class V>
1879 typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
1880
1881 auto E0 = Vs.traverse(VarDecl->Definition, Vs.subExprCtx(Ctx));
1882
1883 Variable *Nvd = Vs.enterScope(*VarDecl, E0);
1884 auto E1 = Vs.traverse(Body, Ctx);
1885 Vs.exitScope(*VarDecl);
1886 return Vs.reduceLet(*this, Nvd, E1);
1887 }
1888
1889 template <class C>
1890 typename C::CType compare(const Let* E, C& Cmp) const {
1891 typename C::CType Ct =
1892 Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
1893 if (Cmp.notTrue(Ct))
1894 return Ct;
1895 Cmp.enterScope(variableDecl(), E->variableDecl());
1896 Ct = Cmp.compare(body(), E->body());
1897 Cmp.leaveScope();
1898 return Ct;
1899 }
1900
1901 private:
1902 Variable *VarDecl;
1903 SExpr* Body;
1904 };
1905
1906 const SExpr *getCanonicalVal(const SExpr *E);
1907 SExpr* simplifyToCanonicalVal(SExpr *E);
1908 void simplifyIncompleteArg(til::Phi *Ph);
1909
1910 }
1911 }
1912
1913 }
1914
1915 #endif