Index: clang/lib/CodeGen/CGAtomic.cpp =================================================================== --- clang/lib/CodeGen/CGAtomic.cpp +++ clang/lib/CodeGen/CGAtomic.cpp @@ -1526,10 +1526,12 @@ if (ValTy->isIntegerTy()) { assert(IntVal->getType() == ValTy && "Different integer types."); return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy)); - } else if (ValTy->isPointerTy()) + } else if (ValTy->isPointerTy()) { return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy)); - else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy)) + } else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy, + CGF.CGM.getDataLayout())) { return RValue::get(CGF.Builder.CreateBitCast(IntVal, ValTy)); + } } // Create a temporary. This needs to be big enough to hold the @@ -1714,7 +1716,8 @@ LVal.isSimple() ? getValueSizeInBits() : getAtomicSizeInBits()); if (isa(Value->getType())) return CGF.Builder.CreatePtrToInt(Value, InputIntTy); - else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy)) + else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy, + CGF.CGM.getDataLayout())) return CGF.Builder.CreateBitCast(Value, InputIntTy); } } Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -11014,8 +11014,12 @@ is always a *no-op cast* because no bits change with this conversion. The conversion is done as if the ``value`` had been stored to memory and read back as type ``ty2``. Pointer (or vector of -pointers) types may only be converted to other pointer (or vector of -pointers) types with the same address space through this instruction. +pointers) types can be converted to other pointer (or vector of +pointers) types in the same address space or different address spaces +with this instruction. When such a reinterpretation +of bits is not supported by the target, value is poison. +(Note: Frontends are expected to check validity but optimisations +may infer such a poison bitcast from the input program). To convert pointers to other types, use the :ref:`inttoptr ` or :ref:`ptrtoint ` instructions first. @@ -11033,6 +11037,7 @@ %Y = bitcast i32* %x to i16* ; yields i16*:%x %Z = bitcast <2 x i32> %V to i64; ; yields i64: %V (depends on endianess) %Z = bitcast <2 x i32*> %V to <2 x i64*> ; yields <2 x i64*> + %W = bitcast i32* %x to i32 addrspace(1)* ; yields i32 addrspace(1)*:%w .. _i_addrspacecast: Index: llvm/include/llvm/Analysis/InstSimplifyFolder.h =================================================================== --- llvm/include/llvm/Analysis/InstSimplifyFolder.h +++ llvm/include/llvm/Analysis/InstSimplifyFolder.h @@ -163,6 +163,12 @@ return C; // avoid calling Fold return ConstFolder.CreateCast(Op, C, DestTy); } + Value *CreateCast(Instruction::CastOps Op, Constant *C, Type *DestTy, + const DataLayout &DL) const override { + if (C->getType() == DestTy) + return C; // avoid calling Fold + return ConstFolder.CreateCast(Op, C, DestTy, DL); + } Value *CreateIntCast(Constant *C, Type *DestTy, bool isSigned) const override { if (C->getType() == DestTy) @@ -182,6 +188,10 @@ Value *CreateBitCast(Constant *C, Type *DestTy) const override { return ConstFolder.CreateBitCast(C, DestTy); } + Value *CreateBitCast(Constant *C, Type *DestTy, + const DataLayout &DL) const override { + return ConstFolder.CreateBitCast(C, DestTy, DL); + } Value *CreateIntToPtr(Constant *C, Type *DestTy) const override { return ConstFolder.CreateIntToPtr(C, DestTy); } Index: llvm/include/llvm/Analysis/TargetFolder.h =================================================================== --- llvm/include/llvm/Analysis/TargetFolder.h +++ llvm/include/llvm/Analysis/TargetFolder.h @@ -196,6 +196,12 @@ return C; // avoid calling Fold return Fold(ConstantExpr::getCast(Op, C, DestTy)); } + Constant *CreateCast(Instruction::CastOps Op, Constant *C, Type *DestTy, + const DataLayout &DL) const override { + if (C->getType() == DestTy) + return C; // avoid calling Fold + return Fold(ConstantExpr::getCast(Op, C, DestTy, DL)); + } Constant *CreateIntCast(Constant *C, Type *DestTy, bool isSigned) const override { if (C->getType() == DestTy) @@ -215,6 +221,10 @@ Constant *CreateBitCast(Constant *C, Type *DestTy) const override { return CreateCast(Instruction::BitCast, C, DestTy); } + Constant *CreateBitCast(Constant *C, Type *DestTy, + const DataLayout &DL) const override { + return CreateCast(Instruction::BitCast, C, DestTy, DL); + } Constant *CreateIntToPtr(Constant *C, Type *DestTy) const override { return CreateCast(Instruction::IntToPtr, C, DestTy); } Index: llvm/include/llvm/IR/ConstantFolder.h =================================================================== --- llvm/include/llvm/IR/ConstantFolder.h +++ llvm/include/llvm/IR/ConstantFolder.h @@ -205,6 +205,11 @@ return ConstantExpr::getCast(Op, C, DestTy); } + Constant *CreateCast(Instruction::CastOps Op, Constant *C, Type *DestTy, + const DataLayout &DL) const override { + return ConstantExpr::getCast(Op, C, DestTy, DL); + } + Constant *CreatePointerCast(Constant *C, Type *DestTy) const override { return ConstantExpr::getPointerCast(C, DestTy); } @@ -227,6 +232,11 @@ return CreateCast(Instruction::BitCast, C, DestTy); } + Constant *CreateBitCast(Constant *C, Type *DestTy, + const DataLayout &DL) const override { + return CreateCast(Instruction::BitCast, C, DestTy, DL); + } + Constant *CreateIntToPtr(Constant *C, Type *DestTy) const override { return CreateCast(Instruction::IntToPtr, C, DestTy); } Index: llvm/include/llvm/IR/Constants.h =================================================================== --- llvm/include/llvm/IR/Constants.h +++ llvm/include/llvm/IR/Constants.h @@ -1054,6 +1054,8 @@ bool OnlyIfReduced = false); static Constant *getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced = false); + static Constant *getBitCast(Constant *C, Type *Ty, const DataLayout &DL, + bool OnlyIfReduced = false); static Constant *getAddrSpaceCast(Constant *C, Type *Ty, bool OnlyIfReduced = false); @@ -1142,6 +1144,16 @@ static Constant *getCast(unsigned ops, Constant *C, Type *Ty, bool OnlyIfReduced = false); + /// Convenience function for getting a Cast operation. + /// + /// \param ops The opcode for the conversion + /// \param C The constant to be converted + /// \param Ty The type to which the constant is converted + /// \param DL The DataLayout + /// \param OnlyIfReduced see \a getWithOperands() docs. + static Constant *getCast(unsigned ops, Constant *C, Type *Ty, + const DataLayout &DL, bool OnlyIfReduced = false); + // Create a ZExt or BitCast cast constant expression static Constant * getZExtOrBitCast(Constant *C, ///< The constant to zext or bitcast Index: llvm/include/llvm/IR/IRBuilder.h =================================================================== --- llvm/include/llvm/IR/IRBuilder.h +++ llvm/include/llvm/IR/IRBuilder.h @@ -1965,6 +1965,11 @@ return CreateCast(Instruction::BitCast, V, DestTy, Name); } + Value *CreateBitCast(Value *V, Type *DestTy, const DataLayout &DL, + const Twine &Name = "") { + return CreateCast(Instruction::BitCast, V, DestTy, DL, Name); + } + Value *CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::AddrSpaceCast, V, DestTy, Name); @@ -2006,6 +2011,15 @@ return Insert(CastInst::Create(Op, V, DestTy), Name); } + Value *CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy, + const DataLayout &DL, const Twine &Name = "") { + if (V->getType() == DestTy) + return V; + if (auto *VC = dyn_cast(V)) + return Insert(Folder.CreateCast(Op, VC, DestTy, DL), Name); + return Insert(CastInst::Create(Op, V, DestTy, DL), Name); + } + Value *CreatePointerCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) Index: llvm/include/llvm/IR/IRBuilderFolder.h =================================================================== --- llvm/include/llvm/IR/IRBuilderFolder.h +++ llvm/include/llvm/IR/IRBuilderFolder.h @@ -91,6 +91,8 @@ virtual Value *CreateCast(Instruction::CastOps Op, Constant *C, Type *DestTy) const = 0; + virtual Value *CreateCast(Instruction::CastOps Op, Constant *C, Type *DestTy, + const DataLayout &DL) const = 0; virtual Value *CreatePointerCast(Constant *C, Type *DestTy) const = 0; virtual Value *CreatePointerBitCastOrAddrSpaceCast(Constant *C, Type *DestTy) const = 0; @@ -98,6 +100,8 @@ bool isSigned) const = 0; virtual Value *CreateFPCast(Constant *C, Type *DestTy) const = 0; virtual Value *CreateBitCast(Constant *C, Type *DestTy) const = 0; + virtual Value *CreateBitCast(Constant *C, Type *DestTy, + const DataLayout &DL) const = 0; virtual Value *CreateIntToPtr(Constant *C, Type *DestTy) const = 0; virtual Value *CreatePtrToInt(Constant *C, Type *DestTy) const = 0; virtual Value *CreateZExtOrBitCast(Constant *C, Type *DestTy) const = 0; Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -27,6 +27,7 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" @@ -471,6 +472,37 @@ BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); + /// Provides a way to construct any of the CastInst subclasses using an + /// opcode instead of the subclass's constructor. The opcode must be in the + /// CastOps category (Instruction::isCast(opcode) returns true). DataLayout + /// is used to check validity of bitcast. This constructor has + /// insert-before-instruction semantics to automatically + /// insert the new CastInst before InsertBefore (if it is non-null). + /// Construct any of the CastInst subclasses + static CastInst *Create( + Instruction::CastOps, ///< The opcode of the cast instruction + Value *S, ///< The value to be casted (operand 0) + Type *Ty, ///< The type to which cast should be made + const DataLayout &DL, ///< DataLayout to check validity of bitcast + const Twine &Name = "", ///< Name for the instruction + Instruction *InsertBefore = nullptr ///< Place to insert the instruction + ); + /// Provides a way to construct any of the CastInst subclasses using an + /// opcode instead of the subclass's constructor. The opcode must be in the + /// CastOps category. DataLayout is used to check validity of bitcast. + /// This constructor has insert-at-end-of-block semantics + /// to automatically insert the new CastInst at the end of InsertAtEnd (if + /// its non-null). + /// Construct any of the CastInst subclasses + static CastInst * + Create(Instruction::CastOps, ///< The opcode for the cast instruction + Value *S, ///< The value to be casted (operand 0) + Type *Ty, ///< The type to which operand is casted + const DataLayout &DL, ///< DataLayout to check validity of bitcast + const Twine &Name, ///< The name for the instruction + BasicBlock *InsertAtEnd ///< The block to insert the instruction into + ); + /// Create a ZExt or BitCast cast instruction static CastInst *CreateZExtOrBitCast( Value *S, ///< The value to be casted (operand 0) @@ -600,8 +632,9 @@ /// Check whether a bitcast between these types is valid static bool isBitCastable( - Type *SrcTy, ///< The Type from which the value should be cast. - Type *DestTy ///< The Type to which the value should be cast. + Type *SrcTy, ///< The Type from which the value should be cast. + Type *DestTy, ///< The Type to which the value should be cast. + const DataLayout &DL ///< The DataLayout to check validity of bitcast ); /// Check whether a bitcast, inttoptr, or ptrtoint cast between these @@ -693,6 +726,17 @@ return castIsValid(op, S->getType(), DstTy); } + /// This method can be used to determine if a cast from SrcTy to DstTy using + /// Opcode op and DataLayout DL is valid or not + /// @returns true iff the proposed cast is valid. + /// Determine if a cast is valid without creating one. + static bool castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy, + const DataLayout &DL); + static bool castIsValid(Instruction::CastOps op, Value *S, Type *DstTy, + const DataLayout &DL) { + return castIsValid(op, S->getType(), DstTy, DL); + } + /// Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Instruction *I) { return I->isCast(); Index: llvm/include/llvm/IR/Instructions.h =================================================================== --- llvm/include/llvm/IR/Instructions.h +++ llvm/include/llvm/IR/Instructions.h @@ -5237,6 +5237,25 @@ BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); + /// Constructor with DataLayout and insert-before-instruction semantics + BitCastInst( + Value *S, ///< The value to be casted + Type *Ty, ///< The type to casted to + const DataLayout &DL, ///< The DataLayout to check validity of bitcast + const Twine &NameStr = "", ///< A name for the new instruction + Instruction *InsertBefore = + nullptr ///< Where to insert the new instruction + ); + + /// Constructor with DataLayout and insert-at-end-of-block semantics + BitCastInst( + Value *S, ///< The value to be casted + Type *Ty, ///< The type to casted to + const DataLayout &DL, ///< The DataLayout to check validity of bitcast + const Twine &NameStr, ///< A name for the new instruction + BasicBlock *InsertAtEnd ///< The block to insert the instruction into + ); + // Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Instruction *I) { return I->getOpcode() == BitCast; Index: llvm/include/llvm/IR/NoFolder.h =================================================================== --- llvm/include/llvm/IR/NoFolder.h +++ llvm/include/llvm/IR/NoFolder.h @@ -195,6 +195,11 @@ return CastInst::Create(Op, C, DestTy); } + Instruction *CreateCast(Instruction::CastOps Op, Constant *C, Type *DestTy, + const DataLayout &DL) const override { + return CastInst::Create(Op, C, DestTy, DL); + } + Instruction *CreatePointerCast(Constant *C, Type *DestTy) const override { return CastInst::CreatePointerCast(C, DestTy); } @@ -217,6 +222,11 @@ return CreateCast(Instruction::BitCast, C, DestTy); } + Instruction *CreateBitCast(Constant *C, Type *DestTy, + const DataLayout &DL) const override { + return CreateCast(Instruction::BitCast, C, DestTy, DL); + } + Instruction *CreateIntToPtr(Constant *C, Type *DestTy) const override { return CreateCast(Instruction::IntToPtr, C, DestTy); } Index: llvm/lib/Analysis/ConstantFolding.cpp =================================================================== --- llvm/lib/Analysis/ConstantFolding.cpp +++ llvm/lib/Analysis/ConstantFolding.cpp @@ -102,8 +102,9 @@ /// This always returns a non-null constant, but it may be a /// ConstantExpr if unfoldable. Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) { - assert(CastInst::castIsValid(Instruction::BitCast, C, DestTy) && - "Invalid constantexpr bitcast!"); + assert( + CastInst::castIsValid(Instruction::BitCast, C->getType(), DestTy, DL) && + "Invalid constantexpr bitcast!"); // Catch the obvious splat cases. if (Constant *Res = ConstantFoldLoadFromUniformValue(C, DestTy)) @@ -376,7 +377,7 @@ else if (SrcTy->isPointerTy() && DestTy->isIntegerTy()) Cast = Instruction::PtrToInt; - if (CastInst::castIsValid(Cast, C, DestTy)) + if (CastInst::castIsValid(Cast, C, DestTy, DL)) return ConstantExpr::getCast(Cast, C, DestTy); } Index: llvm/lib/Analysis/LoopUnrollAnalyzer.cpp =================================================================== --- llvm/lib/Analysis/LoopUnrollAnalyzer.cpp +++ llvm/lib/Analysis/LoopUnrollAnalyzer.cpp @@ -153,8 +153,8 @@ // The cast can be invalid, because SimplifiedValues contains results of SCEV // analysis, which operates on integers (and, e.g., might convert i8* null to // i32 0). - if (CastInst::castIsValid(I.getOpcode(), Op, I.getType())) { - const DataLayout &DL = I.getModule()->getDataLayout(); + const DataLayout &DL = I.getModule()->getDataLayout(); + if (CastInst::castIsValid(I.getOpcode(), Op->getType(), I.getType(), DL)) { if (Value *V = SimplifyCastInst(I.getOpcode(), Op, I.getType(), DL)) { SimplifiedValues[&I] = V; return true; Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -6766,13 +6766,16 @@ parseType(DestTy)) return true; - if (!CastInst::castIsValid((Instruction::CastOps)Opc, Op, DestTy)) { - CastInst::castIsValid((Instruction::CastOps)Opc, Op, DestTy); + if (!CastInst::castIsValid((Instruction::CastOps)Opc, Op, DestTy, + M->getDataLayout())) { + CastInst::castIsValid((Instruction::CastOps)Opc, Op, DestTy, + M->getDataLayout()); return error(Loc, "invalid cast opcode for cast from '" + getTypeString(Op->getType()) + "' to '" + getTypeString(DestTy) + "'"); } - Inst = CastInst::Create((Instruction::CastOps)Opc, Op, DestTy); + Inst = CastInst::Create((Instruction::CastOps)Opc, Op, DestTy, + M->getDataLayout()); return false; } Index: llvm/lib/IR/AutoUpgrade.cpp =================================================================== --- llvm/lib/IR/AutoUpgrade.cpp +++ llvm/lib/IR/AutoUpgrade.cpp @@ -4224,7 +4224,7 @@ // value to the return type of the old function. if (NewFuncTy->getReturnType() != CI->getType() && !CastInst::castIsValid(Instruction::BitCast, CI, - NewFuncTy->getReturnType())) + NewFuncTy->getReturnType(), M.getDataLayout())) continue; bool InvalidCast = false; @@ -4238,7 +4238,8 @@ // Don't upgrade the intrinsic if it's not valid to bitcast the argument // to the parameter type of the new function. if (!CastInst::castIsValid(Instruction::BitCast, Arg, - NewFuncTy->getParamType(I))) { + NewFuncTy->getParamType(I), + M.getDataLayout())) { InvalidCast = true; break; } Index: llvm/lib/IR/Constants.cpp =================================================================== --- llvm/lib/IR/Constants.cpp +++ llvm/lib/IR/Constants.cpp @@ -2047,6 +2047,46 @@ } } +Constant *ConstantExpr::getCast(unsigned oc, Constant *C, Type *Ty, + const DataLayout &DL, bool OnlyIfReduced) { + Instruction::CastOps opc = Instruction::CastOps(oc); + assert(Instruction::isCast(opc) && "opcode out of range"); + assert(C && Ty && "Null arguments to getCast"); + assert(CastInst::castIsValid(opc, C->getType(), Ty, DL) && + "Invalid constantexpr cast!"); + + switch (opc) { + default: + llvm_unreachable("Invalid cast opcode"); + case Instruction::Trunc: + return getTrunc(C, Ty, OnlyIfReduced); + case Instruction::ZExt: + return getZExt(C, Ty, OnlyIfReduced); + case Instruction::SExt: + return getSExt(C, Ty, OnlyIfReduced); + case Instruction::FPTrunc: + return getFPTrunc(C, Ty, OnlyIfReduced); + case Instruction::FPExt: + return getFPExtend(C, Ty, OnlyIfReduced); + case Instruction::UIToFP: + return getUIToFP(C, Ty, OnlyIfReduced); + case Instruction::SIToFP: + return getSIToFP(C, Ty, OnlyIfReduced); + case Instruction::FPToUI: + return getFPToUI(C, Ty, OnlyIfReduced); + case Instruction::FPToSI: + return getFPToSI(C, Ty, OnlyIfReduced); + case Instruction::PtrToInt: + return getPtrToInt(C, Ty, OnlyIfReduced); + case Instruction::IntToPtr: + return getIntToPtr(C, Ty, OnlyIfReduced); + case Instruction::BitCast: + return getBitCast(C, Ty, DL, OnlyIfReduced); + case Instruction::AddrSpaceCast: + return getAddrSpaceCast(C, Ty, OnlyIfReduced); + } +} + Constant *ConstantExpr::getZExtOrBitCast(Constant *C, Type *Ty) { if (C->getType()->getScalarSizeInBits() == Ty->getScalarSizeInBits()) return getBitCast(C, Ty); @@ -2265,6 +2305,19 @@ return getFoldedCast(Instruction::BitCast, C, DstTy, OnlyIfReduced); } +Constant *ConstantExpr::getBitCast(Constant *C, Type *DstTy, + const DataLayout &DL, bool OnlyIfReduced) { + assert(CastInst::castIsValid(Instruction::BitCast, C->getType(), DstTy, DL) && + "Invalid constantexpr bitcast!"); + + // It is common to ask for a bitcast of a value to its own type, handle this + // speedily. + if (C->getType() == DstTy) + return C; + + return getFoldedCast(Instruction::BitCast, C, DstTy, OnlyIfReduced); +} + Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy, bool OnlyIfReduced) { assert(CastInst::castIsValid(Instruction::AddrSpaceCast, C, DstTy) && Index: llvm/lib/IR/Instructions.cpp =================================================================== --- llvm/lib/IR/Instructions.cpp +++ llvm/lib/IR/Instructions.cpp @@ -2888,7 +2888,7 @@ Type *SrcTy, Type *DestTy, const DataLayout &DL) { - assert(castIsValid(Opcode, SrcTy, DestTy) && "method precondition"); + assert(castIsValid(Opcode, SrcTy, DestTy, DL) && "method precondition"); switch (Opcode) { default: llvm_unreachable("Invalid CastOp"); case Instruction::Trunc: @@ -3193,6 +3193,34 @@ } } +CastInst *CastInst::Create(Instruction::CastOps op, Value *S, Type *Ty, + const DataLayout &DL, const Twine &Name, + Instruction *InsertBefore) { + assert(castIsValid(op, S, Ty, DL) && "Invalid cast!"); + + // Construct and return the appropriate CastInst subclass + switch (op) { + case BitCast: + return new BitCastInst(S, Ty, DL, Name, InsertBefore); + default: + CastInst::Create(op, S, Ty, Name, InsertBefore); + } +} + +CastInst *CastInst::Create(Instruction::CastOps op, Value *S, Type *Ty, + const DataLayout &DL, const Twine &Name, + BasicBlock *InsertAtEnd) { + assert(castIsValid(op, S, Ty, DL) && "Invalid cast!"); + + // Construct and return the appropriate CastInst subclass + switch (op) { + case BitCast: + return new BitCastInst(S, Ty, DL, Name, InsertAtEnd); + default: + CastInst::Create(op, S, Ty, Name, InsertAtEnd); + } +} + CastInst *CastInst::CreateZExtOrBitCast(Value *S, Type *Ty, const Twine &Name, Instruction *InsertBefore) { @@ -3369,7 +3397,7 @@ return Create(opcode, C, Ty, Name, InsertAtEnd); } -bool CastInst::isBitCastable(Type *SrcTy, Type *DestTy) { +bool CastInst::isBitCastable(Type *SrcTy, Type *DestTy, const DataLayout &DL) { if (!SrcTy->isFirstClassType() || !DestTy->isFirstClassType()) return false; @@ -3388,7 +3416,12 @@ if (PointerType *DestPtrTy = dyn_cast(DestTy)) { if (PointerType *SrcPtrTy = dyn_cast(SrcTy)) { - return SrcPtrTy->getAddressSpace() == DestPtrTy->getAddressSpace(); + if (SrcPtrTy->getAddressSpace() == DestPtrTy->getAddressSpace()) { + return true; + } else { + return DL.getPointerTypeSizeInBits(SrcTy) == + DL.getPointerTypeSizeInBits(DestTy); + } } } @@ -3421,7 +3454,7 @@ return (IntTy->getBitWidth() == DL.getPointerTypeSizeInBits(PtrTy) && !DL.isNonIntegralPointerType(PtrTy)); - return isBitCastable(SrcTy, DestTy); + return isBitCastable(SrcTy, DestTy, DL); } // Provide a way to get a "cast" where the cast opcode is inferred from the @@ -3533,8 +3566,7 @@ /// could be broken out into the separate constructors but it is useful to have /// it in one place and to eliminate the redundant code for getting the sizes /// of the types involved. -bool -CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) { +bool CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) { if (!SrcTy->isFirstClassType() || !DstTy->isFirstClassType() || SrcTy->isAggregateType() || DstTy->isAggregateType()) return false; @@ -3633,6 +3665,57 @@ } } +bool CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy, + const DataLayout &DL) { + if (!SrcTy->isFirstClassType() || !DstTy->isFirstClassType() || + SrcTy->isAggregateType() || DstTy->isAggregateType()) + return false; + + // Get the size of the types in bits, and whether we are dealing + // with vector types, we'll need this later. + bool SrcIsVec = isa(SrcTy); + bool DstIsVec = isa(DstTy); + + // If these are vector types, get the lengths of the vectors (using zero for + // scalar types means that checking that vector lengths match also checks that + // scalars are not being converted to vectors or vectors to scalars). + ElementCount SrcEC = SrcIsVec ? cast(SrcTy)->getElementCount() + : ElementCount::getFixed(0); + ElementCount DstEC = DstIsVec ? cast(DstTy)->getElementCount() + : ElementCount::getFixed(0); + + switch (op) { + default: + return castIsValid(op, SrcTy, DstTy); + case Instruction::BitCast: { + PointerType *SrcPtrTy = dyn_cast(SrcTy->getScalarType()); + PointerType *DstPtrTy = dyn_cast(DstTy->getScalarType()); + + // BitCast implies a no-op cast of type only. No bits change. + // However, you can't cast pointers to anything but pointers. + if (!SrcPtrTy != !DstPtrTy) + return false; + + // For non-pointer cases, the cast is okay if the source and destination bit + // widths are identical. + if (!SrcPtrTy) + return SrcTy->getPrimitiveSizeInBits() == DstTy->getPrimitiveSizeInBits(); + + // If source or destionation is vector of pointers, compute the total bit + // width of vector elements. else if not vector, use the Pointer size from + // data layout. + unsigned SrcTypeSize = + SrcIsVec ? SrcEC.getKnownMinValue() * DL.getPointerTypeSizeInBits(SrcTy) + : DL.getPointerTypeSizeInBits(SrcTy); + unsigned DstTypeSize = + DstIsVec ? DstEC.getKnownMinValue() * DL.getPointerTypeSizeInBits(DstTy) + : DL.getPointerTypeSizeInBits(DstTy); + + return SrcTypeSize == DstTypeSize; + } + } +} + TruncInst::TruncInst( Value *S, Type *Ty, const Twine &Name, Instruction *InsertBefore ) : CastInst(Ty, Trunc, S, Name, InsertBefore) { @@ -3776,6 +3859,18 @@ assert(castIsValid(getOpcode(), S, Ty) && "Illegal BitCast"); } +BitCastInst::BitCastInst(Value *S, Type *Ty, const DataLayout &DL, + const Twine &Name, Instruction *InsertBefore) + : CastInst(Ty, BitCast, S, Name, InsertBefore) { + assert(castIsValid(getOpcode(), S->getType(), Ty, DL) && "Illegal BitCast"); +} + +BitCastInst::BitCastInst(Value *S, Type *Ty, const DataLayout &DL, + const Twine &Name, BasicBlock *InsertAtEnd) + : CastInst(Ty, BitCast, S, Name, InsertAtEnd) { + assert(castIsValid(getOpcode(), S->getType(), Ty, DL) && "Illegal BitCast"); +} + AddrSpaceCastInst::AddrSpaceCastInst( Value *S, Type *Ty, const Twine &Name, Instruction *InsertBefore ) : CastInst(Ty, AddrSpaceCast, S, Name, InsertBefore) { Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -2135,7 +2135,7 @@ void Verifier::visitConstantExpr(const ConstantExpr *CE) { if (CE->getOpcode() == Instruction::BitCast) Assert(CastInst::castIsValid(Instruction::BitCast, CE->getOperand(0), - CE->getType()), + CE->getType(), DL), "Invalid bitcast", CE); } @@ -3055,9 +3055,9 @@ } void Verifier::visitBitCastInst(BitCastInst &I) { - Assert( - CastInst::castIsValid(Instruction::BitCast, I.getOperand(0), I.getType()), - "Invalid bitcast", &I); + Assert(CastInst::castIsValid(Instruction::BitCast, I.getOperand(0), + I.getType(), DL), + "Invalid bitcast", &I); visitInstruction(I); } Index: llvm/lib/Transforms/Coroutines/Coroutines.cpp =================================================================== --- llvm/lib/Transforms/Coroutines/Coroutines.cpp +++ llvm/lib/Transforms/Coroutines/Coroutines.cpp @@ -444,7 +444,8 @@ // The optimizer likes to eliminate bitcasts leading into variadic // calls, but that messes with our invariants. Re-insert the // bitcast and ignore this type mismatch. - if (CastInst::isBitCastable(SrcTy, *RI)) { + if (CastInst::isBitCastable(SrcTy, *RI, + F.getParent()->getDataLayout())) { auto BCI = new BitCastInst(*SI, *RI, "", Suspend); SI->set(BCI); continue; Index: llvm/lib/Transforms/Utils/VNCoercion.cpp =================================================================== --- llvm/lib/Transforms/Utils/VNCoercion.cpp +++ llvm/lib/Transforms/Utils/VNCoercion.cpp @@ -76,6 +76,11 @@ // If this is already the right type, just return it. Type *StoredValTy = StoredVal->getType(); + // Return if a bitcast has been introduced before and if types matches. + if (StoredValTy == LoadedTy) { + return StoredVal; + } + uint64_t StoredValSize = DL.getTypeSizeInBits(StoredValTy).getFixedSize(); uint64_t LoadedValSize = DL.getTypeSizeInBits(LoadedTy).getFixedSize(); @@ -415,9 +420,22 @@ return SrcVal; } + // If two pointers are in different address spaces + // and if bitcast is valid, introduce a bitcast. + if (SrcVal->getType()->isPtrOrPtrVectorTy() && LoadTy->isPtrOrPtrVectorTy() && + (cast(SrcVal->getType())->getAddressSpace() != + cast(LoadTy)->getAddressSpace())) { + if (CastInst::castIsValid(Instruction::BitCast, SrcVal->getType(), LoadTy, + DL)) { + SrcVal = Helper.CreateBitCast(SrcVal, LoadTy, DL); + return SrcVal; + } + } + uint64_t StoreSize = (DL.getTypeSizeInBits(SrcVal->getType()).getFixedSize() + 7) / 8; uint64_t LoadSize = (DL.getTypeSizeInBits(LoadTy).getFixedSize() + 7) / 8; + // Compute which bits of the stored value are being used by the load. Convert // to an integer type to start with. if (SrcVal->getType()->isPtrOrPtrVectorTy()) Index: llvm/test/Transforms/GVN/gvn-eliminate-inttoptr-ptrtoint-for-load.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/GVN/gvn-eliminate-inttoptr-ptrtoint-for-load.ll @@ -0,0 +1,49 @@ +; RUN: opt -S -gvn < %s | FileCheck %s + +; GVN replaces a load that depends on previous store with intoptr/ptrtoint instructions. +; Instead, replace load with bitcast of pointers from different addrspaces. + +target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-ni:7" + +%struct.S.coerce = type { i32 addrspace(1)* } + +define void @test(%struct.S.coerce %s.coerce) #0 { +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: %s.sroa.0 = alloca i32*, align 8, addrspace(5) +; CHECK-NEXT: %0 = extractvalue %struct.S.coerce %s.coerce, 0 +; CHECK-NEXT: %1 = bitcast i32* addrspace(5)* %s.sroa.0 to i32 addrspace(1)* addrspace(5)* +; CHECK-NEXT: %2 = addrspacecast i32 addrspace(1)* addrspace(5)* %1 to i32 addrspace(1)** +; CHECK-NEXT: store i32 addrspace(1)* %0, i32 addrspace(1)** %2, align 8 +; CHECK-NEXT: %3 = bitcast i32 addrspace(1)* %0 to i32* +; CHECK-NEXT: %4 = load i32, i32* %3, align 4, !tbaa !2 +; CHECK-NEXT: %inc = add nsw i32 %4, 1 +; CHECK-NEXT: store i32 %inc, i32* %3, align 4, !tbaa !2 +; CHECK-NEXT: ret void +; + +entry: + %s.sroa.0 = alloca i32*, align 8, addrspace(5) + + %0 = extractvalue %struct.S.coerce %s.coerce, 0 + %1 = bitcast i32* addrspace(5)* %s.sroa.0 to i32 addrspace(1)* addrspace(5)* + %2 = addrspacecast i32 addrspace(1)* addrspace(5)* %1 to i32 addrspace(1)** + store i32 addrspace(1)* %0, i32 addrspace(1)** %2, align 8 + + %3 = load i32*, i32* addrspace(5)* %s.sroa.0, align 8, !tbaa !2 + %4 = load i32, i32* %3, align 4, !tbaa !2 + %inc = add nsw i32 %4, 1 + store i32 %inc, i32* %3, align 4, !tbaa !2 + + ret void +} + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 11.0.0 (git@github.com:llvm/llvm-project.git 25e22613dfdb4083056e8a951aeb246bea4019f3)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} Index: llvm/test/Transforms/GVN/gvn-eliminate-inttoptr-ptrtoint-for-vector-load.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/GVN/gvn-eliminate-inttoptr-ptrtoint-for-vector-load.ll @@ -0,0 +1,49 @@ +; RUN: opt -S -gvn < %s | FileCheck %s + +; GVN replaces a load that depends on previous store with intoptr/ptrtoint instructions. +; Instead, replace load with bitcast of pointers from different addrspaces. + +target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-ni:7" + +%struct.S.coerce = type { <2 x i32> addrspace(1)* } + +define void @test(%struct.S.coerce %s.coerce) #0 { +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: %s.sroa.0 = alloca <2 x i32>*, align 8, addrspace(5) +; CHECK-NEXT: %0 = extractvalue %struct.S.coerce %s.coerce, 0 +; CHECK-NEXT: %1 = bitcast <2 x i32>* addrspace(5)* %s.sroa.0 to <2 x i32> addrspace(1)* addrspace(5)* +; CHECK-NEXT: %2 = addrspacecast <2 x i32> addrspace(1)* addrspace(5)* %1 to <2 x i32> addrspace(1)** +; CHECK-NEXT: store <2 x i32> addrspace(1)* %0, <2 x i32> addrspace(1)** %2, align 8 +; CHECK-NEXT: %3 = bitcast <2 x i32> addrspace(1)* %0 to <2 x i32>* +; CHECK-NEXT: %4 = load <2 x i32>, <2 x i32>* %3, align 4, !tbaa !2 +; CHECK-NEXT: %inc = add nsw <2 x i32> %4, +; CHECK-NEXT: store <2 x i32> %inc, <2 x i32>* %3, align 4, !tbaa !2 +; CHECK-NEXT: ret void +; + +entry: + %s.sroa.0 = alloca <2 x i32>*, align 8, addrspace(5) + + %0 = extractvalue %struct.S.coerce %s.coerce, 0 + %1 = bitcast <2 x i32>* addrspace(5)* %s.sroa.0 to <2 x i32> addrspace(1)* addrspace(5)* + %2 = addrspacecast <2 x i32> addrspace(1)* addrspace(5)* %1 to <2 x i32> addrspace(1)** + store <2 x i32> addrspace(1)* %0, <2 x i32> addrspace(1)** %2, align 8 + + %3 = load <2 x i32>*, <2 x i32>* addrspace(5)* %s.sroa.0, align 8, !tbaa !2 + %4 = load <2 x i32>, <2 x i32>* %3, align 4, !tbaa !2 + %inc = add nsw <2 x i32> %4, + store <2 x i32> %inc, <2 x i32>* %3, align 4, !tbaa !2 + + ret void +} + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 11.0.0 (git@github.com:llvm/llvm-project.git 25e22613dfdb4083056e8a951aeb246bea4019f3)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} Index: llvm/test/Transforms/GVN/gvn-eliminate-inttoptr-ptrtoint-for-vector-ptr-load.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/GVN/gvn-eliminate-inttoptr-ptrtoint-for-vector-ptr-load.ll @@ -0,0 +1,46 @@ +; RUN: opt -S -gvn < %s | FileCheck %s + +; GVN replaces a load that depends on previous store with intoptr/ptrtoint instructions. +; Instead, replace load with bitcast of pointers from different addrspaces. + +target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-ni:7" + +%struct.S.coerce = type { <2 x i32*> addrspace(1)* } + +define void @test(%struct.S.coerce %s.coerce) #0 { +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: %s.sroa.0 = alloca <2 x i32*>*, align 8, addrspace(5) +; CHECK-NEXT: %0 = extractvalue %struct.S.coerce %s.coerce, 0 +; CHECK-NEXT: %1 = bitcast <2 x i32*>* addrspace(5)* %s.sroa.0 to <2 x i32*> addrspace(1)* addrspace(5)* +; CHECK-NEXT: %2 = addrspacecast <2 x i32*> addrspace(1)* addrspace(5)* %1 to <2 x i32*> addrspace(1)** +; CHECK-NEXT: store <2 x i32*> addrspace(1)* %0, <2 x i32*> addrspace(1)** %2, align 8 +; CHECK-NEXT: %3 = bitcast <2 x i32*> addrspace(1)* %0 to <2 x i32*>* +; CHECK-NEXT: %4 = load <2 x i32*>, <2 x i32*>* %3, align 4, !tbaa !2 +; CHECK-NEXT: store <2 x i32*> %4, <2 x i32*>* %3, align 4, !tbaa !2 +; CHECK-NEXT: ret void +; + +entry: + %s.sroa.0 = alloca <2 x i32*>*, align 8, addrspace(5) + + %0 = extractvalue %struct.S.coerce %s.coerce, 0 + %1 = bitcast <2 x i32*>* addrspace(5)* %s.sroa.0 to <2 x i32*> addrspace(1)* addrspace(5)* + %2 = addrspacecast <2 x i32*> addrspace(1)* addrspace(5)* %1 to <2 x i32*> addrspace(1)** + store <2 x i32*> addrspace(1)* %0, <2 x i32*> addrspace(1)** %2, align 8 + + %3 = load <2 x i32*>*, <2 x i32*>* addrspace(5)* %s.sroa.0, align 8, !tbaa !2 + %4 = load <2 x i32*>, <2 x i32*>* %3, align 4, !tbaa !2 + store <2 x i32*> %4, <2 x i32*>* %3, align 4, !tbaa !2 + ret void +} + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 11.0.0 (git@github.com:llvm/llvm-project.git 25e22613dfdb4083056e8a951aeb246bea4019f3)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} Index: llvm/test/Verifier/bitcast-vector-pointer-as-neg.ll =================================================================== --- llvm/test/Verifier/bitcast-vector-pointer-as-neg.ll +++ llvm/test/Verifier/bitcast-vector-pointer-as-neg.ll @@ -1,14 +1,12 @@ -; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s +; RUN: llvm-as -disable-output %s target datalayout = "e-p:32:32:32-p1:16:16:16-p2:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32" -; CHECK: error: invalid cast opcode for cast from '<4 x i32 addrspace(1)*>' to '<2 x i32 addrspace(2)*>' - ; The pointer in addrspace 1 of the size 16 while pointer in addrspace 2 of the size 32. ; Converting 4 element array of pointers from addrspace 2 to 2 element array in addrspace 2 -; has the same total bit length but bitcast still does not allow conversion into -; different addrspace. -define <2 x i32 addrspace(2)*> @vector_illegal_bitcast_as_1_to_2(<4 x i32 addrspace(1)*> %p) { +; has the same total bit length + +define <2 x i32 addrspace(2)*> @vector_legal_bitcast_as_1_to_2(<4 x i32 addrspace(1)*> %p) { %cast = bitcast <4 x i32 addrspace(1)*> %p to <2 x i32 addrspace(2)*> ret <2 x i32 addrspace(2)*> %cast } Index: llvm/test/Verifier/bitcast-vector-pointer-different-addrspace-illegal.ll =================================================================== --- /dev/null +++ llvm/test/Verifier/bitcast-vector-pointer-different-addrspace-illegal.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s + +target datalayout = "e-p:32:32:32-p1:16:16:16-p2:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32" + +; CHECK: error: invalid cast opcode for cast from '<4 x i32 addrspace(1)*>' to '<4 x i32 addrspace(2)*>' +define <4 x i32 addrspace(2)*> @vector_illegal_bitcast_as_1_to_2(<4 x i32 addrspace(1)*> %p) { + %cast = bitcast <4 x i32 addrspace(1)*> %p to <4 x i32 addrspace(2)*> + ret <4 x i32 addrspace(2)*> %cast +} Index: llvm/test/Verifier/bitcast-vector-pointer-neg.ll =================================================================== --- llvm/test/Verifier/bitcast-vector-pointer-neg.ll +++ llvm/test/Verifier/bitcast-vector-pointer-neg.ll @@ -1,10 +1,12 @@ -; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s +; RUN: llvm-as -disable-output %s target datalayout = "e-p:32:32:32-p1:16:16:16-p2:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32" -; CHECK: error: invalid cast opcode for cast from '<2 x i32*>' to 'i64*' +; The pointer in addrspace 1 of the size 16 while pointer in addrspace 2 of the size 32. +; Converting 4 element array of pointers from addrspace 2 to 2 element array in addrspace 2 +; has the same total bit length -define i64* @illegal_bitcast_vector_of_pointers_to_pointer(<2 x i32*> %a) { - %b = bitcast <2 x i32*> %a to i64* - ret i64* %b +define <2 x i32 addrspace(2)*> @vector_legal_bitcast_as_1_to_2(<4 x i32 addrspace(1)*> %p) { + %cast = bitcast <4 x i32 addrspace(1)*> %p to <2 x i32 addrspace(2)*> + ret <2 x i32 addrspace(2)*> %cast } Index: llvm/test/Verifier/bitcast-vector-pointer-pos.ll =================================================================== --- llvm/test/Verifier/bitcast-vector-pointer-pos.ll +++ llvm/test/Verifier/bitcast-vector-pointer-pos.ll @@ -12,3 +12,7 @@ ret i64* %b } +define <2 x i32 addrspace(2)*> @vector_legal_bitcast_vector_of_pointers_to_vector_of_pointers(<2 x i32*> %a) { + %c = bitcast <2 x i32*> %a to <2 x i32 addrspace(2)*> + ret <2 x i32 addrspace(2)*> %c +} Index: llvm/test/Verifier/bitcast-vector-pointer-same-addrspace.ll =================================================================== --- /dev/null +++ llvm/test/Verifier/bitcast-vector-pointer-same-addrspace.ll @@ -0,0 +1,13 @@ +; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s + +target datalayout = "e-p:32:32:32-p1:16:16:16-p2:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32" + +; CHECK: error: invalid cast opcode for cast from '<4 x i32 addrspace(1)*>' to '<2 x i32 addrspace(1)*>' + +; Converting 4 element array of pointers from addrspace 1 to 2 element array in addrspace 1 +; is invalid since the vector sizes dont match +define <2 x i32 addrspace(1)*> @vector_illegal_bitcast_1(<4 x i32 addrspace(1)*> %p) { + %cast = bitcast <4 x i32 addrspace(1)*> %p to <2 x i32 addrspace(1)*> + ret <2 x i32 addrspace(1)*> %cast +} + Index: llvm/unittests/IR/InstructionsTest.cpp =================================================================== --- llvm/unittests/IR/InstructionsTest.cpp +++ llvm/unittests/IR/InstructionsTest.cpp @@ -189,6 +189,10 @@ TEST(InstructionsTest, CastInst) { LLVMContext C; + DataLayout DL("e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-" + "p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" + "v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-ni:7"); + Type *Int8Ty = Type::getInt8Ty(C); Type *Int16Ty = Type::getInt16Ty(C); Type *Int32Ty = Type::getInt32Ty(C); @@ -217,7 +221,11 @@ Type *Int32PtrAS1Ty = PointerType::get(Int32Ty, 1); Type *Int64PtrAS1Ty = PointerType::get(Int64Ty, 1); + Type *Int32PtrAS2Ty = PointerType::get(Int32Ty, 2); + Type *Int32PtrAS3Ty = PointerType::get(Int32Ty, 3); + Type *V2Int32PtrAS1Ty = FixedVectorType::get(Int32PtrAS1Ty, 2); + Type *V2Int32PtrAS2Ty = FixedVectorType::get(Int32PtrAS2Ty, 2); Type *V2Int64PtrAS1Ty = FixedVectorType::get(Int64PtrAS1Ty, 2); Type *V4Int32PtrAS1Ty = FixedVectorType::get(Int32PtrAS1Ty, 4); Type *VScaleV4Int32PtrAS1Ty = ScalableVectorType::get(Int32PtrAS1Ty, 4); @@ -238,50 +246,52 @@ EXPECT_EQ(CastInst::Trunc, CastInst::getCastOpcode(c64, true, V8x8Ty, true)); EXPECT_EQ(CastInst::SExt, CastInst::getCastOpcode(c8, true, V8x64Ty, true)); - EXPECT_FALSE(CastInst::isBitCastable(V8x8Ty, X86MMXTy)); - EXPECT_FALSE(CastInst::isBitCastable(X86MMXTy, V8x8Ty)); - EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, X86MMXTy)); - EXPECT_FALSE(CastInst::isBitCastable(V8x64Ty, V8x8Ty)); - EXPECT_FALSE(CastInst::isBitCastable(V8x8Ty, V8x64Ty)); - - // Check address space casts are rejected since we don't know the sizes here - EXPECT_FALSE(CastInst::isBitCastable(Int32PtrTy, Int32PtrAS1Ty)); - EXPECT_FALSE(CastInst::isBitCastable(Int32PtrAS1Ty, Int32PtrTy)); - EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, V2Int32PtrAS1Ty)); - EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int32PtrTy)); - EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int64PtrAS1Ty)); + EXPECT_FALSE(CastInst::isBitCastable(V8x8Ty, X86MMXTy, DL)); + EXPECT_FALSE(CastInst::isBitCastable(X86MMXTy, V8x8Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, X86MMXTy, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V8x64Ty, V8x8Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V8x8Ty, V8x64Ty, DL)); + + // Check validity of casts here + EXPECT_TRUE(CastInst::isBitCastable(Int32PtrAS2Ty, Int32PtrAS3Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(Int32PtrAS1Ty, Int32PtrAS2Ty, DL)); + EXPECT_TRUE(CastInst::isBitCastable(Int32PtrTy, Int32PtrAS1Ty, DL)); + EXPECT_TRUE(CastInst::isBitCastable(Int32PtrAS1Ty, Int32PtrTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrTy, V2Int32PtrAS1Ty, DL)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int32PtrTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int64PtrAS1Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int32PtrAS2Ty, DL)); EXPECT_EQ(CastInst::AddrSpaceCast, CastInst::getCastOpcode(v2ptr32, true, V2Int32PtrAS1Ty, true)); // Test mismatched number of elements for pointers - EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V4Int64PtrAS1Ty)); - EXPECT_FALSE(CastInst::isBitCastable(V4Int64PtrAS1Ty, V2Int32PtrAS1Ty)); - EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V4Int32PtrAS1Ty)); - EXPECT_FALSE(CastInst::isBitCastable(Int32PtrTy, V2Int32PtrTy)); - EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, Int32PtrTy)); - - EXPECT_TRUE(CastInst::isBitCastable(Int32PtrTy, Int64PtrTy)); - EXPECT_FALSE(CastInst::isBitCastable(DoubleTy, FloatTy)); - EXPECT_FALSE(CastInst::isBitCastable(FloatTy, DoubleTy)); - EXPECT_TRUE(CastInst::isBitCastable(FloatTy, FloatTy)); - EXPECT_TRUE(CastInst::isBitCastable(FloatTy, FloatTy)); - EXPECT_TRUE(CastInst::isBitCastable(FloatTy, Int32Ty)); - EXPECT_TRUE(CastInst::isBitCastable(Int16Ty, HalfTy)); - EXPECT_TRUE(CastInst::isBitCastable(Int32Ty, FloatTy)); - EXPECT_TRUE(CastInst::isBitCastable(V2Int32Ty, Int64Ty)); - - EXPECT_TRUE(CastInst::isBitCastable(V2Int32Ty, V4Int16Ty)); - EXPECT_FALSE(CastInst::isBitCastable(Int32Ty, Int64Ty)); - EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, Int32Ty)); - - EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, Int64Ty)); - EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, V2Int32PtrTy)); - EXPECT_TRUE(CastInst::isBitCastable(V2Int64PtrTy, V2Int32PtrTy)); - EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrTy, V2Int64PtrTy)); - EXPECT_FALSE(CastInst::isBitCastable(V2Int32Ty, V2Int64Ty)); - EXPECT_FALSE(CastInst::isBitCastable(V2Int64Ty, V2Int32Ty)); - + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V4Int64PtrAS1Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V4Int64PtrAS1Ty, V2Int32PtrAS1Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V4Int32PtrAS1Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(Int32PtrTy, V2Int32PtrTy, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, Int32PtrTy, DL)); + + EXPECT_TRUE(CastInst::isBitCastable(Int32PtrTy, Int64PtrTy, DL)); + EXPECT_FALSE(CastInst::isBitCastable(DoubleTy, FloatTy, DL)); + EXPECT_FALSE(CastInst::isBitCastable(FloatTy, DoubleTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(FloatTy, FloatTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(FloatTy, FloatTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(FloatTy, Int32Ty, DL)); + EXPECT_TRUE(CastInst::isBitCastable(Int16Ty, HalfTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(Int32Ty, FloatTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32Ty, Int64Ty, DL)); + + EXPECT_TRUE(CastInst::isBitCastable(V2Int32Ty, V4Int16Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(Int32Ty, Int64Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, Int32Ty, DL)); + + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, Int64Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, V2Int32PtrTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int64PtrTy, V2Int32PtrTy, DL)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrTy, V2Int64PtrTy, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32Ty, V2Int64Ty, DL)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int64Ty, V2Int32Ty, DL)); EXPECT_FALSE(CastInst::castIsValid(Instruction::BitCast, Constant::getNullValue(V4Int32PtrTy), @@ -345,6 +355,14 @@ Constant::getNullValue(VScaleV4Int16Ty), V4Int16Ty)); + // Bit casting between pointers from different addrspace + EXPECT_TRUE(CastInst::castIsValid(Instruction::BitCast, + Constant::getNullValue(Int32PtrAS2Ty), + Int32PtrAS3Ty, DL)); + EXPECT_FALSE(CastInst::castIsValid(Instruction::BitCast, + Constant::getNullValue(Int32PtrAS1Ty), + Int32PtrAS2Ty, DL)); + // Bit casting scalable vectors to scalable vectors. EXPECT_TRUE(CastInst::castIsValid(Instruction::BitCast, Constant::getNullValue(VScaleV4Int16Ty),