[llvm-branch-commits] [llvm] llvm-reduce: Change function return types if function is not called (PR #134035)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri May 2 03:09:33 PDT 2025


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/134035

>From 3575aa56fba108e376621c7d5b195ccca9483ef4 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 2 Apr 2025 11:45:24 +0700
Subject: [PATCH 1/4] llvm-reduce: Change function return types if function is
 not called

Extend the early return on value reduction to mutate the function return
type if the function has no call uses. This could be generalized to rewrite
cases where all callsites are used, but it turns out that complicates the
visitation order given we try to compute all opportunities up front.

This is enough to cleanup the common case where we end up with one
function with a return of an uninteresting constant.
---
 .../reduce-instructions-to-return.ll          | 20 +++-
 ...reduce-values-to-return-new-return-type.ll | 95 +++++++++++++++++++
 .../deltas/ReduceValuesToReturn.cpp           |  7 +-
 3 files changed, 118 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll

diff --git a/llvm/test/tools/llvm-reduce/reduce-instructions-to-return.ll b/llvm/test/tools/llvm-reduce/reduce-instructions-to-return.ll
index 2af87aad05169..77501418f5283 100644
--- a/llvm/test/tools/llvm-reduce/reduce-instructions-to-return.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-instructions-to-return.ll
@@ -196,13 +196,25 @@ define i32 @callsite_already_new_return_type(ptr %arg) {
 ; INTERESTING: ret
 
 ; RESULT-LABEL: define ptr @non_void_no_op(
-; RESULT: ret ptr null
+; RESULT-NEXT: %load = load i32, ptr %arg
+; RESULT-NEXT: store i32 %load, ptr @gv
+; RESULT-NEXT: ret ptr null
 define ptr @non_void_no_op(ptr %arg) {
   %load = load i32, ptr %arg
   store i32 %load, ptr @gv
   ret ptr null
 }
 
+; INTERESTING-LABEL: @non_void_no_op_caller(
+
+; RESULT-LABEL: define ptr @non_void_no_op_caller(ptr %arg) {
+; RESULT-NEXT: %call = call ptr @non_void_no_op(ptr %arg)
+; RESULT-NEXT: ret ptr %call
+define ptr @non_void_no_op_caller(ptr %arg) {
+  %call = call ptr @non_void_no_op(ptr %arg)
+  ret ptr %call
+}
+
 ; INTERESTING-LABEL: @non_void_same_type_use(
 ; INTERESTING: = load
 ; INTERESTING: ret
@@ -230,6 +242,12 @@ define i32 @non_void_bitcastable_type_use(ptr %arg) {
   ret i32 0
 }
 
+; INTERESTING-LABEL: @non_void_bitcastable_type_use_caller(
+define i32 @non_void_bitcastable_type_use_caller(ptr %arg) {
+  %ret = call i32 @non_void_bitcastable_type_use(ptr %arg)
+  ret i32 %ret
+}
+
 ; INTERESTING-LABEL: @form_return_struct(
 ; INTERESTING: = load { i32, float }
 
diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
new file mode 100644
index 0000000000000..9ddbbe3def44f
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
@@ -0,0 +1,95 @@
+; Test that llvm-reduce can move intermediate values by inserting
+; early returns when the function already has a different return type
+;
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions-to-return --test FileCheck --test-arg --check-prefix=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefix=RESULT %s < %t
+
+
+ at gv = global i32 0, align 4
+ at ptr_array = global [2 x ptr] [ptr @inst_to_return_has_different_type_but_no_func_call_use,
+                               ptr @multiple_callsites_wrong_return_type]
+
+; Should rewrite this return from i64 to i32 since the function has no
+; uses.
+; INTERESTING-LABEL: @inst_to_return_has_different_type_but_no_func_call_use(
+; RESULT-LABEL: define i32 @inst_to_return_has_different_type_but_no_func_call_use(ptr %arg) {
+; RESULT-NEXT: %load = load i32, ptr %arg, align 4
+; RESULT-NEXT: ret i32 %load
+define i64 @inst_to_return_has_different_type_but_no_func_call_use(ptr %arg) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret i64 0
+}
+
+; INTERESTING-LABEL: @callsite_different_type_unused_0(
+; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
+; RESULT-NEXT: %load = load i32, ptr %arg
+; RESULT-NEXT: store i32 %load, ptr @gv
+; RESULT-NEXT: ret i64 0
+define void @callsite_different_type_unused_0(ptr %arg) {
+  %unused0 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
+  %unused1 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr null)
+  ret void
+}
+
+; TODO: Could rewrite this return from i64 to i32 since the callsite is unused.
+; INTERESTING-LABEL: @inst_to_return_has_different_type_but_call_result_unused(
+; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
+; RESULT: ret i64 0
+define i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret i64 0
+}
+
+; INTERESTING-LABEL: @multiple_callsites_wrong_return_type(
+; RESULT-LABEL: define i64 @multiple_callsites_wrong_return_type(
+; RESULT: ret i64 0
+define i64 @multiple_callsites_wrong_return_type(ptr %arg) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret i64 0
+}
+
+; INTERESTING-LABEL: @unused_with_wrong_return_types(
+; RESULT-LABEL: define i64 @unused_with_wrong_return_types(
+; RESULT-NEXT: %unused0 = call i64 @multiple_callsites_wrong_return_type(ptr %arg)
+; RESULT-NEXT: ret i64 %unused0
+define void @unused_with_wrong_return_types(ptr %arg) {
+  %unused0 = call i64 @multiple_callsites_wrong_return_type(ptr %arg)
+  %unused1 = call i32 @multiple_callsites_wrong_return_type(ptr %arg)
+  %unused2 = call ptr @multiple_callsites_wrong_return_type(ptr %arg)
+  ret void
+}
+
+; INTERESTING-LABEL: @multiple_returns_wrong_return_type(
+; INTERESTING: %load0 = load i32,
+
+; RESULT-LABEL: define i32 @multiple_returns_wrong_return_type(
+; RESULT: ret i32
+; RESULT: ret i32
+; RESULT: ret i32
+define i32 @multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2) {
+entry:
+  br i1 %cond, label %bb0, label %bb1
+
+bb0:
+  %load0 = load i32, ptr %arg
+  store i32 %load0, ptr @gv
+  ret i32 234
+
+bb1:
+  ret i32 %arg2
+
+bb2:
+  ret i32 34
+}
+
+; INTERESTING-LABEL: @call_multiple_returns_wrong_return_type(
+; RESULT-LABEL: define <2 x i32> @call_multiple_returns_wrong_return_type(
+; RESULT-NEXT: %unused = call <2 x i32> @multiple_returns_wrong_return_type(
+; RESULT-NEXT: ret <2 x i32> %unused
+define void @call_multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2) {
+  %unused = call <2 x i32> @multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2)
+  ret void
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index 3a00b415b0f09..ceb25c651ce29 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -165,7 +165,9 @@ static bool canReplaceFuncUsers(const Function &F, Type *NewRetTy) {
     if (CB->getType() == NewRetTy)
       continue;
 
-    LLVM_DEBUG(dbgs() << "Cannot replace callsite with wrong type: " << *CB
+    // TODO: If all callsites have no uses, we could mutate the type of all the
+    // callsites. This will complicate the visit and rewrite ordering though.
+    LLVM_DEBUG(dbgs() << "Cannot replace used callsite with wrong type: " << *CB
                       << '\n');
     return false;
   }
@@ -201,8 +203,7 @@ static bool shouldForwardValueToReturn(const BasicBlock &BB, const Value *V,
   if (!isReallyValidReturnType(V->getType()))
     return false;
 
-  return (RetTy->isVoidTy() ||
-          (RetTy == V->getType() && shouldReplaceNonVoidReturnValue(BB, V))) &&
+  return (RetTy->isVoidTy() || shouldReplaceNonVoidReturnValue(BB, V)) &&
          canReplaceFuncUsers(*BB.getParent(), V->getType());
 }
 

>From e43e69236e9292049ed46142df807ea3d6867348 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 2 Apr 2025 13:32:07 +0700
Subject: [PATCH 2/4] Fix multiple return case

---
 ...reduce-values-to-return-new-return-type.ll | 41 ++++++++++++++++---
 .../deltas/ReduceValuesToReturn.cpp           |  2 +-
 2 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
index 9ddbbe3def44f..ae1ef4b5353f1 100644
--- a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
@@ -21,11 +21,38 @@ define i64 @inst_to_return_has_different_type_but_no_func_call_use(ptr %arg) {
   ret i64 0
 }
 
-; INTERESTING-LABEL: @callsite_different_type_unused_0(
-; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
-; RESULT-NEXT: %load = load i32, ptr %arg
-; RESULT-NEXT: store i32 %load, ptr @gv
-; RESULT-NEXT: ret i64 0
+; INTERESTING-LABEL: @multiple_returns_wrong_return_type_no_callers(
+; RESULT-LABEL: define i32 @multiple_returns_wrong_return_type_no_callers(
+
+; RESULT: bb0:
+; RESULT-NEXT: %load0 = load i32,
+; RESULT-NEXT: ret i32 %load0
+
+; RESULT: bb1:
+; RESULT-NEXT: store i32 8, ptr null
+; RESULT-NEXT: ret i32 0
+define i64 @multiple_returns_wrong_return_type_no_callers(ptr %arg, i1 %cond, i64 %arg2) {
+entry:
+  br i1 %cond, label %bb0, label %bb1
+
+bb0:
+  %load0 = load i32, ptr %arg
+  store i32 %load0, ptr @gv
+  ret i64 234
+
+bb1:
+  store i32 8, ptr null
+  ret i64 %arg2
+
+bb2:
+  ret i64 34
+}
+
+; INTERESTING-LABEL: define {{.+}} @callsite_different_type_unused_0(
+
+; RESULT-LABEL: define i64 @callsite_different_type_unused_0(ptr %arg) {
+; RESULT-NEXT: %unused0 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
+; RESULT-NEXT: ret i64 %unused0
 define void @callsite_different_type_unused_0(ptr %arg) {
   %unused0 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
   %unused1 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr null)
@@ -33,8 +60,10 @@ define void @callsite_different_type_unused_0(ptr %arg) {
 }
 
 ; TODO: Could rewrite this return from i64 to i32 since the callsite is unused.
-; INTERESTING-LABEL: @inst_to_return_has_different_type_but_call_result_unused(
+; INTERESTING-LABEL: define {{.+}} @inst_to_return_has_different_type_but_call_result_unused(
 ; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
+; RESULT-NEXT: %load = load i32, ptr %arg
+; RESULT-NEXT: store i32 %load, ptr @gv
 ; RESULT: ret i64 0
 define i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg) {
   %load = load i32, ptr %arg
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index ceb25c651ce29..caf204810a138 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -57,7 +57,7 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
       NewRetI ? NewRetI->getIterator() : EntryBB.end();
 
   // Hack up any return values in other blocks, we can't leave them as ret void.
-  if (OldFuncTy->getReturnType()->isVoidTy()) {
+  if (OldFuncTy->getReturnType() != NewRetTy) {
     for (BasicBlock &OtherRetBB : OldF) {
       if (&OtherRetBB != NewRetBlock) {
         auto *OrigRI = dyn_cast<ReturnInst>(OtherRetBB.getTerminator());

>From 94a608347f2accd879441e3efda76ca8895bfe47 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 2 Apr 2025 14:05:02 +0700
Subject: [PATCH 3/4] Fix return attributes

---
 ...reduce-values-to-return-new-return-type.ll | 35 +++++++++++++++++--
 .../deltas/ReduceValuesToReturn.cpp           | 15 +++++++-
 2 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
index ae1ef4b5353f1..d8c878c5dc7cb 100644
--- a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
@@ -51,10 +51,10 @@ bb2:
 ; INTERESTING-LABEL: define {{.+}} @callsite_different_type_unused_0(
 
 ; RESULT-LABEL: define i64 @callsite_different_type_unused_0(ptr %arg) {
-; RESULT-NEXT: %unused0 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
+; RESULT-NEXT: %unused0 = call range(i64 99, 1024) i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
 ; RESULT-NEXT: ret i64 %unused0
 define void @callsite_different_type_unused_0(ptr %arg) {
-  %unused0 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
+  %unused0 = call range(i64 99, 1024) i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
   %unused1 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr null)
   ret void
 }
@@ -122,3 +122,34 @@ define void @call_multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %ar
   %unused = call <2 x i32> @multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2)
   ret void
 }
+
+; INTERESTING-LABEL: @drop_incompatible_type_return_attrs(
+
+; RESULT-LABEL: define i32 @drop_incompatible_type_return_attrs(ptr %arg, float %arg1) {
+; RESULT-NEXT: %load = load i32, ptr %arg, align 4
+; RESULT-NEXT: ret i32 %load
+define nofpclass(nan inf) float @drop_incompatible_type_return_attrs(ptr %arg, float %arg1) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret float %arg1
+}
+
+; INTERESTING-LABEL: @drop_incompatible_return_range(
+; RESULT-LABEL: define i32 @drop_incompatible_return_range(ptr %arg, i64 %arg1) {
+; RESULT-NEXT: %load = load i32, ptr %arg, align 4
+; RESULT-NEXT: ret i32 %load
+define range(i64 8, 256) i64 @drop_incompatible_return_range(ptr %arg, i64 %arg1) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret i64 %arg1
+}
+
+; INTERESTING-LABEL: @preserve_compatible_return_range(
+; RESULT-LABEL: define range(i32 8, 256) i32 @preserve_compatible_return_range(ptr %arg, <2 x i32> %arg1) {
+; RESULT-NEXT: %load = load i32, ptr %arg, align 4
+; RESULT-NEXT: ret i32 %load
+define range(i32 8, 256) <2 x i32> @preserve_compatible_return_range(ptr %arg, <2 x i32> %arg1) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret <2 x i32> %arg1
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index caf204810a138..b71be826563b9 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -18,6 +18,8 @@
 
 #include "Delta.h"
 #include "Utils.h"
+#include "llvm/IR/AttributeMask.h"
+#include "llvm/IR/Attributes.h"
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/Support/Debug.h"
@@ -56,8 +58,10 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
   BasicBlock::iterator NewValIt =
       NewRetI ? NewRetI->getIterator() : EntryBB.end();
 
+  Type *OldRetTy = OldFuncTy->getReturnType();
+
   // Hack up any return values in other blocks, we can't leave them as ret void.
-  if (OldFuncTy->getReturnType() != NewRetTy) {
+  if (OldRetTy != NewRetTy) {
     for (BasicBlock &OtherRetBB : OldF) {
       if (&OtherRetBB != NewRetBlock) {
         auto *OrigRI = dyn_cast<ReturnInst>(OtherRetBB.getTerminator());
@@ -93,6 +97,15 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
   // result of our pruning here.
   EliminateUnreachableBlocks(OldF);
 
+
+  // Drop the incompatible attributes before we copy over to the new function.
+  if (OldRetTy != NewRetTy) {
+    AttributeList AL = OldF.getAttributes();
+    AttributeMask IncompatibleAttrs =
+        AttributeFuncs::typeIncompatible(NewRetTy, AL.getRetAttrs());
+    OldF.removeRetAttrs(IncompatibleAttrs);
+  }
+
   Function *NewF =
       Function::Create(NewFuncTy, OldF.getLinkage(), OldF.getAddressSpace(), "",
                        OldF.getParent());

>From 579ac18c30b0b4553c7ac3ecf3b9327714b3651a Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 2 Apr 2025 14:31:05 +0700
Subject: [PATCH 4/4] Fix returned attr

---
 ...reduce-values-to-return-new-return-type.ll | 33 +++++++++++++++++++
 .../deltas/ReduceValuesToReturn.cpp           |  5 ++-
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
index d8c878c5dc7cb..76ae1d17f885c 100644
--- a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
@@ -153,3 +153,36 @@ define range(i32 8, 256) <2 x i32> @preserve_compatible_return_range(ptr %arg, <
   store i32 %load, ptr @gv
   ret <2 x i32> %arg1
 }
+
+; INTERESTING-LABEL: @drop_incompatible_returned_param_attr_0(
+
+; RESULT-LABEL: define i32 @drop_incompatible_returned_param_attr_0(ptr %arg, ptr %arg1) {
+; RESULT-NEXT: %load = load i32, ptr %arg
+; RESULT-NEXT: ret i32 %load
+define ptr @drop_incompatible_returned_param_attr_0(ptr returned %arg, ptr %arg1) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret ptr %arg
+}
+
+; INTERESTING-LABEL: @drop_incompatible_returned_param_attr_1(
+
+; RESULT-LABEL: define i32 @drop_incompatible_returned_param_attr_1(ptr %arg, ptr %arg1) {
+; RESULT-NEXT: %load = load i32, ptr %arg
+; RESULT-NEXT: ret i32 %load
+define ptr @drop_incompatible_returned_param_attr_1(ptr %arg, ptr returned %arg1) {
+  %load = load i32, ptr %arg
+  store i32 %load, ptr @gv
+  ret ptr %arg
+}
+
+; INTERESTING-LABEL: @drop_incompatible_returned_param_attr_2
+
+; RESULT-LABEL: define ptr @drop_incompatible_returned_param_attr_2(ptr %arg, ptr %arg1) {
+; RESULT-NEXT: %load = load ptr, ptr %arg
+; RESULT-NEXT: ret ptr %load
+define ptr @drop_incompatible_returned_param_attr_2(ptr %arg, ptr returned %arg1) {
+  %load = load ptr, ptr %arg
+  store ptr %load, ptr @gv
+  ret ptr %arg1
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index b71be826563b9..3922395697b76 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -97,7 +97,6 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
   // result of our pruning here.
   EliminateUnreachableBlocks(OldF);
 
-
   // Drop the incompatible attributes before we copy over to the new function.
   if (OldRetTy != NewRetTy) {
     AttributeList AL = OldF.getAttributes();
@@ -106,6 +105,10 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
     OldF.removeRetAttrs(IncompatibleAttrs);
   }
 
+  // Now we need to remove any returned attributes from parameters.
+  for (Argument &A : OldF.args())
+    OldF.removeParamAttr(A.getArgNo(), Attribute::Returned);
+
   Function *NewF =
       Function::Create(NewFuncTy, OldF.getLinkage(), OldF.getAddressSpace(), "",
                        OldF.getParent());



More information about the llvm-branch-commits mailing list