[OpaquePtr] Make loads and stores work with opaque pointers

Don't check that types match when the pointer operand is an opaque
pointer.

I would separate the Assembler and Verifier changes, but
verify-uselistorder in the Assembler test ends up running the verifier.

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D102450
This commit is contained in:
Arthur Eubanks 2021-05-13 15:44:21 -07:00
parent 832f7af283
commit 6013d84392
7 changed files with 49 additions and 12 deletions

View File

@ -676,6 +676,14 @@ public:
/// 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;

View File

@ -7483,7 +7483,7 @@ int LLParser::parseLoad(Instruction *&Inst, PerFunctionState &PFS) {
Ordering == AtomicOrdering::AcquireRelease)
return error(Loc, "atomic load cannot use Release ordering");
if (Ty != cast<PointerType>(Val->getType())->getElementType()) {
if (!cast<PointerType>(Val->getType())->isOpaqueOrPointeeTypeMatches(Ty)) {
return error(
ExplicitTypeLoc,
typeComparisonErrorMessage(
@ -7534,7 +7534,8 @@ int LLParser::parseStore(Instruction *&Inst, PerFunctionState &PFS) {
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<PointerType>(Ptr->getType())->getElementType() != Val->getType())
if (!cast<PointerType>(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");

View File

@ -3844,12 +3844,11 @@ Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata,
Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) {
if (!isa<PointerType>(PtrType))
return error("Load/Store operand is not a pointer type");
Type *ElemType = cast<PointerType>(PtrType)->getElementType();
if (ValType && ValType != ElemType)
if (!cast<PointerType>(PtrType)->isOpaqueOrPointeeTypeMatches(ValType))
return error("Explicit load/store type does not match pointee "
"type of pointer operand");
if (!PointerType::isLoadableOrStorableType(ElemType))
if (!PointerType::isLoadableOrStorableType(ValType))
return error("Cannot load/store from pointer");
return Error::success();
}

View File

@ -1436,7 +1436,7 @@ LoadInst::LoadInst(Type *Ty, Value *Ptr, const Twine &Name, bool isVolatile,
Align Align, AtomicOrdering Order, SyncScope::ID SSID,
Instruction *InsertBef)
: UnaryInstruction(Ty, Load, Ptr, InsertBef) {
assert(Ty == cast<PointerType>(Ptr->getType())->getElementType());
assert(cast<PointerType>(Ptr->getType())->isOpaqueOrPointeeTypeMatches(Ty));
setVolatile(isVolatile);
setAlignment(Align);
setAtomic(Order, SSID);
@ -1448,7 +1448,7 @@ LoadInst::LoadInst(Type *Ty, Value *Ptr, const Twine &Name, bool isVolatile,
Align Align, AtomicOrdering Order, SyncScope::ID SSID,
BasicBlock *InsertAE)
: UnaryInstruction(Ty, Load, Ptr, InsertAE) {
assert(Ty == cast<PointerType>(Ptr->getType())->getElementType());
assert(cast<PointerType>(Ptr->getType())->isOpaqueOrPointeeTypeMatches(Ty));
setVolatile(isVolatile);
setAlignment(Align);
setAtomic(Order, SSID);
@ -1464,9 +1464,9 @@ void StoreInst::AssertOK() {
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<PointerType>(getOperand(1)->getType())->getElementType()
&& "Ptr must be a pointer to Val type!");
assert(cast<PointerType>(getOperand(1)->getType())
->isOpaqueOrPointeeTypeMatches(getOperand(0)->getType()) &&
"Ptr must be a pointer to Val type!");
assert(!(isAtomic() && getAlignment() == 0) &&
"Alignment required for atomic store");
}

View File

@ -3753,8 +3753,8 @@ void Verifier::visitLoadInst(LoadInst &LI) {
void Verifier::visitStoreInst(StoreInst &SI) {
PointerType *PTy = dyn_cast<PointerType>(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);

View File

@ -24,3 +24,19 @@ define ptr addrspace(2) @g2(ptr addrspace(0) %a) {
%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
}

View File

@ -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
}