Skip to content

Conversation

@boomanaiden154
Copy link
Contributor

No description provided.

Created using spr 1.3.7
@llvmbot llvmbot added clang:codegen IR generation bugs: mangling, exceptions, etc. llvm:ir llvm:transforms labels Dec 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 22, 2025

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-llvm-transforms

Author: Aiden Grossman (boomanaiden154)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/173294.diff

13 Files Affected:

  • (modified) clang/lib/CodeGen/CGCall.cpp (+1-1)
  • (modified) llvm/include/llvm/AsmParser/LLParser.h (+3-1)
  • (modified) llvm/include/llvm/IR/Argument.h (+4-2)
  • (modified) llvm/include/llvm/IR/Attributes.h (+7-6)
  • (modified) llvm/include/llvm/IR/Function.h (+1-1)
  • (modified) llvm/lib/AsmParser/LLParser.cpp (+19-11)
  • (modified) llvm/lib/IR/AttributeImpl.h (+1-1)
  • (modified) llvm/lib/IR/Attributes.cpp (+21-9)
  • (modified) llvm/lib/IR/Function.cpp (+1-1)
  • (modified) llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp (+2-1)
  • (modified) llvm/test/Bitcode/attributes.ll (+7-2)
  • (modified) llvm/test/Bitcode/dead-on-return-upgrade.ll (+1-1)
  • (modified) llvm/test/Transforms/DeadStoreElimination/simple.ll (+3-3)
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 4a9025b6e0b0f..6a04f16677131 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -2884,7 +2884,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
           // (e.g., Obj-C ARC-managed structs, MSVC callee-destroyed objects).
           if (!ParamType.isDestructedType() || !ParamType->isRecordType() ||
               ParamType->castAsRecordDecl()->isParamDestroyedInCallee())
-            Attrs.addAttribute(llvm::Attribute::DeadOnReturn);
+            Attrs.addDeadOnReturnAttr(std::nullopt);
         }
       }
 
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index f94d7c7644427..b792155206f05 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -319,7 +319,9 @@ namespace llvm {
     bool parseOptionalAlignment(MaybeAlign &Alignment,
                                 bool AllowParens = false);
     bool parseOptionalCodeModel(CodeModel::Model &model);
-    bool parseOptionalAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
+    bool parseOptionalAttrBytes(lltok::Kind AttrKind,
+                                std::optional<uint64_t> &Bytes,
+                                bool ErrorNoBytes = false);
     bool parseOptionalUWTableKind(UWTableKind &Kind);
     bool parseAllocKind(AllocFnKind &Kind);
     std::optional<MemoryEffects> parseMemoryAttr();
diff --git a/llvm/include/llvm/IR/Argument.h b/llvm/include/llvm/IR/Argument.h
index df380919629fe..d70459aa80639 100644
--- a/llvm/include/llvm/IR/Argument.h
+++ b/llvm/include/llvm/IR/Argument.h
@@ -78,8 +78,10 @@ class Argument final : public Value {
   /// Return true if this argument has the byval attribute.
   LLVM_ABI bool hasByValAttr() const;
 
-  /// Return true if this argument has the dead_on_return attribute.
-  LLVM_ABI uint64_t getDeadOnReturnBytes() const;
+  /// Return the number of bytes marked dead by the dead_on_return attribute.
+  /// If no count was specified (implying all memory reachable through the
+  /// pointer is marked dead on return), std::nullopt is returned.
+  LLVM_ABI std::optional<uint64_t> getDeadOnReturnBytes() const;
 
   /// Return true if this argument has the byref attribute.
   LLVM_ABI bool hasByRefAttr() const;
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 241c5060ec6cf..6366f98cc91ad 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -276,9 +276,10 @@ class Attribute {
   /// dereferenceable attribute.
   LLVM_ABI uint64_t getDereferenceableBytes() const;
 
-  /// Returns the number of dead_on_return bytes from the
-  /// dead_on_return attribute.
-  LLVM_ABI uint64_t getDeadOnReturnBytes() const;
+  /// Returns the number of dead_on_return bytes from the dead_on_return
+  /// attribute, or std::nullopt if all memory reachable through the pointer is
+  /// marked dead on return.
+  LLVM_ABI std::optional<uint64_t> getDeadOnReturnBytes() const;
 
   /// Returns the number of dereferenceable_or_null bytes from the
   /// dereferenceable_or_null attribute.
@@ -449,7 +450,7 @@ class AttributeSet {
   LLVM_ABI MaybeAlign getAlignment() const;
   LLVM_ABI MaybeAlign getStackAlignment() const;
   LLVM_ABI uint64_t getDereferenceableBytes() const;
-  LLVM_ABI uint64_t getDeadOnReturnBytes() const;
+  LLVM_ABI std::optional<uint64_t> getDeadOnReturnBytes() const;
   LLVM_ABI uint64_t getDereferenceableOrNullBytes() const;
   LLVM_ABI Type *getByValType() const;
   LLVM_ABI Type *getStructRetType() const;
@@ -970,7 +971,7 @@ class AttributeList {
   LLVM_ABI uint64_t getRetDereferenceableOrNullBytes() const;
 
   /// Get the number of dead_on_return bytes (or zero if unknown) of an arg.
-  LLVM_ABI uint64_t getDeadOnReturnBytes(unsigned Index) const;
+  LLVM_ABI std::optional<uint64_t> getDeadOnReturnBytes(unsigned Index) const;
 
   /// Get the number of dereferenceable_or_null bytes (or zero if unknown) of an
   /// arg.
@@ -1252,7 +1253,7 @@ class AttrBuilder {
 
   /// This turns the number of dead_on_return bytes into the form used
   /// internally in Attribute.
-  LLVM_ABI AttrBuilder &addDeadOnReturnAttr(uint64_t Bytes);
+  LLVM_ABI AttrBuilder &addDeadOnReturnAttr(std::optional<uint64_t> Bytes);
 
   /// This turns the number of dereferenceable_or_null bytes into the
   /// form used internally in Attribute.
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index 48b1604bdea32..ba4eff5b7d546 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -525,7 +525,7 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
 
   /// Extract the number of dead_on_return bytes for a parameter.
   /// @param ArgNo Index of an argument, with 0 being the first function arg.
-  uint64_t getDeadOnReturnBytes(unsigned ArgNo) const {
+  std::optional<uint64_t> getDeadOnReturnBytes(unsigned ArgNo) const {
     return AttributeSets.getDeadOnReturnBytes(ArgNo);
   }
 
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 148e0dad8e5c3..a6a9f0629bc25 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -1606,24 +1606,26 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
     return false;
   }
   case Attribute::Dereferenceable: {
-    uint64_t Bytes;
+    std::optional<uint64_t> Bytes;
     if (parseOptionalAttrBytes(lltok::kw_dereferenceable, Bytes))
       return true;
-    B.addDereferenceableAttr(Bytes);
+    assert(Bytes.has_value());
+    B.addDereferenceableAttr(Bytes.value());
     return false;
   }
   case Attribute::DeadOnReturn: {
-    uint64_t Bytes;
+    std::optional<uint64_t> Bytes;
     if (parseOptionalAttrBytes(lltok::kw_dead_on_return, Bytes))
       return true;
     B.addDeadOnReturnAttr(Bytes);
     return false;
   }
   case Attribute::DereferenceableOrNull: {
-    uint64_t Bytes;
+    std::optional<uint64_t> Bytes;
     if (parseOptionalAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
       return true;
-    B.addDereferenceableOrNullAttr(Bytes);
+    assert(Bytes.has_value());
+    B.addDereferenceableOrNullAttr(Bytes.value());
     return false;
   }
   case Attribute::UWTable: {
@@ -2481,7 +2483,9 @@ bool LLParser::parseOptionalCodeModel(CodeModel::Model &model) {
 ///
 /// where AttrKind is either 'dereferenceable', 'dereferenceable_or_null', or
 /// 'dead_on_return'
-bool LLParser::parseOptionalAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes) {
+bool LLParser::parseOptionalAttrBytes(lltok::Kind AttrKind,
+                                      std::optional<uint64_t> &Bytes,
+                                      bool ErrorNoBytes) {
   assert((AttrKind == lltok::kw_dereferenceable ||
           AttrKind == lltok::kw_dereferenceable_or_null ||
           AttrKind == lltok::kw_dead_on_return) &&
@@ -2491,16 +2495,20 @@ bool LLParser::parseOptionalAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes) {
   if (!EatIfPresent(AttrKind))
     return false;
   LocTy ParenLoc = Lex.getLoc();
-  if (!EatIfPresent(lltok::lparen))
-    return error(ParenLoc, "expected '('");
+  if (!EatIfPresent(lltok::lparen)) {
+    if (ErrorNoBytes)
+      return error(ParenLoc, "expected '('");
+    Bytes = std::nullopt;
+    return false;
+  }
   LocTy DerefLoc = Lex.getLoc();
-  if (parseUInt64(Bytes))
+  if (parseUInt64(Bytes.value()))
     return true;
   ParenLoc = Lex.getLoc();
   if (!EatIfPresent(lltok::rparen))
     return error(ParenLoc, "expected ')'");
-  if (!Bytes)
-    return error(DerefLoc, "dereferenceable bytes must be non-zero");
+  if (!Bytes.value())
+    return error(DerefLoc, "byte count specified must be non-zero");
   return false;
 }
 
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index da216458d0b19..b23e8166dc757 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -332,7 +332,7 @@ class AttributeSetNode final
   MaybeAlign getAlignment() const;
   MaybeAlign getStackAlignment() const;
   uint64_t getDereferenceableBytes() const;
-  uint64_t getDeadOnReturnBytes() const;
+  std::optional<uint64_t> getDeadOnReturnBytes() const;
   uint64_t getDereferenceableOrNullBytes() const;
   std::optional<std::pair<unsigned, std::optional<unsigned>>> getAllocSizeArgs()
       const;
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 87d30672de956..7fc1773726192 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -451,11 +451,14 @@ uint64_t Attribute::getDereferenceableBytes() const {
   return pImpl->getValueAsInt();
 }
 
-uint64_t Attribute::getDeadOnReturnBytes() const {
+std::optional<uint64_t> Attribute::getDeadOnReturnBytes() const {
   assert(hasAttribute(Attribute::DeadOnReturn) &&
          "Trying to get dead_on_return bytes from"
          "from a parameter without such an attribute!");
-  return pImpl->getValueAsInt();
+  uint64_t DeadBytes = pImpl->getValueAsInt();
+  if (DeadBytes == std::numeric_limits<uint64_t>::max())
+    return std::nullopt;
+  return DeadBytes;
 }
 
 uint64_t Attribute::getDereferenceableOrNullBytes() const {
@@ -581,8 +584,12 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
   if (hasAttribute(Attribute::DereferenceableOrNull))
     return AttrWithBytesToString("dereferenceable_or_null");
 
-  if (hasAttribute(Attribute::DeadOnReturn))
+  if (hasAttribute(Attribute::DeadOnReturn)) {
+    uint64_t DeadBytes = getValueAsInt();
+    if (DeadBytes == std::numeric_limits<uint64_t>::max())
+      return "dead_on_return";
     return AttrWithBytesToString("dead_on_return");
+  }
 
   if (hasAttribute(Attribute::AllocSize)) {
     unsigned ElemSize;
@@ -1172,7 +1179,7 @@ uint64_t AttributeSet::getDereferenceableBytes() const {
   return SetNode ? SetNode->getDereferenceableBytes() : 0;
 }
 
-uint64_t AttributeSet::getDeadOnReturnBytes() const {
+std::optional<uint64_t> AttributeSet::getDeadOnReturnBytes() const {
   return SetNode ? SetNode->getDeadOnReturnBytes() : 0;
 }
 
@@ -1380,7 +1387,7 @@ uint64_t AttributeSetNode::getDereferenceableBytes() const {
   return 0;
 }
 
-uint64_t AttributeSetNode::getDeadOnReturnBytes() const {
+std::optional<uint64_t> AttributeSetNode::getDeadOnReturnBytes() const {
   if (auto A = findEnumAttribute(Attribute::DeadOnReturn))
     return A->getDeadOnReturnBytes();
   return 0;
@@ -2003,7 +2010,8 @@ uint64_t AttributeList::getRetDereferenceableOrNullBytes() const {
   return getRetAttrs().getDereferenceableOrNullBytes();
 }
 
-uint64_t AttributeList::getDeadOnReturnBytes(unsigned Index) const {
+std::optional<uint64_t>
+AttributeList::getDeadOnReturnBytes(unsigned Index) const {
   return getParamAttrs(Index).getDeadOnReturnBytes();
 }
 
@@ -2229,11 +2237,15 @@ AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
   return addRawIntAttr(Attribute::Dereferenceable, Bytes);
 }
 
-AttrBuilder &AttrBuilder::addDeadOnReturnAttr(uint64_t Bytes) {
-  if (Bytes == 0)
+AttrBuilder &AttrBuilder::addDeadOnReturnAttr(std::optional<uint64_t> Bytes) {
+  if (!Bytes.has_value())
+    return addRawIntAttr(Attribute::DeadOnReturn,
+                         std::numeric_limits<uint64_t>::max());
+
+  if (Bytes.value() == 0)
     return *this;
 
-  return addRawIntAttr(Attribute::DeadOnReturn, Bytes);
+  return addRawIntAttr(Attribute::DeadOnReturn, Bytes.value());
 }
 
 AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index d4e80762919c8..78578ac223e66 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -130,7 +130,7 @@ bool Argument::hasByValAttr() const {
   return hasAttribute(Attribute::ByVal);
 }
 
-uint64_t Argument::getDeadOnReturnBytes() const {
+std::optional<uint64_t> Argument::getDeadOnReturnBytes() const {
   assert(getType()->isPointerTy() && "Only pointers have dead_on_return bytes");
   return getParent()->getDeadOnReturnBytes(getArgNo());
 }
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 16ab2d5f63dd5..51a27993af270 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1018,7 +1018,8 @@ struct DSEState {
     // stores to them are dead at the end of the function.
     for (Argument &AI : F.args())
       if (AI.hasPassPointeeByValueCopyAttr() ||
-          (AI.getType()->isPointerTy() && AI.getDeadOnReturnBytes() > 0))
+          (AI.getType()->isPointerTy() &&
+           !AI.getDeadOnReturnBytes().has_value()))
         InvisibleToCallerAfterRet.insert({&AI, true});
 
     // Collect whether there is any irreducible control flow in the function.
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index e908d95215c7d..4f234d7a40079 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -577,8 +577,13 @@ define void @captures(ptr captures(address) %p) {
   ret void
 }
 
-; CHECK: define void @dead_on_return(ptr dead_on_return(4) %p)
-define void @dead_on_return(ptr dead_on_return(4) %p) {
+; CHECK: define void @dead_on_return(ptr dead_on_return %p)
+define void @dead_on_return(ptr dead_on_return %p) {
+  ret void
+}
+
+; CHECK: define void @dead_on_return_sized(ptr dead_on_return(4) %p)
+define void @dead_on_return_sized(ptr dead_on_return(4) %p) {
   ret void
 }
 
diff --git a/llvm/test/Bitcode/dead-on-return-upgrade.ll b/llvm/test/Bitcode/dead-on-return-upgrade.ll
index d3fa2b8f91108..ddf70f453091e 100644
--- a/llvm/test/Bitcode/dead-on-return-upgrade.ll
+++ b/llvm/test/Bitcode/dead-on-return-upgrade.ll
@@ -1,6 +1,6 @@
 ; RUN: llvm-dis -o - %s.bc | FileCheck %s
 
-; CHECK: define void @test_dead_on_return_autoupgrade(ptr dead_on_return(18446744073709551615) %p) {
+; CHECK: define void @test_dead_on_return_autoupgrade(ptr dead_on_return %p) {
 
 define void @test_dead_on_return_autoupgrade(ptr dead_on_return %p) {
   ret void
diff --git a/llvm/test/Transforms/DeadStoreElimination/simple.ll b/llvm/test/Transforms/DeadStoreElimination/simple.ll
index c9f43c6a574bc..9d28395a4ccd0 100644
--- a/llvm/test/Transforms/DeadStoreElimination/simple.ll
+++ b/llvm/test/Transforms/DeadStoreElimination/simple.ll
@@ -856,7 +856,7 @@ bb:
   ret void
 }
 
-define void @test_dead_on_return(ptr dead_on_return(4) %p) {
+define void @test_dead_on_return(ptr dead_on_return %p) {
 ; CHECK-LABEL: @test_dead_on_return(
 ; CHECK-NEXT:    ret void
 ;
@@ -864,7 +864,7 @@ define void @test_dead_on_return(ptr dead_on_return(4) %p) {
   ret void
 }
 
-define void @test_dead_on_return_maythrow(ptr dead_on_return(4) %p) {
+define void @test_dead_on_return_maythrow(ptr dead_on_return %p) {
 ; CHECK-LABEL: @test_dead_on_return_maythrow(
 ; CHECK-NEXT:    call void @maythrow()
 ; CHECK-NEXT:    ret void
@@ -874,7 +874,7 @@ define void @test_dead_on_return_maythrow(ptr dead_on_return(4) %p) {
   ret void
 }
 
-define ptr @test_dead_on_return_ptr_returned(ptr dead_on_return(64) %p) {
+define ptr @test_dead_on_return_ptr_returned(ptr dead_on_return %p) {
 ; CHECK-LABEL: @test_dead_on_return_ptr_returned(
 ; CHECK-NEXT:    [[LOCAL_VAR:%.*]] = alloca ptr, align 8
 ; CHECK-NEXT:    call void @opaque(ptr [[LOCAL_VAR]])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:codegen IR generation bugs: mangling, exceptions, etc. llvm:ir llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants