//===-- ConstantsContext.h - Constants-related Context Interals -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines various helper methods and classes used by // LLVMContextImpl for creating and managing constants. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_IR_CONSTANTSCONTEXT_H #define LLVM_LIB_IR_CONSTANTSCONTEXT_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/None.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/OperandTraits.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #define DEBUG_TYPE "ir" namespace llvm { /// UnaryConstantExpr - This class is private to Constants.cpp, and is used /// behind the scenes to implement unary constant exprs. class UnaryConstantExpr : public ConstantExpr { public: UnaryConstantExpr(unsigned Opcode, Constant *C, Type *Ty) : ConstantExpr(Ty, Opcode, &Op<0>(), 1) { Op<0>() = C; } // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); } DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// BinaryConstantExpr - This class is private to Constants.cpp, and is used /// behind the scenes to implement binary constant exprs. class BinaryConstantExpr : public ConstantExpr { public: BinaryConstantExpr(unsigned Opcode, Constant *C1, Constant *C2, unsigned Flags) : ConstantExpr(C1->getType(), Opcode, &Op<0>(), 2) { Op<0>() = C1; Op<1>() = C2; SubclassOptionalData = Flags; } // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// SelectConstantExpr - This class is private to Constants.cpp, and is used /// behind the scenes to implement select constant exprs. class SelectConstantExpr : public ConstantExpr { public: SelectConstantExpr(Constant *C1, Constant *C2, Constant *C3) : ConstantExpr(C2->getType(), Instruction::Select, &Op<0>(), 3) { Op<0>() = C1; Op<1>() = C2; Op<2>() = C3; } // allocate space for exactly three operands void *operator new(size_t s) { return User::operator new(s, 3); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// ExtractElementConstantExpr - This class is private to /// Constants.cpp, and is used behind the scenes to implement /// extractelement constant exprs. class ExtractElementConstantExpr : public ConstantExpr { public: ExtractElementConstantExpr(Constant *C1, Constant *C2) : ConstantExpr(cast(C1->getType())->getElementType(), Instruction::ExtractElement, &Op<0>(), 2) { Op<0>() = C1; Op<1>() = C2; } // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// InsertElementConstantExpr - This class is private to /// Constants.cpp, and is used behind the scenes to implement /// insertelement constant exprs. class InsertElementConstantExpr : public ConstantExpr { public: InsertElementConstantExpr(Constant *C1, Constant *C2, Constant *C3) : ConstantExpr(C1->getType(), Instruction::InsertElement, &Op<0>(), 3) { Op<0>() = C1; Op<1>() = C2; Op<2>() = C3; } // allocate space for exactly three operands void *operator new(size_t s) { return User::operator new(s, 3); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// ShuffleVectorConstantExpr - This class is private to /// Constants.cpp, and is used behind the scenes to implement /// shufflevector constant exprs. class ShuffleVectorConstantExpr : public ConstantExpr { public: ShuffleVectorConstantExpr(Constant *C1, Constant *C2, Constant *C3) : ConstantExpr(VectorType::get( cast(C1->getType())->getElementType(), cast(C3->getType())->getElementCount()), Instruction::ShuffleVector, &Op<0>(), 3) { Op<0>() = C1; Op<1>() = C2; Op<2>() = C3; } // allocate space for exactly three operands void *operator new(size_t s) { return User::operator new(s, 3); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// ExtractValueConstantExpr - This class is private to /// Constants.cpp, and is used behind the scenes to implement /// extractvalue constant exprs. class ExtractValueConstantExpr : public ConstantExpr { public: ExtractValueConstantExpr(Constant *Agg, ArrayRef IdxList, Type *DestTy) : ConstantExpr(DestTy, Instruction::ExtractValue, &Op<0>(), 1), Indices(IdxList.begin(), IdxList.end()) { Op<0>() = Agg; } // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); } /// Indices - These identify which value to extract. const SmallVector Indices; /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); static bool classof(const ConstantExpr *CE) { return CE->getOpcode() == Instruction::ExtractValue; } static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; /// InsertValueConstantExpr - This class is private to /// Constants.cpp, and is used behind the scenes to implement /// insertvalue constant exprs. class InsertValueConstantExpr : public ConstantExpr { public: InsertValueConstantExpr(Constant *Agg, Constant *Val, ArrayRef IdxList, Type *DestTy) : ConstantExpr(DestTy, Instruction::InsertValue, &Op<0>(), 2), Indices(IdxList.begin(), IdxList.end()) { Op<0>() = Agg; Op<1>() = Val; } // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 2); } /// Indices - These identify the position for the insertion. const SmallVector Indices; /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); static bool classof(const ConstantExpr *CE) { return CE->getOpcode() == Instruction::InsertValue; } static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; /// GetElementPtrConstantExpr - This class is private to Constants.cpp, and is /// used behind the scenes to implement getelementpr constant exprs. class GetElementPtrConstantExpr : public ConstantExpr { Type *SrcElementTy; Type *ResElementTy; GetElementPtrConstantExpr(Type *SrcElementTy, Constant *C, ArrayRef IdxList, Type *DestTy); public: static GetElementPtrConstantExpr *Create(Type *SrcElementTy, Constant *C, ArrayRef IdxList, Type *DestTy, unsigned Flags) { GetElementPtrConstantExpr *Result = new (IdxList.size() + 1) GetElementPtrConstantExpr(SrcElementTy, C, IdxList, DestTy); Result->SubclassOptionalData = Flags; return Result; } Type *getSourceElementType() const; Type *getResultElementType() const; /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); static bool classof(const ConstantExpr *CE) { return CE->getOpcode() == Instruction::GetElementPtr; } static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; // CompareConstantExpr - This class is private to Constants.cpp, and is used // behind the scenes to implement ICmp and FCmp constant expressions. This is // needed in order to store the predicate value for these instructions. class CompareConstantExpr : public ConstantExpr { public: unsigned short predicate; CompareConstantExpr(Type *ty, Instruction::OtherOps opc, unsigned short pred, Constant* LHS, Constant* RHS) : ConstantExpr(ty, opc, &Op<0>(), 2), predicate(pred) { Op<0>() = LHS; Op<1>() = RHS; } // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); static bool classof(const ConstantExpr *CE) { return CE->getOpcode() == Instruction::ICmp || CE->getOpcode() == Instruction::FCmp; } static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(UnaryConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SelectConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ExtractElementConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ShuffleVectorConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ExtractValueConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertValueConstantExpr, Value) template <> struct OperandTraits : public VariadicOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrConstantExpr, Value) template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CompareConstantExpr, Value) template struct ConstantAggrKeyType; struct InlineAsmKeyType; struct ConstantExprKeyType; template struct ConstantInfo; template <> struct ConstantInfo { using ValType = ConstantExprKeyType; using TypeClass = Type; }; template <> struct ConstantInfo { using ValType = InlineAsmKeyType; using TypeClass = PointerType; }; template <> struct ConstantInfo { using ValType = ConstantAggrKeyType; using TypeClass = ArrayType; }; template <> struct ConstantInfo { using ValType = ConstantAggrKeyType; using TypeClass = StructType; }; template <> struct ConstantInfo { using ValType = ConstantAggrKeyType; using TypeClass = VectorType; }; template struct ConstantAggrKeyType { ArrayRef Operands; ConstantAggrKeyType(ArrayRef Operands) : Operands(Operands) {} ConstantAggrKeyType(ArrayRef Operands, const ConstantClass *) : Operands(Operands) {} ConstantAggrKeyType(const ConstantClass *C, SmallVectorImpl &Storage) { assert(Storage.empty() && "Expected empty storage"); for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) Storage.push_back(C->getOperand(I)); Operands = Storage; } bool operator==(const ConstantAggrKeyType &X) const { return Operands == X.Operands; } bool operator==(const ConstantClass *C) const { if (Operands.size() != C->getNumOperands()) return false; for (unsigned I = 0, E = Operands.size(); I != E; ++I) if (Operands[I] != C->getOperand(I)) return false; return true; } unsigned getHash() const { return hash_combine_range(Operands.begin(), Operands.end()); } using TypeClass = typename ConstantInfo::TypeClass; ConstantClass *create(TypeClass *Ty) const { return new (Operands.size()) ConstantClass(Ty, Operands); } }; struct InlineAsmKeyType { StringRef AsmString; StringRef Constraints; FunctionType *FTy; bool HasSideEffects; bool IsAlignStack; InlineAsm::AsmDialect AsmDialect; InlineAsmKeyType(StringRef AsmString, StringRef Constraints, FunctionType *FTy, bool HasSideEffects, bool IsAlignStack, InlineAsm::AsmDialect AsmDialect) : AsmString(AsmString), Constraints(Constraints), FTy(FTy), HasSideEffects(HasSideEffects), IsAlignStack(IsAlignStack), AsmDialect(AsmDialect) {} InlineAsmKeyType(const InlineAsm *Asm, SmallVectorImpl &) : AsmString(Asm->getAsmString()), Constraints(Asm->getConstraintString()), FTy(Asm->getFunctionType()), HasSideEffects(Asm->hasSideEffects()), IsAlignStack(Asm->isAlignStack()), AsmDialect(Asm->getDialect()) {} bool operator==(const InlineAsmKeyType &X) const { return HasSideEffects == X.HasSideEffects && IsAlignStack == X.IsAlignStack && AsmDialect == X.AsmDialect && AsmString == X.AsmString && Constraints == X.Constraints && FTy == X.FTy; } bool operator==(const InlineAsm *Asm) const { return HasSideEffects == Asm->hasSideEffects() && IsAlignStack == Asm->isAlignStack() && AsmDialect == Asm->getDialect() && AsmString == Asm->getAsmString() && Constraints == Asm->getConstraintString() && FTy == Asm->getFunctionType(); } unsigned getHash() const { return hash_combine(AsmString, Constraints, HasSideEffects, IsAlignStack, AsmDialect, FTy); } using TypeClass = ConstantInfo::TypeClass; InlineAsm *create(TypeClass *Ty) const { assert(PointerType::getUnqual(FTy) == Ty); return new InlineAsm(FTy, AsmString, Constraints, HasSideEffects, IsAlignStack, AsmDialect); } }; struct ConstantExprKeyType { uint8_t Opcode; uint8_t SubclassOptionalData; uint16_t SubclassData; ArrayRef Ops; ArrayRef Indexes; Type *ExplicitTy; ConstantExprKeyType(unsigned Opcode, ArrayRef Ops, unsigned short SubclassData = 0, unsigned short SubclassOptionalData = 0, ArrayRef Indexes = None, Type *ExplicitTy = nullptr) : Opcode(Opcode), SubclassOptionalData(SubclassOptionalData), SubclassData(SubclassData), Ops(Ops), Indexes(Indexes), ExplicitTy(ExplicitTy) {} ConstantExprKeyType(ArrayRef Operands, const ConstantExpr *CE) : Opcode(CE->getOpcode()), SubclassOptionalData(CE->getRawSubclassOptionalData()), SubclassData(CE->isCompare() ? CE->getPredicate() : 0), Ops(Operands), Indexes(CE->hasIndices() ? CE->getIndices() : ArrayRef()), ExplicitTy(nullptr) {} ConstantExprKeyType(const ConstantExpr *CE, SmallVectorImpl &Storage) : Opcode(CE->getOpcode()), SubclassOptionalData(CE->getRawSubclassOptionalData()), SubclassData(CE->isCompare() ? CE->getPredicate() : 0), Indexes(CE->hasIndices() ? CE->getIndices() : ArrayRef()), ExplicitTy(nullptr) { assert(Storage.empty() && "Expected empty storage"); for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I) Storage.push_back(CE->getOperand(I)); Ops = Storage; } bool operator==(const ConstantExprKeyType &X) const { return Opcode == X.Opcode && SubclassData == X.SubclassData && SubclassOptionalData == X.SubclassOptionalData && Ops == X.Ops && Indexes == X.Indexes; } bool operator==(const ConstantExpr *CE) const { if (Opcode != CE->getOpcode()) return false; if (SubclassOptionalData != CE->getRawSubclassOptionalData()) return false; if (Ops.size() != CE->getNumOperands()) return false; if (SubclassData != (CE->isCompare() ? CE->getPredicate() : 0)) return false; for (unsigned I = 0, E = Ops.size(); I != E; ++I) if (Ops[I] != CE->getOperand(I)) return false; if (Indexes != (CE->hasIndices() ? CE->getIndices() : ArrayRef())) return false; return true; } unsigned getHash() const { return hash_combine(Opcode, SubclassOptionalData, SubclassData, hash_combine_range(Ops.begin(), Ops.end()), hash_combine_range(Indexes.begin(), Indexes.end())); } using TypeClass = ConstantInfo::TypeClass; ConstantExpr *create(TypeClass *Ty) const { switch (Opcode) { default: if (Instruction::isCast(Opcode) || (Opcode >= Instruction::UnaryOpsBegin && Opcode < Instruction::UnaryOpsEnd)) return new UnaryConstantExpr(Opcode, Ops[0], Ty); if ((Opcode >= Instruction::BinaryOpsBegin && Opcode < Instruction::BinaryOpsEnd)) return new BinaryConstantExpr(Opcode, Ops[0], Ops[1], SubclassOptionalData); llvm_unreachable("Invalid ConstantExpr!"); case Instruction::Select: return new SelectConstantExpr(Ops[0], Ops[1], Ops[2]); case Instruction::ExtractElement: return new ExtractElementConstantExpr(Ops[0], Ops[1]); case Instruction::InsertElement: return new InsertElementConstantExpr(Ops[0], Ops[1], Ops[2]); case Instruction::ShuffleVector: return new ShuffleVectorConstantExpr(Ops[0], Ops[1], Ops[2]); case Instruction::InsertValue: return new InsertValueConstantExpr(Ops[0], Ops[1], Indexes, Ty); case Instruction::ExtractValue: return new ExtractValueConstantExpr(Ops[0], Indexes, Ty); case Instruction::GetElementPtr: return GetElementPtrConstantExpr::Create( ExplicitTy ? ExplicitTy : cast(Ops[0]->getType()->getScalarType()) ->getElementType(), Ops[0], Ops.slice(1), Ty, SubclassOptionalData); case Instruction::ICmp: return new CompareConstantExpr(Ty, Instruction::ICmp, SubclassData, Ops[0], Ops[1]); case Instruction::FCmp: return new CompareConstantExpr(Ty, Instruction::FCmp, SubclassData, Ops[0], Ops[1]); } } }; template class ConstantUniqueMap { public: using ValType = typename ConstantInfo::ValType; using TypeClass = typename ConstantInfo::TypeClass; using LookupKey = std::pair; /// Key and hash together, so that we compute the hash only once and reuse it. using LookupKeyHashed = std::pair; private: struct MapInfo { using ConstantClassInfo = DenseMapInfo; static inline ConstantClass *getEmptyKey() { return ConstantClassInfo::getEmptyKey(); } static inline ConstantClass *getTombstoneKey() { return ConstantClassInfo::getTombstoneKey(); } static unsigned getHashValue(const ConstantClass *CP) { SmallVector Storage; return getHashValue(LookupKey(CP->getType(), ValType(CP, Storage))); } static bool isEqual(const ConstantClass *LHS, const ConstantClass *RHS) { return LHS == RHS; } static unsigned getHashValue(const LookupKey &Val) { return hash_combine(Val.first, Val.second.getHash()); } static unsigned getHashValue(const LookupKeyHashed &Val) { return Val.first; } static bool isEqual(const LookupKey &LHS, const ConstantClass *RHS) { if (RHS == getEmptyKey() || RHS == getTombstoneKey()) return false; if (LHS.first != RHS->getType()) return false; return LHS.second == RHS; } static bool isEqual(const LookupKeyHashed &LHS, const ConstantClass *RHS) { return isEqual(LHS.second, RHS); } }; public: using MapTy = DenseSet; private: MapTy Map; public: typename MapTy::iterator begin() { return Map.begin(); } typename MapTy::iterator end() { return Map.end(); } void freeConstants() { for (auto &I : Map) delete I; // Asserts that use_empty(). } private: ConstantClass *create(TypeClass *Ty, ValType V, LookupKeyHashed &HashKey) { ConstantClass *Result = V.create(Ty); assert(Result->getType() == Ty && "Type specified is not correct!"); Map.insert_as(Result, HashKey); return Result; } public: /// Return the specified constant from the map, creating it if necessary. ConstantClass *getOrCreate(TypeClass *Ty, ValType V) { LookupKey Key(Ty, V); /// Hash once, and reuse it for the lookup and the insertion if needed. LookupKeyHashed Lookup(MapInfo::getHashValue(Key), Key); ConstantClass *Result = nullptr; auto I = Map.find_as(Lookup); if (I == Map.end()) Result = create(Ty, V, Lookup); else Result = *I; assert(Result && "Unexpected nullptr"); return Result; } /// Remove this constant from the map void remove(ConstantClass *CP) { typename MapTy::iterator I = Map.find(CP); assert(I != Map.end() && "Constant not found in constant table!"); assert(*I == CP && "Didn't find correct element?"); Map.erase(I); } ConstantClass *replaceOperandsInPlace(ArrayRef Operands, ConstantClass *CP, Value *From, Constant *To, unsigned NumUpdated = 0, unsigned OperandNo = ~0u) { LookupKey Key(CP->getType(), ValType(Operands, CP)); /// Hash once, and reuse it for the lookup and the insertion if needed. LookupKeyHashed Lookup(MapInfo::getHashValue(Key), Key); auto ItMap = Map.find_as(Lookup); if (ItMap != Map.end()) return *ItMap; // Update to the new value. Optimize for the case when we have a single // operand that we're changing, but handle bulk updates efficiently. remove(CP); if (NumUpdated == 1) { assert(OperandNo < CP->getNumOperands() && "Invalid index"); assert(CP->getOperand(OperandNo) != To && "I didn't contain From!"); CP->setOperand(OperandNo, To); } else { for (unsigned I = 0, E = CP->getNumOperands(); I != E; ++I) if (CP->getOperand(I) == From) CP->setOperand(I, To); } Map.insert_as(CP, Lookup); return nullptr; } void dump() const { LLVM_DEBUG(dbgs() << "Constant.cpp: ConstantUniqueMap\n"); } }; } // end namespace llvm #endif // LLVM_LIB_IR_CONSTANTSCONTEXT_H