diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h index 677137271974..179aa579fa96 100644 --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -1818,14 +1818,14 @@ class CallBase : public Instruction { /// Determine if the call does not access or only reads memory. bool onlyReadsMemory() const { - return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly); + return hasImpliedFnAttr(Attribute::ReadOnly); } void setOnlyReadsMemory() { addFnAttr(Attribute::ReadOnly); } /// Determine if the call does not access or only writes memory. bool onlyWritesMemory() const { - return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); + return hasImpliedFnAttr(Attribute::WriteOnly); } void setOnlyWritesMemory() { addFnAttr(Attribute::WriteOnly); } @@ -2288,6 +2288,26 @@ class CallBase : public Instruction { return hasFnAttrOnCalledFunction(Kind); } + /// A specialized version of hasFnAttrImpl for when the caller wants to + /// know if an attribute's semantics are implied, not whether the attribute + /// is actually present. This distinction only exists when checking whether + /// something is readonly or writeonly since readnone implies both. The case + /// which motivates the specialized code is a callee with readnone, and an + /// operand bundle on the call which disallows readnone but not either + /// readonly or writeonly. + bool hasImpliedFnAttr(Attribute::AttrKind Kind) const { + assert((Kind == Attribute::ReadOnly || Kind == Attribute::WriteOnly) && + "use hasFnAttrImpl instead"); + if (Attrs.hasFnAttr(Kind) || Attrs.hasFnAttr(Attribute::ReadNone)) + return true; + + if (isFnAttrDisallowedByOpBundle(Kind)) + return false; + + return hasFnAttrOnCalledFunction(Kind) || + hasFnAttrOnCalledFunction(Attribute::ReadNone); + } + /// Determine whether the return value has the given attribute. Supports /// Attribute::AttrKind and StringRef as \p AttrKind types. template bool hasRetAttrImpl(AttrKind Kind) const { diff --git a/llvm/test/Transforms/InstCombine/trivial-dse-calls.ll b/llvm/test/Transforms/InstCombine/trivial-dse-calls.ll index 5e89789a0e23..29755575ddd9 100644 --- a/llvm/test/Transforms/InstCombine/trivial-dse-calls.ll +++ b/llvm/test/Transforms/InstCombine/trivial-dse-calls.ll @@ -253,7 +253,6 @@ define void @test_readnone() { define void @test_readnone_with_deopt() { ; CHECK-LABEL: @test_readnone_with_deopt( -; CHECK-NEXT: call void @removable_readnone() [ "deopt"() ] ; CHECK-NEXT: ret void ; call void @removable_readnone() [ "deopt"() ]