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 @@ -7664,7 +7664,8 @@ return tokError("atomicrmw cannot be unordered"); if (!Ptr->getType()->isPointerTy()) return error(PtrLoc, "atomicrmw operand must be a pointer"); - if (cast(Ptr->getType())->getElementType() != Val->getType()) + if (!cast(Ptr->getType()) + ->isOpaqueOrPointeeTypeMatches(Val->getType())) return error(ValLoc, "atomicrmw value and pointer type do not match"); if (Operation == AtomicRMWInst::Xchg) { 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 @@ -5230,15 +5230,18 @@ unsigned OpNum = 0; Value *Ptr = nullptr; - if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy)) + if (getValueTypePair(Record, OpNum, NextValueNo, Ptr)) return error("Invalid record"); if (!isa(Ptr->getType())) return error("Invalid record"); Value *Val = nullptr; - if (popValue(Record, OpNum, NextValueNo, - getPointerElementFlatType(FullTy), Val)) + if (popValue(Record, OpNum, NextValueNo, nullptr, Val)) + return error("Invalid record"); + + if (!cast(Ptr->getType()) + ->isOpaqueOrPointeeTypeMatches(Val->getType())) return error("Invalid record"); if (!(NumRecords == (OpNum + 4) || NumRecords == (OpNum + 5))) @@ -5271,7 +5274,6 @@ Align(TheModule->getDataLayout().getTypeStoreSize(Val->getType())); I = new AtomicRMWInst(Operation, Ptr, Val, *Alignment, Ordering, SSID); - FullTy = getPointerElementFlatType(FullTy); cast(I)->setVolatile(IsVol); InstructionList.push_back(I); 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 @@ -1607,9 +1607,9 @@ "All operands must be non-null!"); assert(getOperand(0)->getType()->isPointerTy() && "Ptr must have pointer type!"); - assert(getOperand(1)->getType() == - cast(getOperand(0)->getType())->getElementType() - && "Ptr must be a pointer to Val type!"); + assert(cast(getOperand(0)->getType()) + ->isOpaqueOrPointeeTypeMatches(getOperand(1)->getType()) && + "Ptr must be a pointer to Val type!"); assert(Ordering != AtomicOrdering::NotAtomic && "AtomicRMW instructions must be atomic!"); } 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 @@ -3867,7 +3867,7 @@ auto Op = RMWI.getOperation(); PointerType *PTy = dyn_cast(RMWI.getOperand(0)->getType()); Assert(PTy, "First atomicrmw operand must be a pointer.", &RMWI); - Type *ElTy = PTy->getElementType(); + Type *ElTy = RMWI.getOperand(1)->getType(); if (Op == AtomicRMWInst::Xchg) { Assert(ElTy->isIntegerTy() || ElTy->isFloatingPointTy(), "atomicrmw " + AtomicRMWInst::getOperationName(Op) + @@ -3885,7 +3885,7 @@ &RMWI, ElTy); } checkAtomicMemAccessSize(ElTy, &RMWI); - Assert(ElTy == RMWI.getOperand(1)->getType(), + Assert(PTy->isOpaqueOrPointeeTypeMatches(ElTy), "Argument value type does not match pointer operand type!", &RMWI, ElTy); Assert(AtomicRMWInst::FIRST_BINOP <= Op && Op <= AtomicRMWInst::LAST_BINOP, 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 @@ -40,3 +40,11 @@ store i32 %i, ptr %a ret void } + +; CHECK: define void @atomicrmw(ptr %a, i32 %i) +; CHECK: %b = atomicrmw add ptr %a, i32 %i acquire +; CHECK: ret void +define void @atomicrmw(ptr %a, i32 %i) { + %b = atomicrmw add ptr %a, i32 %i acquire + ret void +} diff --git a/llvm/test/Verifier/opaque-ptr.ll b/llvm/test/Verifier/opaque-ptr.ll --- a/llvm/test/Verifier/opaque-ptr.ll +++ b/llvm/test/Verifier/opaque-ptr.ll @@ -11,3 +11,9 @@ store i32 %i, ptr %a ret void } + +; CHECK: @atomicrmw +define void @atomicrmw(ptr %a, i32 %i) { + %b = atomicrmw add ptr %a, i32 %i acquire + ret void +}