diff options
| author | Stephen Hines <srhines@google.com> | 2019-07-02 16:25:20 -0700 |
|---|---|---|
| committer | Ali B <abittin@gmail.com> | 2019-07-05 19:33:16 +0300 |
| commit | 9afee4e65dc5f9f5eb371683729ff67b8df81d03 (patch) | |
| tree | 4cf241d6c9044f91ee8c06e6920174d06f8de0b6 /clang-r353983e/include/llvm/IR/Operator.h | |
| parent | 2f19bd722c4c825320d1511c1ed83161b7f95d51 (diff) | |
clang 9.0.5 (based on r353983e) from build 5696680.
Bug: http://b/135931688
Bug: http://b/136008926
Test: N/A
Change-Id: I922d17410047d2e2df4625615352c588ee71b203
Diffstat (limited to 'clang-r353983e/include/llvm/IR/Operator.h')
| -rw-r--r-- | clang-r353983e/include/llvm/IR/Operator.h | 583 |
1 files changed, 583 insertions, 0 deletions
diff --git a/clang-r353983e/include/llvm/IR/Operator.h b/clang-r353983e/include/llvm/IR/Operator.h new file mode 100644 index 00000000..613d4342 --- /dev/null +++ b/clang-r353983e/include/llvm/IR/Operator.h @@ -0,0 +1,583 @@ +//===-- 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/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" +#include <cstddef> + +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<Instruction>(this)) + return I->getOpcode(); + return cast<ConstantExpr>(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<Instruction>(V)) + return I->getOpcode(); + if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(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<Instruction>(V) || isa<ConstantExpr>(V); + } +}; + +/// 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 { + 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<Instruction>(V) && classof(cast<Instruction>(V))) || + (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(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<Instruction>(V) && classof(cast<Instruction>(V))) || + (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V))); + } +}; + +/// Convenience struct for specifying and reasoning about fast-math flags. +class FastMathFlags { +private: + friend class FPMathOperator; + + unsigned Flags = 0; + + FastMathFlags(unsigned F) { + // If all 7 bits are set, turn this into -1. If the number of bits grows, + // this must be updated. This is intended to provide some forward binary + // compatibility insurance for the meaning of 'fast' in case bits are added. + if (F == 0x7F) Flags = ~0U; + else Flags = F; + } + +public: + // This is how the bits are used in Value::SubclassOptionalData so they + // should fit there too. + // WARNING: We're out of space. SubclassOptionalData only has 7 bits. New + // functionality will require a change in how this information is stored. + enum { + AllowReassoc = (1 << 0), + NoNaNs = (1 << 1), + NoInfs = (1 << 2), + NoSignedZeros = (1 << 3), + AllowReciprocal = (1 << 4), + AllowContract = (1 << 5), + ApproxFunc = (1 << 6) + }; + + FastMathFlags() = default; + + bool any() const { return Flags != 0; } + bool none() const { return Flags == 0; } + bool all() const { return Flags == ~0U; } + + void clear() { Flags = 0; } + void set() { Flags = ~0U; } + + /// Flag queries + bool allowReassoc() const { return 0 != (Flags & AllowReassoc); } + bool noNaNs() const { return 0 != (Flags & NoNaNs); } + bool noInfs() const { return 0 != (Flags & NoInfs); } + bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); } + bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); } + bool allowContract() const { return 0 != (Flags & AllowContract); } + bool approxFunc() const { return 0 != (Flags & ApproxFunc); } + /// 'Fast' means all bits are set. + bool isFast() const { return all(); } + + /// Flag setters + void setAllowReassoc(bool B = true) { + Flags = (Flags & ~AllowReassoc) | B * AllowReassoc; + } + void setNoNaNs(bool B = true) { + Flags = (Flags & ~NoNaNs) | B * NoNaNs; + } + void setNoInfs(bool B = true) { + Flags = (Flags & ~NoInfs) | B * NoInfs; + } + void setNoSignedZeros(bool B = true) { + Flags = (Flags & ~NoSignedZeros) | B * NoSignedZeros; + } + void setAllowReciprocal(bool B = true) { + Flags = (Flags & ~AllowReciprocal) | B * AllowReciprocal; + } + void setAllowContract(bool B = true) { + Flags = (Flags & ~AllowContract) | B * AllowContract; + } + void setApproxFunc(bool B = true) { + Flags = (Flags & ~ApproxFunc) | B * ApproxFunc; + } + void setFast(bool B = true) { B ? set() : clear(); } + + void operator&=(const FastMathFlags &OtherFlags) { + Flags &= OtherFlags.Flags; + } +}; + +/// 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<Instruction>(V)) + Opcode = I->getOpcode(); + else if (auto *CE = dyn_cast<ConstantExpr>(V)) + Opcode = CE->getOpcode(); + else + return false; + + switch (Opcode) { + case Instruction::FCmp: + return true; + // non math FP Operators (no FMF) + case Instruction::ExtractElement: + case Instruction::ShuffleVector: + case Instruction::InsertElement: + return false; + default: + return V->getType()->isFPOrFPVectorTy(); + } + } +}; + +/// A helper template for defining operators for individual opcodes. +template<typename SuperClass, unsigned Opc> +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<Instruction>(V) && classof(cast<Instruction>(V))) || + (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V))); + } +}; + +class AddOperator + : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Add> { +}; +class SubOperator + : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Sub> { +}; +class MulOperator + : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Mul> { +}; +class ShlOperator + : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Shl> { +}; + +class SDivOperator + : public ConcreteOperator<PossiblyExactOperator, Instruction::SDiv> { +}; +class UDivOperator + : public ConcreteOperator<PossiblyExactOperator, Instruction::UDiv> { +}; +class AShrOperator + : public ConcreteOperator<PossiblyExactOperator, Instruction::AShr> { +}; +class LShrOperator + : public ConcreteOperator<PossiblyExactOperator, Instruction::LShr> { +}; + +class ZExtOperator : public ConcreteOperator<Operator, Instruction::ZExt> {}; + +class GEPOperator + : public ConcreteOperator<Operator, Instruction::GetElementPtr> { + 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 None if + /// none. + Optional<unsigned> getInRangeIndex() const { + if (SubclassOptionalData >> 1 == 0) return None; + 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(); } + + 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<ConstantInt>(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<ConstantInt>(I)) + return false; + } + return true; + } + + unsigned countNonConstantIndices() const { + return count_if(make_range(idx_begin(), idx_end()), [](const Use& use) { + return !isa<ConstantInt>(*use); + }); + } + + /// Accumulate the constant address offset of this GEP if possible. + /// + /// This routine accepts an APInt into which it will accumulate the constant + /// offset of this GEP if the GEP is in fact constant. If the GEP is not + /// all-constant, it 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) const; +}; + +class PtrToIntOperator + : public ConcreteOperator<Operator, Instruction::PtrToInt> { + 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<PointerType>(getPointerOperandType())->getAddressSpace(); + } +}; + +class BitCastOperator + : public ConcreteOperator<Operator, Instruction::BitCast> { + friend class BitCastInst; + friend class ConstantExpr; + +public: + Type *getSrcTy() const { + return getOperand(0)->getType(); + } + + Type *getDestTy() const { + return getType(); + } +}; + +} // end namespace llvm + +#endif // LLVM_IR_OPERATOR_H |
