[OpaquePtr] Make loads and stores work with opaque pointers
authorArthur Eubanks <aeubanks@google.com>
Thu, 13 May 2021 22:44:21 +0000 (15:44 -0700)
committerArthur Eubanks <aeubanks@google.com>
Tue, 18 May 2021 20:43:50 +0000 (13:43 -0700)
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

llvm/include/llvm/IR/DerivedTypes.h
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/Bitcode/Reader/BitcodeReader.cpp
llvm/lib/IR/Instructions.cpp
llvm/lib/IR/Verifier.cpp
llvm/test/Assembler/opaque-ptr.ll
llvm/test/Verifier/opaque-ptr.ll [new file with mode: 0644]

index 1566b42..1904f82 100644 (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;
index ca3efa8..2f85e8d 100644 (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");
index 25edf24..b2794b3 100644 (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();
 }
index 6abe913..134a023 100644 (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");
 }
index de28c26..986d7ec 100644 (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);
index 82fcf9f..95a5a53 100644 (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
+}
diff --git a/llvm/test/Verifier/opaque-ptr.ll b/llvm/test/Verifier/opaque-ptr.ll
new file mode 100644 (file)
index 0000000..ff25a8c
--- /dev/null
@@ -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
+}