From f1d1f4c4591e81cfa80034df094b26d7eb4fa92b Mon Sep 17 00:00:00 2001 From: Eugene Zelenko Date: Fri, 16 Mar 2018 00:37:51 +0000 Subject: [PATCH] [Analysis] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@327687 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../clang/Analysis/Analyses/ThreadSafetyTIL.h | 543 +++++++++--------- .../Analysis/Analyses/ThreadSafetyUtil.h | 105 ++-- lib/Analysis/ThreadSafetyTIL.cpp | 38 +- 3 files changed, 341 insertions(+), 345 deletions(-) diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index 0a58d2a802..810f2052b7 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -1,4 +1,4 @@ -//===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===// +//===- ThreadSafetyTIL.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -47,20 +47,33 @@ #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H -// All clang include dependencies for this file must be put in -// ThreadSafetyUtil.h. -#include "ThreadSafetyUtil.h" +#include "clang/AST/Decl.h" +#include "clang/Analysis/Analyses/ThreadSafetyUtil.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" #include #include #include -#include +#include +#include +#include #include - namespace clang { + +class CallExpr; +class Expr; +class Stmt; + namespace threadSafety { namespace til { +class BasicBlock; /// Enum for the different distinct classes of SExpr enum TIL_Opcode { @@ -100,11 +113,21 @@ enum TIL_BinaryOpcode : unsigned char { /// Opcode for cast operations. enum TIL_CastOpcode : unsigned char { CAST_none = 0, - CAST_extendNum, // extend precision of numeric type - CAST_truncNum, // truncate precision of numeric type - CAST_toFloat, // convert to floating point type - CAST_toInt, // convert to integer type - CAST_objToPtr // convert smart pointer to pointer (C++ only) + + // Extend precision of numeric type + CAST_extendNum, + + // Truncate precision of numeric type + CAST_truncNum, + + // Convert to floating point type + CAST_toFloat, + + // Convert to integer type + CAST_toInt, + + // Convert smart pointer to pointer (C++ only) + CAST_objToPtr }; const TIL_Opcode COP_Min = COP_Future; @@ -122,7 +145,6 @@ StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op); /// Return the name of a binary opcode. StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op); - /// ValueTypes are data types that can actually be held in registers. /// All variables and expressions must have a value type. /// Pointer types are further subdivided into the various heap-allocated @@ -150,22 +172,22 @@ struct ValueType { ST_128 }; + ValueType(BaseType B, SizeType Sz, bool S, unsigned char VS) + : Base(B), Size(Sz), Signed(S), VectSize(VS) {} + inline static SizeType getSizeType(unsigned nbytes); template inline static ValueType getValueType(); - ValueType(BaseType B, SizeType Sz, bool S, unsigned char VS) - : Base(B), Size(Sz), Signed(S), VectSize(VS) - { } + BaseType Base; + SizeType Size; + bool Signed; - BaseType Base; - SizeType Size; - bool Signed; - unsigned char VectSize; // 0 for scalar, otherwise num elements in vector + // 0 for scalar, otherwise num elements in vector + unsigned char VectSize; }; - inline ValueType::SizeType ValueType::getSizeType(unsigned nbytes) { switch (nbytes) { case 1: return ST_8; @@ -177,7 +199,6 @@ inline ValueType::SizeType ValueType::getSizeType(unsigned nbytes) { } } - template<> inline ValueType ValueType::getValueType() { return ValueType(BT_Void, ST_0, false, 0); @@ -253,13 +274,11 @@ inline ValueType ValueType::getValueType() { return ValueType(BT_Pointer, getSizeType(sizeof(void*)), false, 0); } - -class BasicBlock; - - /// Base class for AST nodes in the typed intermediate language. class SExpr { public: + SExpr() = delete; + TIL_Opcode opcode() const { return static_cast(Opcode); } // Subclasses of SExpr must define the following: @@ -280,6 +299,9 @@ public: return ::operator new(S, R); } + /// SExpr objects must be created in an arena. + void *operator new(size_t) = delete; + /// SExpr objects cannot be deleted. // This declaration is public to workaround a gcc bug that breaks building // with REQUIRES_EH=1. @@ -291,45 +313,33 @@ public: /// Returns the block, if this is an instruction in a basic block, /// otherwise returns null. - BasicBlock* block() const { return Block; } + BasicBlock *block() const { return Block; } /// Set the basic block and instruction ID for this expression. void setID(BasicBlock *B, unsigned id) { Block = B; SExprID = id; } protected: - SExpr(TIL_Opcode Op) - : Opcode(Op), Reserved(0), Flags(0), SExprID(0), Block(nullptr) {} - SExpr(const SExpr &E) - : Opcode(E.Opcode), Reserved(0), Flags(E.Flags), SExprID(0), - Block(nullptr) {} + SExpr(TIL_Opcode Op) : Opcode(Op) {} + SExpr(const SExpr &E) : Opcode(E.Opcode), Flags(E.Flags) {} const unsigned char Opcode; - unsigned char Reserved; - unsigned short Flags; - unsigned SExprID; - BasicBlock* Block; - -private: - SExpr() = delete; - - /// SExpr objects must be created in an arena. - void *operator new(size_t) = delete; + unsigned char Reserved = 0; + unsigned short Flags = 0; + unsigned SExprID = 0; + BasicBlock *Block = nullptr; }; - // Contains various helper functions for SExprs. namespace ThreadSafetyTIL { - inline bool isTrivial(const SExpr *E) { - unsigned Op = E->opcode(); - return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr; - } + +inline bool isTrivial(const SExpr *E) { + unsigned Op = E->opcode(); + return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr; } -// Nodes which declare variables -class Function; -class SFunction; -class Let; +} // namespace ThreadSafetyTIL +// Nodes which declare variables /// A named variable, e.g. "x". /// @@ -345,28 +355,35 @@ class Let; /// pointer to the original declaration. class Variable : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; } - enum VariableKind { - VK_Let, ///< Let-variable - VK_Fun, ///< Function parameter - VK_SFun ///< SFunction (self) parameter + /// Let-variable + VK_Let, + + /// Function parameter + VK_Fun, + + /// SFunction (self) parameter + VK_SFun }; Variable(StringRef s, SExpr *D = nullptr) - : SExpr(COP_Variable), Name(s), Definition(D), Cvdecl(nullptr) { + : SExpr(COP_Variable), Name(s), Definition(D) { Flags = VK_Let; } - Variable(SExpr *D, const clang::ValueDecl *Cvd = nullptr) + + Variable(SExpr *D, const ValueDecl *Cvd = nullptr) : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"), Definition(D), Cvdecl(Cvd) { Flags = VK_Let; } + Variable(const Variable &Vd, SExpr *D) // rewrite constructor : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl) { Flags = Vd.kind(); } + static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; } + /// Return the kind of variable (let, function param, or self) VariableKind kind() const { return static_cast(Flags); } @@ -374,7 +391,7 @@ public: StringRef name() const { return Name; } /// Return the clang declaration for this variable, if any. - const clang::ValueDecl *clangDecl() const { return Cvdecl; } + const ValueDecl *clangDecl() const { return Cvdecl; } /// Return the definition of the variable. /// For let-vars, this is the setting expression. @@ -385,7 +402,7 @@ public: void setName(StringRef S) { Name = S; } void setKind(VariableKind K) { Flags = K; } void setDefinition(SExpr *E) { Definition = E; } - void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; } + void setClangDecl(const ValueDecl *VD) { Cvdecl = VD; } template typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -399,42 +416,41 @@ public: } private: - friend class Function; - friend class SFunction; friend class BasicBlock; + friend class Function; friend class Let; + friend class SFunction; - StringRef Name; // The name of the variable. - SExpr* Definition; // The TIL type or definition - const clang::ValueDecl *Cvdecl; // The clang declaration for this variable. -}; + // The name of the variable. + StringRef Name; + + // The TIL type or definition. + SExpr *Definition; + // The clang declaration for this variable. + const ValueDecl *Cvdecl = nullptr; +}; /// Placeholder for an expression that has not yet been created. /// Used to implement lazy copy and rewriting strategies. class Future : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Future; } - enum FutureStatus { FS_pending, FS_evaluating, FS_done }; - Future() : SExpr(COP_Future), Status(FS_pending), Result(nullptr) {} - -private: + Future() : SExpr(COP_Future) {} virtual ~Future() = delete; -public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Future; } + // A lazy rewriting strategy should subclass Future and override this method. virtual SExpr *compute() { return nullptr; } // Return the result of this future if it exists, otherwise return null. - SExpr *maybeGetResult() const { - return Result; - } + SExpr *maybeGetResult() const { return Result; } // Return the result of this future; forcing it if necessary. SExpr *result() { @@ -464,19 +480,18 @@ public: private: SExpr* force(); - FutureStatus Status; - SExpr *Result; + FutureStatus Status = FS_pending; + SExpr *Result = nullptr; }; - /// Placeholder for expressions that cannot be represented in the TIL. class Undefined : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; } - - Undefined(const clang::Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {} + Undefined(const Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {} Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; } + template typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { return Vs.reduceUndefined(*this); @@ -488,17 +503,16 @@ public: } private: - const clang::Stmt *Cstmt; + const Stmt *Cstmt; }; - /// Placeholder for a wildcard that matches any other expression. class Wildcard : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; } - Wildcard() : SExpr(COP_Wildcard) {} - Wildcard(const Wildcard &W) : SExpr(W) {} + Wildcard(const Wildcard &) = default; + + static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; } template typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { return Vs.reduceWildcard(*this); @@ -510,22 +524,20 @@ public: } }; - template class LiteralT; // Base class for literal values. class Literal : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; } + Literal(const Expr *C) + : SExpr(COP_Literal), ValType(ValueType::getValueType()), Cexpr(C) {} + Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT) {} + Literal(const Literal &) = default; - Literal(const clang::Expr *C) - : SExpr(COP_Literal), ValType(ValueType::getValueType()), Cexpr(C) - { } - Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT), Cexpr(nullptr) {} - Literal(const Literal &L) : SExpr(L), ValType(L.ValType), Cexpr(L.Cexpr) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; } // The clang expression for this literal. - const clang::Expr *clangExpr() const { return Cexpr; } + const Expr *clangExpr() const { return Cexpr; } ValueType valueType() const { return ValType; } @@ -546,26 +558,23 @@ public: private: const ValueType ValType; - const clang::Expr *Cexpr; + const Expr *Cexpr = nullptr; }; - // Derived class for literal values, which stores the actual value. template class LiteralT : public Literal { public: - LiteralT(T Dat) : Literal(ValueType::getValueType()), Val(Dat) { } - LiteralT(const LiteralT &L) : Literal(L), Val(L.Val) { } + LiteralT(T Dat) : Literal(ValueType::getValueType()), Val(Dat) {} + LiteralT(const LiteralT &L) : Literal(L), Val(L.Val) {} - T value() const { return Val;} + T value() const { return Val;} T& value() { return Val; } private: T Val; }; - - template typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) { if (Cexpr) @@ -622,18 +631,17 @@ typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) { return Vs.reduceLiteral(*this); } - /// A Literal pointer to an object allocated in memory. /// At compile time, pointer literals are represented by symbolic names. class LiteralPtr : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; } + LiteralPtr(const ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {} + LiteralPtr(const LiteralPtr &) = default; - LiteralPtr(const clang::ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {} - LiteralPtr(const LiteralPtr &R) : SExpr(R), Cvdecl(R.Cvdecl) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; } // The clang declaration for the value that this pointer points to. - const clang::ValueDecl *clangDecl() const { return Cvdecl; } + const ValueDecl *clangDecl() const { return Cvdecl; } template typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -646,26 +654,26 @@ public: } private: - const clang::ValueDecl *Cvdecl; + const ValueDecl *Cvdecl; }; - /// A function -- a.k.a. lambda abstraction. /// Functions with multiple arguments are created by currying, /// e.g. (Function (x: Int) (Function (y: Int) (Code { return x + y }))) class Function : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Function; } - Function(Variable *Vd, SExpr *Bd) : SExpr(COP_Function), VarDecl(Vd), Body(Bd) { Vd->setKind(Variable::VK_Fun); } + Function(const Function &F, Variable *Vd, SExpr *Bd) // rewrite constructor : SExpr(F), VarDecl(Vd), Body(Bd) { Vd->setKind(Variable::VK_Fun); } + static bool classof(const SExpr *E) { return E->opcode() == COP_Function; } + Variable *variableDecl() { return VarDecl; } const Variable *variableDecl() const { return VarDecl; } @@ -700,20 +708,18 @@ private: SExpr* Body; }; - /// A self-applicable function. /// A self-applicable function can be applied to itself. It's useful for /// implementing objects and late binding. class SFunction : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; } - SFunction(Variable *Vd, SExpr *B) : SExpr(COP_SFunction), VarDecl(Vd), Body(B) { assert(Vd->Definition == nullptr); Vd->setKind(Variable::VK_SFun); Vd->Definition = this; } + SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor : SExpr(F), VarDecl(Vd), Body(B) { assert(Vd->Definition == nullptr); @@ -721,6 +727,8 @@ public: Vd->Definition = this; } + static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; } + Variable *variableDecl() { return VarDecl; } const Variable *variableDecl() const { return VarDecl; } @@ -752,16 +760,15 @@ private: SExpr* Body; }; - /// A block of code -- e.g. the body of a function. class Code : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Code; } - Code(SExpr *T, SExpr *B) : SExpr(COP_Code), ReturnType(T), Body(B) {} Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor : SExpr(C), ReturnType(T), Body(B) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Code; } + SExpr *returnType() { return ReturnType; } const SExpr *returnType() const { return ReturnType; } @@ -788,16 +795,15 @@ private: SExpr* Body; }; - /// A typed, writable location in memory class Field : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Field; } - Field(SExpr *R, SExpr *B) : SExpr(COP_Field), Range(R), Body(B) {} Field(const Field &C, SExpr *R, SExpr *B) // rewrite constructor : SExpr(C), Range(R), Body(B) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Field; } + SExpr *range() { return Range; } const SExpr *range() const { return Range; } @@ -824,7 +830,6 @@ private: SExpr* Body; }; - /// Apply an argument to a function. /// Note that this does not actually call the function. Functions are curried, /// so this returns a closure in which the first parameter has been applied. @@ -832,12 +837,11 @@ private: /// function. class Apply : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; } - Apply(SExpr *F, SExpr *A) : SExpr(COP_Apply), Fun(F), Arg(A) {} Apply(const Apply &A, SExpr *F, SExpr *Ar) // rewrite constructor - : SExpr(A), Fun(F), Arg(Ar) - {} + : SExpr(A), Fun(F), Arg(Ar) {} + + static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; } SExpr *fun() { return Fun; } const SExpr *fun() const { return Fun; } @@ -865,16 +869,15 @@ private: SExpr* Arg; }; - /// Apply a self-argument to a self-applicable function. class SApply : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; } - SApply(SExpr *Sf, SExpr *A = nullptr) : SExpr(COP_SApply), Sfun(Sf), Arg(A) {} SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr) // rewrite constructor : SExpr(A), Sfun(Sf), Arg(Ar) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; } + SExpr *sfun() { return Sfun; } const SExpr *sfun() const { return Sfun; } @@ -904,23 +907,23 @@ private: SExpr* Arg; }; - /// Project a named slot from a C++ struct or class. class Project : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Project; } - - Project(SExpr *R, const clang::ValueDecl *Cvd) + Project(SExpr *R, const ValueDecl *Cvd) : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) { assert(Cvd && "ValueDecl must not be null"); } + static bool classof(const SExpr *E) { return E->opcode() == COP_Project; } + SExpr *record() { return Rec; } const SExpr *record() const { return Rec; } - const clang::ValueDecl *clangDecl() const { return Cvdecl; } + const ValueDecl *clangDecl() const { return Cvdecl; } bool isArrow() const { return (Flags & 0x01) != 0; } + void setArrow(bool b) { if (b) Flags |= 0x01; else Flags &= 0xFFFE; @@ -954,23 +957,22 @@ public: private: SExpr* Rec; mutable llvm::Optional SlotName; - const clang::ValueDecl *Cvdecl; + const ValueDecl *Cvdecl; }; - /// Call a function (after all arguments have been applied). class Call : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } - - Call(SExpr *T, const clang::CallExpr *Ce = nullptr) + Call(SExpr *T, const CallExpr *Ce = nullptr) : SExpr(COP_Call), Target(T), Cexpr(Ce) {} Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } + SExpr *target() { return Target; } const SExpr *target() const { return Target; } - const clang::CallExpr *clangCallExpr() const { return Cexpr; } + const CallExpr *clangCallExpr() const { return Cexpr; } template typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -985,15 +987,12 @@ public: private: SExpr* Target; - const clang::CallExpr *Cexpr; + const CallExpr *Cexpr; }; - /// Allocate memory for a new value on the heap or stack. class Alloc : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } - enum AllocKind { AK_Stack, AK_Heap @@ -1002,6 +1001,8 @@ public: Alloc(SExpr *D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) { Flags = K; } Alloc(const Alloc &A, SExpr *Dt) : SExpr(A), Dtype(Dt) { Flags = A.kind(); } + static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } + AllocKind kind() const { return static_cast(Flags); } SExpr *dataType() { return Dtype; } @@ -1025,15 +1026,14 @@ private: SExpr* Dtype; }; - /// Load a value from memory. class Load : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Load; } - Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {} Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Load; } + SExpr *pointer() { return Ptr; } const SExpr *pointer() const { return Ptr; } @@ -1052,16 +1052,15 @@ private: SExpr* Ptr; }; - /// Store a value to memory. /// The destination is a pointer to a field, the source is the value to store. class Store : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Store; } - Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {} Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Store; } + SExpr *destination() { return Dest; } // Address to store to const SExpr *destination() const { return Dest; } @@ -1088,16 +1087,15 @@ private: SExpr* Source; }; - /// If p is a reference to an array, then p[i] is a reference to the i'th /// element of the array. class ArrayIndex : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; } - ArrayIndex(SExpr *A, SExpr *N) : SExpr(COP_ArrayIndex), Array(A), Index(N) {} ArrayIndex(const ArrayIndex &E, SExpr *A, SExpr *N) - : SExpr(E), Array(A), Index(N) {} + : SExpr(E), Array(A), Index(N) {} + + static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; } SExpr *array() { return Array; } const SExpr *array() const { return Array; } @@ -1125,17 +1123,16 @@ private: SExpr* Index; }; - /// Pointer arithmetic, restricted to arrays only. /// If p is a reference to an array, then p + n, where n is an integer, is /// a reference to a subarray. class ArrayAdd : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; } - ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {} ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N) - : SExpr(E), Array(A), Index(N) {} + : SExpr(E), Array(A), Index(N) {} + + static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; } SExpr *array() { return Array; } const SExpr *array() const { return Array; } @@ -1163,18 +1160,18 @@ private: SExpr* Index; }; - /// Simple arithmetic unary operations, e.g. negate and not. /// These operations have no side-effects. class UnaryOp : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; } - UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) { Flags = Op; } + UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U), Expr0(E) { Flags = U.Flags; } + static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; } + TIL_UnaryOpcode unaryOpcode() const { return static_cast(Flags); } @@ -1201,22 +1198,22 @@ private: SExpr* Expr0; }; - /// Simple arithmetic binary operations, e.g. +, -, etc. /// These operations have no side effects. class BinaryOp : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; } - BinaryOp(TIL_BinaryOpcode Op, SExpr *E0, SExpr *E1) : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) { Flags = Op; } + BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1) : SExpr(B), Expr0(E0), Expr1(E1) { Flags = B.Flags; } + static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; } + TIL_BinaryOpcode binaryOpcode() const { return static_cast(Flags); } @@ -1251,17 +1248,16 @@ private: SExpr* Expr1; }; - /// Cast expressions. /// Cast expressions are essentially unary operations, but we treat them /// as a distinct AST node because they only change the type of the result. class Cast : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; } - Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; } Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; } + static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; } + TIL_CastOpcode castOpcode() const { return static_cast(Flags); } @@ -1288,16 +1284,14 @@ private: SExpr* Expr0; }; - class SCFG; - /// Phi Node, for code in SSA form. /// Each Phi node has an array of possible values that it can take, /// depending on where control flow comes from. class Phi : public SExpr { public: - typedef SimpleArray ValArray; + using ValArray = SimpleArray; // In minimal SSA form, all Phi nodes are MultiVal. // During conversion to SSA, incomplete Phi nodes may be introduced, which @@ -1308,14 +1302,11 @@ public: PH_Incomplete // Phi node is incomplete }; - static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; } + Phi() : SExpr(COP_Phi) {} + Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {} + Phi(const Phi &P, ValArray &&Vs) : SExpr(P), Values(std::move(Vs)) {} - Phi() - : SExpr(COP_Phi), Cvdecl(nullptr) {} - Phi(MemRegionRef A, unsigned Nvals) - : SExpr(COP_Phi), Values(A, Nvals), Cvdecl(nullptr) {} - Phi(const Phi &P, ValArray &&Vs) - : SExpr(P), Values(std::move(Vs)), Cvdecl(nullptr) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; } const ValArray &values() const { return Values; } ValArray &values() { return Values; } @@ -1324,19 +1315,18 @@ public: void setStatus(Status s) { Flags = s; } /// Return the clang declaration of the variable for this Phi node, if any. - const clang::ValueDecl *clangDecl() const { return Cvdecl; } + const ValueDecl *clangDecl() const { return Cvdecl; } /// Set the clang variable associated with this Phi node. - void setClangDecl(const clang::ValueDecl *Cvd) { Cvdecl = Cvd; } + void setClangDecl(const ValueDecl *Cvd) { Cvdecl = Cvd; } template typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { typename V::template Container Nvs(Vs, Values.size()); - for (auto *Val : Values) { + for (const auto *Val : Values) Nvs.push_back( Vs.traverse(Val, Vs.subExprCtx(Ctx)) ); - } return Vs.reducePhi(*this, Nvs); } @@ -1348,31 +1338,28 @@ public: private: ValArray Values; - const clang::ValueDecl* Cvdecl; + const ValueDecl* Cvdecl = nullptr; }; - /// Base class for basic block terminators: Branch, Goto, and Return. class Terminator : public SExpr { +protected: + Terminator(TIL_Opcode Op) : SExpr(Op) {} + Terminator(const SExpr &E) : SExpr(E) {} + public: static bool classof(const SExpr *E) { return E->opcode() >= COP_Goto && E->opcode() <= COP_Return; } -protected: - Terminator(TIL_Opcode Op) : SExpr(Op) {} - Terminator(const SExpr &E) : SExpr(E) {} - -public: /// Return the list of basic blocks that this terminator can branch to. - ArrayRef successors(); + ArrayRef successors(); - ArrayRef successors() const { + ArrayRef successors() const { return const_cast(this)->successors(); } }; - /// Jump to another basic block. /// A goto instruction is essentially a tail-recursive call into another /// block. In addition to the block pointer, it specifies an index into the @@ -1380,13 +1367,13 @@ public: /// of the call. class Goto : public Terminator { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; } - Goto(BasicBlock *B, unsigned I) : Terminator(COP_Goto), TargetBlock(B), Index(I) {} Goto(const Goto &G, BasicBlock *B, unsigned I) : Terminator(COP_Goto), TargetBlock(B), Index(I) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; } + const BasicBlock *targetBlock() const { return TargetBlock; } BasicBlock *targetBlock() { return TargetBlock; } @@ -1394,9 +1381,7 @@ public: unsigned index() const { return Index; } /// Return the list of basic blocks that this terminator can branch to. - ArrayRef successors() { - return TargetBlock; - } + ArrayRef successors() { return TargetBlock; } template typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1415,25 +1400,25 @@ private: unsigned Index; }; - /// A conditional branch to two other blocks. /// Note that unlike Goto, Branch does not have an index. The target blocks /// must be child-blocks, and cannot have Phi nodes. class Branch : public Terminator { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; } - Branch(SExpr *C, BasicBlock *T, BasicBlock *E) : Terminator(COP_Branch), Condition(C) { Branches[0] = T; Branches[1] = E; } + Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E) : Terminator(Br), Condition(C) { Branches[0] = T; Branches[1] = E; } + static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; } + const SExpr *condition() const { return Condition; } SExpr *condition() { return Condition; } @@ -1463,24 +1448,21 @@ public: } private: - SExpr* Condition; + SExpr *Condition; BasicBlock *Branches[2]; }; - /// Return from the enclosing function, passing the return value to the caller. /// Only the exit block should end with a return statement. class Return : public Terminator { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Return; } - Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {} Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_Return; } + /// Return an empty list. - ArrayRef successors() { - return None; - } + ArrayRef successors() { return None; } SExpr *returnValue() { return Retval; } const SExpr *returnValue() const { return Retval; } @@ -1500,7 +1482,6 @@ private: SExpr* Retval; }; - inline ArrayRef Terminator::successors() { switch (opcode()) { case COP_Goto: return cast(this)->successors(); @@ -1511,7 +1492,6 @@ inline ArrayRef Terminator::successors() { } } - /// A basic block is part of an SCFG. It can be treated as a function in /// continuation passing style. A block consists of a sequence of phi nodes, /// which are "arguments" to the function, followed by a sequence of @@ -1519,15 +1499,23 @@ inline ArrayRef Terminator::successors() { /// another basic block in the same SCFG. class BasicBlock : public SExpr { public: - typedef SimpleArray InstrArray; - typedef SimpleArray BlockArray; + using InstrArray = SimpleArray; + using BlockArray = SimpleArray; // TopologyNodes are used to overlay tree structures on top of the CFG, // such as dominator and postdominator trees. Each block is assigned an // ID in the tree according to a depth-first search. Tree traversals are // always up, towards the parents. struct TopologyNode { - TopologyNode() : NodeID(0), SizeOfSubTree(0), Parent(nullptr) {} + int NodeID = 0; + + // Includes this node, so must be > 1. + int SizeOfSubTree = 0; + + // Pointer to parent. + BasicBlock *Parent = nullptr; + + TopologyNode() = default; bool isParentOf(const TopologyNode& OtherNode) { return OtherNode.NodeID > NodeID && @@ -1538,22 +1526,17 @@ public: return OtherNode.NodeID >= NodeID && OtherNode.NodeID < NodeID + SizeOfSubTree; } - - int NodeID; - int SizeOfSubTree; // Includes this node, so must be > 1. - BasicBlock *Parent; // Pointer to parent. }; - static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; } - explicit BasicBlock(MemRegionRef A) - : SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0), - Visited(0), TermInstr(nullptr) {} + : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false) {} BasicBlock(BasicBlock &B, MemRegionRef A, InstrArray &&As, InstrArray &&Is, Terminator *T) - : SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0),Visited(0), + : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false), Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {} + static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; } + /// Returns the block ID. Every block has a unique ID in the CFG. int blockID() const { return BlockID; } @@ -1600,11 +1583,13 @@ public: Args.reserveCheck(1, Arena); Args.push_back(V); } + /// Add a new instruction. void addInstruction(SExpr *V) { Instrs.reserveCheck(1, Arena); Instrs.push_back(V); } + // Add a new predecessor, and return the phi-node index for it. // Will add an argument to all phi-nodes, initialized to nullptr. unsigned addPredecessor(BasicBlock *Pred); @@ -1632,11 +1617,11 @@ public: // Entering the basic block should do any scope initialization. Vs.enterBasicBlock(*this); - for (auto *E : Args) { + for (const auto *E : Args) { auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx)); Nas.push_back(Ne); } - for (auto *E : Instrs) { + for (const auto *E : Instrs) { auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx)); Nis.push_back(Ne); } @@ -1657,43 +1642,56 @@ public: private: friend class SCFG; - int renumberInstrs(int id); // assign unique ids to all instructions - int topologicalSort(SimpleArray& Blocks, int ID); - int topologicalFinalSort(SimpleArray& Blocks, int ID); + // assign unique ids to all instructions + int renumberInstrs(int id); + + int topologicalSort(SimpleArray &Blocks, int ID); + int topologicalFinalSort(SimpleArray &Blocks, int ID); void computeDominator(); void computePostDominator(); -private: - MemRegionRef Arena; // The arena used to allocate this block. - SCFG *CFGPtr; // The CFG that contains this block. - int BlockID : 31; // unique id for this BB in the containing CFG. - // IDs are in topological order. - bool Visited : 1; // Bit to determine if a block has been visited - // during a traversal. - BlockArray Predecessors; // Predecessor blocks in the CFG. - InstrArray Args; // Phi nodes. One argument per predecessor. - InstrArray Instrs; // Instructions. - Terminator* TermInstr; // Terminating instruction - - TopologyNode DominatorNode; // The dominator tree - TopologyNode PostDominatorNode; // The post-dominator tree -}; + // The arena used to allocate this block. + MemRegionRef Arena; + + // The CFG that contains this block. + SCFG *CFGPtr = nullptr; + + // Unique ID for this BB in the containing CFG. IDs are in topological order. + int BlockID : 31; + // Bit to determine if a block has been visited during a traversal. + bool Visited : 1; + + // Predecessor blocks in the CFG. + BlockArray Predecessors; + + // Phi nodes. One argument per predecessor. + InstrArray Args; + + // Instructions. + InstrArray Instrs; + + // Terminating instruction. + Terminator *TermInstr = nullptr; + + // The dominator tree. + TopologyNode DominatorNode; + + // The post-dominator tree. + TopologyNode PostDominatorNode; +}; /// An SCFG is a control-flow graph. It consists of a set of basic blocks, /// each of which terminates in a branch to another basic block. There is one /// entry point, and one exit point. class SCFG : public SExpr { public: - typedef SimpleArray BlockArray; - typedef BlockArray::iterator iterator; - typedef BlockArray::const_iterator const_iterator; - - static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; } + using BlockArray = SimpleArray; + using iterator = BlockArray::iterator; + using const_iterator = BlockArray::const_iterator; SCFG(MemRegionRef A, unsigned Nblocks) - : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks), - Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) { + : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks) { Entry = new (A) BasicBlock(A); Exit = new (A) BasicBlock(A); auto *V = new (A) Phi(); @@ -1702,12 +1700,14 @@ public: add(Entry); add(Exit); } + SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba - : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)), - Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) { + : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)) { // TODO: set entry and exit! } + static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; } + /// Return true if this CFG is valid. bool valid() const { return Entry && Exit && Blocks.size() > 0; } @@ -1756,7 +1756,7 @@ public: Vs.enterCFG(*this); typename V::template Container Bbs(Vs, Blocks.size()); - for (auto *B : Blocks) { + for (const auto *B : Blocks) { Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) ); } Vs.exitCFG(*this); @@ -1770,27 +1770,25 @@ public: } private: - void renumberInstrs(); // assign unique ids to all instructions + // assign unique ids to all instructions + void renumberInstrs(); -private: MemRegionRef Arena; - BlockArray Blocks; - BasicBlock *Entry; - BasicBlock *Exit; - unsigned NumInstructions; - bool Normal; + BlockArray Blocks; + BasicBlock *Entry = nullptr; + BasicBlock *Exit = nullptr; + unsigned NumInstructions = 0; + bool Normal = false; }; - - /// An identifier, e.g. 'foo' or 'x'. /// This is a pseduo-term; it will be lowered to a variable or projection. class Identifier : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; } + Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) {} + Identifier(const Identifier &) = default; - Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) { } - Identifier(const Identifier& I) : SExpr(I), Name(I.Name) { } + static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; } StringRef name() const { return Name; } @@ -1808,19 +1806,16 @@ private: StringRef Name; }; - /// An if-then-else expression. /// This is a pseduo-term; it will be lowered to a branch in a CFG. class IfThenElse : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; } - IfThenElse(SExpr *C, SExpr *T, SExpr *E) - : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E) - { } + : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E) {} IfThenElse(const IfThenElse &I, SExpr *C, SExpr *T, SExpr *E) - : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) - { } + : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) {} + + static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; } SExpr *condition() { return Condition; } // Address to store to const SExpr *condition() const { return Condition; } @@ -1856,20 +1851,20 @@ private: SExpr* ElseExpr; }; - /// A let-expression, e.g. let x=t; u. /// This is a pseduo-term; it will be lowered to instructions in a CFG. class Let : public SExpr { public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Let; } - Let(Variable *Vd, SExpr *Bd) : SExpr(COP_Let), VarDecl(Vd), Body(Bd) { Vd->setKind(Variable::VK_Let); } + Let(const Let &L, Variable *Vd, SExpr *Bd) : SExpr(L), VarDecl(Vd), Body(Bd) { Vd->setKind(Variable::VK_Let); } + static bool classof(const SExpr *E) { return E->opcode() == COP_Let; } + Variable *variableDecl() { return VarDecl; } const Variable *variableDecl() const { return VarDecl; } @@ -1904,15 +1899,13 @@ private: SExpr* Body; }; - - const SExpr *getCanonicalVal(const SExpr *E); SExpr* simplifyToCanonicalVal(SExpr *E); void simplifyIncompleteArg(til::Phi *Ph); +} // namespace til +} // namespace threadSafety -} // end namespace til -} // end namespace threadSafety -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H diff --git a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h index cb80ce5da8..a94b4b18a8 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h @@ -1,4 +1,4 @@ -//===- ThreadSafetyUtil.h --------------------------------------*- C++ --*-===// +//===- ThreadSafetyUtil.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,18 +14,23 @@ #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H -#include "clang/AST/ExprCXX.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/AlignOf.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/Compiler.h" #include #include +#include +#include #include -#include +#include #include namespace clang { + +class Expr; + namespace threadSafety { namespace til { @@ -41,7 +46,7 @@ private: }; public: - MemRegionRef() : Allocator(nullptr) {} + MemRegionRef() = default; MemRegionRef(llvm::BumpPtrAllocator *A) : Allocator(A) {} void *allocate(size_t Sz) { @@ -55,12 +60,13 @@ public: } private: - llvm::BumpPtrAllocator *Allocator; + llvm::BumpPtrAllocator *Allocator = nullptr; }; -} // end namespace til -} // end namespace threadSafety -} // end namespace clang +} // namespace til +} // namespace threadSafety + +} // namespace clang inline void *operator new(size_t Sz, clang::threadSafety::til::MemRegionRef &R) { @@ -70,10 +76,7 @@ inline void *operator new(size_t Sz, namespace clang { namespace threadSafety { -std::string getSourceLiteralString(const clang::Expr *CE); - -using llvm::StringRef; -using clang::SourceLocation; +std::string getSourceLiteralString(const Expr *CE); namespace til { @@ -81,11 +84,13 @@ namespace til { // suitable for use with bump pointer allocation. template class SimpleArray { public: - SimpleArray() : Data(nullptr), Size(0), Capacity(0) {} + SimpleArray() = default; SimpleArray(T *Dat, size_t Cp, size_t Sz = 0) : Data(Dat), Size(Sz), Capacity(Cp) {} SimpleArray(MemRegionRef A, size_t Cp) : Data(Cp == 0 ? nullptr : A.allocateT(Cp)), Size(0), Capacity(Cp) {} + SimpleArray(const SimpleArray &A) = delete; + SimpleArray(SimpleArray &&A) : Data(A.Data), Size(A.Size), Capacity(A.Capacity) { A.Data = nullptr; @@ -123,10 +128,10 @@ public: reserve(u_max(Size + N, Capacity * 2), A); } - typedef T *iterator; - typedef const T *const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; + using iterator = T *; + using const_iterator = const T *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; size_t size() const { return Size; } size_t capacity() const { return Capacity; } @@ -135,27 +140,30 @@ public: assert(i < Size && "Array index out of bounds."); return Data[i]; } + const T &operator[](unsigned i) const { assert(i < Size && "Array index out of bounds."); return Data[i]; } + T &back() { assert(Size && "No elements in the array."); return Data[Size - 1]; } + const T &back() const { assert(Size && "No elements in the array."); return Data[Size - 1]; } iterator begin() { return Data; } - iterator end() { return Data + Size; } + iterator end() { return Data + Size; } const_iterator begin() const { return Data; } - const_iterator end() const { return Data + Size; } + const_iterator end() const { return Data + Size; } const_iterator cbegin() const { return Data; } - const_iterator cend() const { return Data + Size; } + const_iterator cend() const { return Data + Size; } reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } @@ -163,6 +171,7 @@ public: const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } @@ -198,6 +207,7 @@ public: llvm::iterator_range reverse() { return llvm::make_range(rbegin(), rend()); } + llvm::iterator_range reverse() const { return llvm::make_range(rbegin(), rend()); } @@ -209,14 +219,12 @@ private: static const size_t InitialCapacity = 4; - SimpleArray(const SimpleArray &A) = delete; - - T *Data; - size_t Size; - size_t Capacity; + T *Data = nullptr; + size_t Size = 0; + size_t Capacity = 0; }; -} // end namespace til +} // namespace til // A copy on write vector. // The vector can be in one of three states: @@ -228,20 +236,28 @@ template class CopyOnWriteVector { class VectorData { public: - VectorData() : NumRefs(1) { } - VectorData(const VectorData &VD) : NumRefs(1), Vect(VD.Vect) { } - - unsigned NumRefs; + unsigned NumRefs = 1; std::vector Vect; - }; - // No copy constructor or copy assignment. Use clone() with move assignment. - CopyOnWriteVector(const CopyOnWriteVector &V) = delete; - void operator=(const CopyOnWriteVector &V) = delete; + VectorData() = default; + VectorData(const VectorData &VD) : Vect(VD.Vect) {} + }; public: - CopyOnWriteVector() : Data(nullptr) {} + CopyOnWriteVector() = default; CopyOnWriteVector(CopyOnWriteVector &&V) : Data(V.Data) { V.Data = nullptr; } + + CopyOnWriteVector &operator=(CopyOnWriteVector &&V) { + destroy(); + Data = V.Data; + V.Data = nullptr; + return *this; + } + + // No copy constructor or copy assignment. Use clone() with move assignment. + CopyOnWriteVector(const CopyOnWriteVector &) = delete; + CopyOnWriteVector &operator=(const CopyOnWriteVector &) = delete; + ~CopyOnWriteVector() { destroy(); } // Returns true if this holds a valid vector. @@ -283,14 +299,7 @@ public: // Create a lazy copy of this vector. CopyOnWriteVector clone() { return CopyOnWriteVector(Data); } - CopyOnWriteVector &operator=(CopyOnWriteVector &&V) { - destroy(); - Data = V.Data; - V.Data = nullptr; - return *this; - } - - typedef typename std::vector::const_iterator const_iterator; + using const_iterator = typename std::vector::const_iterator; const std::vector &elements() const { return Data->Vect; } @@ -336,14 +345,14 @@ private: ++Data->NumRefs; } - VectorData *Data; + VectorData *Data = nullptr; }; inline std::ostream& operator<<(std::ostream& ss, const StringRef str) { return ss.write(str.data(), str.size()); } -} // end namespace threadSafety -} // end namespace clang +} // namespace threadSafety +} // namespace clang #endif // LLVM_CLANG_THREAD_SAFETY_UTIL_H diff --git a/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp index cd7cdc69ab..798bbfb29d 100644 --- a/lib/Analysis/ThreadSafetyTIL.cpp +++ b/lib/Analysis/ThreadSafetyTIL.cpp @@ -1,4 +1,4 @@ -//===- ThreadSafetyTIL.cpp -------------------------------------*- C++ --*-===// +//===- ThreadSafetyTIL.cpp ------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,11 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" -#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Casting.h" +#include +#include + using namespace clang; using namespace threadSafety; using namespace til; @@ -19,7 +23,7 @@ StringRef til::getUnaryOpcodeString(TIL_UnaryOpcode Op) { case UOP_BitNot: return "~"; case UOP_LogicNot: return "!"; } - return ""; + return {}; } StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) { @@ -42,10 +46,9 @@ StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) { case BOP_LogicAnd: return "&&"; case BOP_LogicOr: return "||"; } - return ""; + return {}; } - SExpr* Future::force() { Status = FS_evaluating; Result = compute(); @@ -53,13 +56,12 @@ SExpr* Future::force() { return Result; } - unsigned BasicBlock::addPredecessor(BasicBlock *Pred) { unsigned Idx = Predecessors.size(); Predecessors.reserveCheck(1, Arena); Predecessors.push_back(Pred); - for (SExpr *E : Args) { - if (Phi* Ph = dyn_cast(E)) { + for (auto *E : Args) { + if (auto *Ph = dyn_cast(E)) { Ph->values().reserveCheck(1, Arena); Ph->values().push_back(nullptr); } @@ -67,28 +69,26 @@ unsigned BasicBlock::addPredecessor(BasicBlock *Pred) { return Idx; } - void BasicBlock::reservePredecessors(unsigned NumPreds) { Predecessors.reserve(NumPreds, Arena); - for (SExpr *E : Args) { - if (Phi* Ph = dyn_cast(E)) { + for (auto *E : Args) { + if (auto *Ph = dyn_cast(E)) { Ph->values().reserve(NumPreds, Arena); } } } - // If E is a variable, then trace back through any aliases or redundant // Phi nodes to find the canonical definition. const SExpr *til::getCanonicalVal(const SExpr *E) { while (true) { - if (auto *V = dyn_cast(E)) { + if (const auto *V = dyn_cast(E)) { if (V->kind() == Variable::VK_Let) { E = V->definition(); continue; } } - if (const Phi *Ph = dyn_cast(E)) { + if (const auto *Ph = dyn_cast(E)) { if (Ph->status() == Phi::PH_SingleVal) { E = Ph->values()[0]; continue; @@ -99,7 +99,6 @@ const SExpr *til::getCanonicalVal(const SExpr *E) { return E; } - // If E is a variable, then trace back through any aliases or redundant // Phi nodes to find the canonical definition. // The non-const version will simplify incomplete Phi nodes. @@ -129,7 +128,6 @@ SExpr *til::simplifyToCanonicalVal(SExpr *E) { } } - // Trace the arguments of an incomplete Phi node to see if they have the same // canonical definition. If so, mark the Phi node as redundant. // getCanonicalVal() will recursively call simplifyIncompletePhi(). @@ -140,7 +138,7 @@ void til::simplifyIncompleteArg(til::Phi *Ph) { Ph->setStatus(Phi::PH_MultiVal); SExpr *E0 = simplifyToCanonicalVal(Ph->values()[0]); - for (unsigned i=1, n=Ph->values().size(); ivalues().size(); i < n; ++i) { SExpr *Ei = simplifyToCanonicalVal(Ph->values()[i]); if (Ei == Ph) continue; // Recursive reference to itself. Don't count. @@ -151,7 +149,6 @@ void til::simplifyIncompleteArg(til::Phi *Ph) { Ph->setStatus(Phi::PH_SingleVal); } - // Renumbers the arguments and instructions to have unique, sequential IDs. int BasicBlock::renumberInstrs(int ID) { for (auto *Arg : Args) @@ -166,7 +163,7 @@ int BasicBlock::renumberInstrs(int ID) { // Each block will be written into the Blocks array in order, and its BlockID // will be set to the index in the array. Sorting should start from the entry // block, and ID should be the total number of blocks. -int BasicBlock::topologicalSort(SimpleArray& Blocks, int ID) { +int BasicBlock::topologicalSort(SimpleArray &Blocks, int ID) { if (Visited) return ID; Visited = true; for (auto *Block : successors()) @@ -258,7 +255,6 @@ void BasicBlock::computePostDominator() { PostDominatorNode.SizeOfSubTree = 1; } - // Renumber instructions in all blocks void SCFG::renumberInstrs() { int InstrID = 0; @@ -266,7 +262,6 @@ void SCFG::renumberInstrs() { InstrID = Block->renumberInstrs(InstrID); } - static inline void computeNodeSize(BasicBlock *B, BasicBlock::TopologyNode BasicBlock::*TN) { BasicBlock::TopologyNode *N = &(B->*TN); @@ -287,7 +282,6 @@ static inline void computeNodeID(BasicBlock *B, } } - // Normalizes a CFG. Normalization has a few major components: // 1) Removing unreachable blocks. // 2) Computing dominators and post-dominators -- 2.40.0