diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h --- a/llvm/include/llvm/IR/DerivedTypes.h +++ b/llvm/include/llvm/IR/DerivedTypes.h @@ -670,12 +670,17 @@ /// Return true if the specified type is valid as a element type. static bool isValidElementType(Type *ElemTy); - /// Return true if we can load or store from a pointer to this type. - static bool isLoadableOrStorableType(Type *ElemTy); - /// Return the address space of the Pointer type. inline unsigned getAddressSpace() const { return getSubclassData(); } + /// Return true if either this is an opaque pointer type or if this pointee + /// type matches Ty. Primarily used for checking if an instruction's pointer + /// operands are valid types. Will be useless after non-opaque pointers are + /// removed. + bool isOpaqueOrPointeeTypeMatches(Type *Ty) { + return isOpaque() || PointeeTy == Ty; + } + /// Implement support type inquiry through isa, cast, and dyn_cast. static bool classof(const Type *T) { return T->getTypeID() == PointerTyID; diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -7483,7 +7483,7 @@ Ordering == AtomicOrdering::AcquireRelease) return error(Loc, "atomic load cannot use Release ordering"); - if (Ty != cast(Val->getType())->getElementType()) { + if (!cast(Val->getType())->isOpaqueOrPointeeTypeMatches(Ty)) { return error( ExplicitTypeLoc, typeComparisonErrorMessage( @@ -7534,7 +7534,8 @@ return error(PtrLoc, "store operand must be a pointer"); if (!Val->getType()->isFirstClassType()) return error(Loc, "store operand must be a first class value"); - if (cast(Ptr->getType())->getElementType() != Val->getType()) + if (!cast(Ptr->getType()) + ->isOpaqueOrPointeeTypeMatches(Val->getType())) return error(Loc, "stored value and pointer type do not match"); if (isAtomic && !Alignment) return error(Loc, "atomic store must have explicit non-zero alignment"); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3844,12 +3844,11 @@ Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) { if (!isa(PtrType)) return error("Load/Store operand is not a pointer type"); - Type *ElemType = cast(PtrType)->getElementType(); - if (ValType && ValType != ElemType) + if (!cast(PtrType)->isOpaqueOrPointeeTypeMatches(ValType)) return error("Explicit load/store type does not match pointee " "type of pointer operand"); - if (!PointerType::isLoadableOrStorableType(ElemType)) + if (!ValType->isFunctionTy()) return error("Cannot load/store from pointer"); return Error::success(); } diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -1436,7 +1436,7 @@ Align Align, AtomicOrdering Order, SyncScope::ID SSID, Instruction *InsertBef) : UnaryInstruction(Ty, Load, Ptr, InsertBef) { - assert(Ty == cast(Ptr->getType())->getElementType()); + assert(cast(Ptr->getType())->isOpaqueOrPointeeTypeMatches(Ty)); setVolatile(isVolatile); setAlignment(Align); setAtomic(Order, SSID); @@ -1448,7 +1448,7 @@ Align Align, AtomicOrdering Order, SyncScope::ID SSID, BasicBlock *InsertAE) : UnaryInstruction(Ty, Load, Ptr, InsertAE) { - assert(Ty == cast(Ptr->getType())->getElementType()); + assert(cast(Ptr->getType())->isOpaqueOrPointeeTypeMatches(Ty)); setVolatile(isVolatile); setAlignment(Align); setAtomic(Order, SSID); @@ -1464,9 +1464,9 @@ assert(getOperand(0) && getOperand(1) && "Both operands must be non-null!"); assert(getOperand(1)->getType()->isPointerTy() && "Ptr must have pointer type!"); - assert(getOperand(0)->getType() == - cast(getOperand(1)->getType())->getElementType() - && "Ptr must be a pointer to Val type!"); + assert(cast(getOperand(1)->getType()) + ->isOpaqueOrPointeeTypeMatches(getOperand(0)->getType()) && + "Ptr must be a pointer to Val type!"); assert(!(isAtomic() && getAlignment() == 0) && "Alignment required for atomic store"); } diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -735,7 +735,3 @@ !ElemTy->isX86_AMXTy() && !(ElemTy->isPointerTy() && cast(ElemTy)->isOpaque()); } - -bool PointerType::isLoadableOrStorableType(Type *ElemTy) { - return isValidElementType(ElemTy) && !ElemTy->isFunctionTy(); -} diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3753,8 +3753,8 @@ void Verifier::visitStoreInst(StoreInst &SI) { PointerType *PTy = dyn_cast(SI.getOperand(1)->getType()); Assert(PTy, "Store operand must be a pointer.", &SI); - Type *ElTy = PTy->getElementType(); - Assert(ElTy == SI.getOperand(0)->getType(), + Type *ElTy = SI.getOperand(0)->getType(); + Assert(PTy->isOpaqueOrPointeeTypeMatches(ElTy), "Stored value type does not match pointer operand type!", &SI, ElTy); Assert(SI.getAlignment() <= Value::MaximumAlignment, "huge alignment values are unsupported", &SI); diff --git a/llvm/test/Assembler/opaque-ptr.ll b/llvm/test/Assembler/opaque-ptr.ll --- a/llvm/test/Assembler/opaque-ptr.ll +++ b/llvm/test/Assembler/opaque-ptr.ll @@ -24,3 +24,19 @@ %b = addrspacecast ptr addrspace(0) %a to ptr addrspace(2) ret ptr addrspace(2) %b } + +; CHECK: define i32 @load(ptr %a) +; CHECK: %i = load i32, ptr %a +; CHECK: ret i32 %i +define i32 @load(ptr %a) { + %i = load i32, ptr %a + ret i32 %i +} + +; CHECK: define void @store(ptr %a, i32 %i) +; CHECK: store i32 %i, ptr %a +; CHECK: ret void +define void @store(ptr %a, i32 %i) { + store i32 %i, ptr %a + ret void +} diff --git a/llvm/test/Verifier/opaque-ptr.ll b/llvm/test/Verifier/opaque-ptr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/opaque-ptr.ll @@ -0,0 +1,13 @@ +; RUN: opt -passes=verify -S < %s | FileCheck %s + +; CHECK: @load +define i32 @load(ptr %a) { + %i = load i32, ptr %a + ret i32 %i +} + +; CHECK: @store +define void @store(ptr %a, i32 %i) { + store i32 %i, ptr %a + ret void +}