//===-- llvm/Operator.h - Operator utility subclass -------------*- 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 classes for working with Instructions and // ConstantExprs. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_OPERATOR_H #define LLVM_IR_OPERATOR_H #include "llvm/ADT/MapVector.h" #include "llvm/IR/Constants.h" #include "llvm/IR/FMF.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include #include namespace llvm { /// This is a utility class that provides an abstraction for the common /// functionality between Instructions and ConstantExprs. class Operator : public User { public: // The Operator class is intended to be used as a utility, and is never itself // instantiated. Operator() = delete; ~Operator() = delete; void *operator new(size_t s) = delete; /// Return the opcode for this Instruction or ConstantExpr. unsigned getOpcode() const { if (const Instruction *I = dyn_cast(this)) return I->getOpcode(); return cast(this)->getOpcode(); } /// If V is an Instruction or ConstantExpr, return its opcode. /// Otherwise return UserOp1. static unsigned getOpcode(const Value *V) { if (const Instruction *I = dyn_cast(V)) return I->getOpcode(); if (const ConstantExpr *CE = dyn_cast(V)) return CE->getOpcode(); return Instruction::UserOp1; } static bool classof(const Instruction *) { return true; } static bool classof(const ConstantExpr *) { return true; } static bool classof(const Value *V) { return isa(V) || isa(V); } /// Return true if this operator has flags which may cause this operator /// to evaluate to poison despite having non-poison inputs. bool hasPoisonGeneratingFlags() const; /// Return true if this operator has poison-generating flags or metadata. /// The latter is only possible for instructions. bool hasPoisonGeneratingFlagsOrMetadata() const; }; /// Utility class for integer operators which may exhibit overflow - Add, Sub, /// Mul, and Shl. It does not include SDiv, despite that operator having the /// potential for overflow. class OverflowingBinaryOperator : public Operator { public: enum { AnyWrap = 0, NoUnsignedWrap = (1 << 0), NoSignedWrap = (1 << 1) }; private: friend class Instruction; friend class ConstantExpr; void setHasNoUnsignedWrap(bool B) { SubclassOptionalData = (SubclassOptionalData & ~NoUnsignedWrap) | (B * NoUnsignedWrap); } void setHasNoSignedWrap(bool B) { SubclassOptionalData = (SubclassOptionalData & ~NoSignedWrap) | (B * NoSignedWrap); } public: /// Test whether this operation is known to never /// undergo unsigned overflow, aka the nuw property. bool hasNoUnsignedWrap() const { return SubclassOptionalData & NoUnsignedWrap; } /// Test whether this operation is known to never /// undergo signed overflow, aka the nsw property. bool hasNoSignedWrap() const { return (SubclassOptionalData & NoSignedWrap) != 0; } static bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Add || I->getOpcode() == Instruction::Sub || I->getOpcode() == Instruction::Mul || I->getOpcode() == Instruction::Shl; } static bool classof(const ConstantExpr *CE) { return CE->getOpcode() == Instruction::Add || CE->getOpcode() == Instruction::Sub || CE->getOpcode() == Instruction::Mul || CE->getOpcode() == Instruction::Shl; } static bool classof(const Value *V) { return (isa(V) && classof(cast(V))) || (isa(V) && classof(cast(V))); } }; /// A udiv or sdiv instruction, which can be marked as "exact", /// indicating that no bits are destroyed. class PossiblyExactOperator : public Operator { public: enum { IsExact = (1 << 0) }; private: friend class Instruction; friend class ConstantExpr; void setIsExact(bool B) { SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact); } public: /// Test whether this division is known to be exact, with zero remainder. bool isExact() const { return SubclassOptionalData & IsExact; } static bool isPossiblyExactOpcode(unsigned OpC) { return OpC == Instruction::SDiv || OpC == Instruction::UDiv || OpC == Instruction::AShr || OpC == Instruction::LShr; } static bool classof(const ConstantExpr *CE) { return isPossiblyExactOpcode(CE->getOpcode()); } static bool classof(const Instruction *I) { return isPossiblyExactOpcode(I->getOpcode()); } static bool classof(const Value *V) { return (isa(V) && classof(cast(V))) || (isa(V) && classof(cast(V))); } }; /// Utility class for floating point operations which can have /// information about relaxed accuracy requirements attached to them. class FPMathOperator : public Operator { private: friend class Instruction; /// 'Fast' means all bits are set. void setFast(bool B) { setHasAllowReassoc(B); setHasNoNaNs(B); setHasNoInfs(B); setHasNoSignedZeros(B); setHasAllowReciprocal(B); setHasAllowContract(B); setHasApproxFunc(B); } void setHasAllowReassoc(bool B) { SubclassOptionalData = (SubclassOptionalData & ~FastMathFlags::AllowReassoc) | (B * FastMathFlags::AllowReassoc); } void setHasNoNaNs(bool B) { SubclassOptionalData = (SubclassOptionalData & ~FastMathFlags::NoNaNs) | (B * FastMathFlags::NoNaNs); } void setHasNoInfs(bool B) { SubclassOptionalData = (SubclassOptionalData & ~FastMathFlags::NoInfs) | (B * FastMathFlags::NoInfs); } void setHasNoSignedZeros(bool B) { SubclassOptionalData = (SubclassOptionalData & ~FastMathFlags::NoSignedZeros) | (B * FastMathFlags::NoSignedZeros); } void setHasAllowReciprocal(bool B) { SubclassOptionalData = (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) | (B * FastMathFlags::AllowReciprocal); } void setHasAllowContract(bool B) { SubclassOptionalData = (SubclassOptionalData & ~FastMathFlags::AllowContract) | (B * FastMathFlags::AllowContract); } void setHasApproxFunc(bool B) { SubclassOptionalData = (SubclassOptionalData & ~FastMathFlags::ApproxFunc) | (B * FastMathFlags::ApproxFunc); } /// Convenience function for setting multiple fast-math flags. /// FMF is a mask of the bits to set. void setFastMathFlags(FastMathFlags FMF) { SubclassOptionalData |= FMF.Flags; } /// Convenience function for copying all fast-math flags. /// All values in FMF are transferred to this operator. void copyFastMathFlags(FastMathFlags FMF) { SubclassOptionalData = FMF.Flags; } public: /// Test if this operation allows all non-strict floating-point transforms. bool isFast() const { return ((SubclassOptionalData & FastMathFlags::AllowReassoc) != 0 && (SubclassOptionalData & FastMathFlags::NoNaNs) != 0 && (SubclassOptionalData & FastMathFlags::NoInfs) != 0 && (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0 && (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0 && (SubclassOptionalData & FastMathFlags::AllowContract) != 0 && (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0); } /// Test if this operation may be simplified with reassociative transforms. bool hasAllowReassoc() const { return (SubclassOptionalData & FastMathFlags::AllowReassoc) != 0; } /// Test if this operation's arguments and results are assumed not-NaN. bool hasNoNaNs() const { return (SubclassOptionalData & FastMathFlags::NoNaNs) != 0; } /// Test if this operation's arguments and results are assumed not-infinite. bool hasNoInfs() const { return (SubclassOptionalData & FastMathFlags::NoInfs) != 0; } /// Test if this operation can ignore the sign of zero. bool hasNoSignedZeros() const { return (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0; } /// Test if this operation can use reciprocal multiply instead of division. bool hasAllowReciprocal() const { return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0; } /// Test if this operation can be floating-point contracted (FMA). bool hasAllowContract() const { return (SubclassOptionalData & FastMathFlags::AllowContract) != 0; } /// Test if this operation allows approximations of math library functions or /// intrinsics. bool hasApproxFunc() const { return (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0; } /// Convenience function for getting all the fast-math flags FastMathFlags getFastMathFlags() const { return FastMathFlags(SubclassOptionalData); } /// Get the maximum error permitted by this operation in ULPs. An accuracy of /// 0.0 means that the operation should be performed with the default /// precision. float getFPAccuracy() const; static bool classof(const Value *V) { unsigned Opcode; if (auto *I = dyn_cast(V)) Opcode = I->getOpcode(); else if (auto *CE = dyn_cast(V)) Opcode = CE->getOpcode(); else return false; switch (Opcode) { case Instruction::FNeg: case Instruction::FAdd: case Instruction::FSub: case Instruction::FMul: case Instruction::FDiv: case Instruction::FRem: // FIXME: To clean up and correct the semantics of fast-math-flags, FCmp // should not be treated as a math op, but the other opcodes should. // This would make things consistent with Select/PHI (FP value type // determines whether they are math ops and, therefore, capable of // having fast-math-flags). case Instruction::FCmp: return true; case Instruction::PHI: case Instruction::Select: case Instruction::Call: { Type *Ty = V->getType(); while (ArrayType *ArrTy = dyn_cast(Ty)) Ty = ArrTy->getElementType(); return Ty->isFPOrFPVectorTy(); } default: return false; } } }; /// A helper template for defining operators for individual opcodes. template class ConcreteOperator : public SuperClass { public: static bool classof(const Instruction *I) { return I->getOpcode() == Opc; } static bool classof(const ConstantExpr *CE) { return CE->getOpcode() == Opc; } static bool classof(const Value *V) { return (isa(V) && classof(cast(V))) || (isa(V) && classof(cast(V))); } }; class AddOperator : public ConcreteOperator { }; class SubOperator : public ConcreteOperator { }; class MulOperator : public ConcreteOperator { }; class ShlOperator : public ConcreteOperator { }; class SDivOperator : public ConcreteOperator { }; class UDivOperator : public ConcreteOperator { }; class AShrOperator : public ConcreteOperator { }; class LShrOperator : public ConcreteOperator { }; class ZExtOperator : public ConcreteOperator {}; class GEPOperator : public ConcreteOperator { friend class GetElementPtrInst; friend class ConstantExpr; enum { IsInBounds = (1 << 0), // InRangeIndex: bits 1-6 }; void setIsInBounds(bool B) { SubclassOptionalData = (SubclassOptionalData & ~IsInBounds) | (B * IsInBounds); } public: /// Test whether this is an inbounds GEP, as defined by LangRef.html. bool isInBounds() const { return SubclassOptionalData & IsInBounds; } /// Returns the offset of the index with an inrange attachment, or /// std::nullopt if none. std::optional getInRangeIndex() const { if (SubclassOptionalData >> 1 == 0) return std::nullopt; return (SubclassOptionalData >> 1) - 1; } inline op_iterator idx_begin() { return op_begin()+1; } inline const_op_iterator idx_begin() const { return op_begin()+1; } inline op_iterator idx_end() { return op_end(); } inline const_op_iterator idx_end() const { return op_end(); } inline iterator_range indices() { return make_range(idx_begin(), idx_end()); } inline iterator_range indices() const { return make_range(idx_begin(), idx_end()); } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; // get index for modifying correct operand } /// Method to return the pointer operand as a PointerType. Type *getPointerOperandType() const { return getPointerOperand()->getType(); } Type *getSourceElementType() const; Type *getResultElementType() const; /// Method to return the address space of the pointer operand. unsigned getPointerAddressSpace() const { return getPointerOperandType()->getPointerAddressSpace(); } unsigned getNumIndices() const { // Note: always non-negative return getNumOperands() - 1; } bool hasIndices() const { return getNumOperands() > 1; } /// Return true if all of the indices of this GEP are zeros. /// If so, the result pointer and the first operand have the same /// value, just potentially different types. bool hasAllZeroIndices() const { for (const_op_iterator I = idx_begin(), E = idx_end(); I != E; ++I) { if (ConstantInt *C = dyn_cast(I)) if (C->isZero()) continue; return false; } return true; } /// Return true if all of the indices of this GEP are constant integers. /// If so, the result pointer and the first operand have /// a constant offset between them. bool hasAllConstantIndices() const { for (const_op_iterator I = idx_begin(), E = idx_end(); I != E; ++I) { if (!isa(I)) return false; } return true; } unsigned countNonConstantIndices() const { return count_if(indices(), [](const Use& use) { return !isa(*use); }); } /// Compute the maximum alignment that this GEP is garranteed to preserve. Align getMaxPreservedAlignment(const DataLayout &DL) const; /// Accumulate the constant address offset of this GEP if possible. /// /// This routine accepts an APInt into which it will try to accumulate the /// constant offset of this GEP. /// /// If \p ExternalAnalysis is provided it will be used to calculate a offset /// when a operand of GEP is not constant. /// For example, for a value \p ExternalAnalysis might try to calculate a /// lower bound. If \p ExternalAnalysis is successful, it should return true. /// /// If the \p ExternalAnalysis returns false or the value returned by \p /// ExternalAnalysis results in a overflow/underflow, this routine returns /// false and the value of the offset APInt is undefined (it is *not* /// preserved!). /// /// The APInt passed into this routine must be at exactly as wide as the /// IntPtr type for the address space of the base GEP pointer. bool accumulateConstantOffset( const DataLayout &DL, APInt &Offset, function_ref ExternalAnalysis = nullptr) const; static bool accumulateConstantOffset( Type *SourceType, ArrayRef Index, const DataLayout &DL, APInt &Offset, function_ref ExternalAnalysis = nullptr); /// Collect the offset of this GEP as a map of Values to their associated /// APInt multipliers, as well as a total Constant Offset. bool collectOffset(const DataLayout &DL, unsigned BitWidth, MapVector &VariableOffsets, APInt &ConstantOffset) const; }; class PtrToIntOperator : public ConcreteOperator { friend class PtrToInt; friend class ConstantExpr; public: Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; // get index for modifying correct operand } /// Method to return the pointer operand as a PointerType. Type *getPointerOperandType() const { return getPointerOperand()->getType(); } /// Method to return the address space of the pointer operand. unsigned getPointerAddressSpace() const { return cast(getPointerOperandType())->getAddressSpace(); } }; class BitCastOperator : public ConcreteOperator { friend class BitCastInst; friend class ConstantExpr; public: Type *getSrcTy() const { return getOperand(0)->getType(); } Type *getDestTy() const { return getType(); } }; class AddrSpaceCastOperator : public ConcreteOperator { friend class AddrSpaceCastInst; friend class ConstantExpr; public: Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } unsigned getSrcAddressSpace() const { return getPointerOperand()->getType()->getPointerAddressSpace(); } unsigned getDestAddressSpace() const { return getType()->getPointerAddressSpace(); } }; } // end namespace llvm #endif // LLVM_IR_OPERATOR_H