[llvm-branch-commits] [llvm] llvm-reduce: Reduce with early return of arguments (PR #133627)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Apr 7 23:48:00 PDT 2025


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

>From b77ade49fa87432ea501e1a50c2d4e59dedb2039 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 24 Mar 2025 14:33:36 +0700
Subject: [PATCH 1/2] llvm-reduce: Reduce with early return of arguments

Extend the instruction -> return reduction with one that inserts
return of function arguments. Not sure how useful this really is. This
has more freedom since we could insert the return anywhere in the function,
but this just inserts the return in the entry block.
---
 .../reduce-values-to-return-args.ll           | 77 +++++++++++++++++++
 ...-values-to-return-nonvoid-noncallee-use.ll |  2 +-
 .../llvm-reduce/reduce-values-to-return.ll    |  2 +-
 llvm/tools/llvm-reduce/DeltaPasses.def        |  5 +-
 .../deltas/ReduceValuesToReturn.cpp           | 42 +++++++++-
 .../llvm-reduce/deltas/ReduceValuesToReturn.h |  3 +-
 6 files changed, 124 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll

diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll
new file mode 100644
index 0000000000000..abbc643822033
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll
@@ -0,0 +1,77 @@
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=arguments-to-return --test FileCheck --test-arg --check-prefixes=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefixes=RESULT %s < %t
+
+
+; INTERESTING-LABEL: @move_entry_block_use_argument_to_return(i32 %arg, ptr %ptr) {
+; INTERESTING: %arg
+
+; RESULT-LABEL: define i32 @move_entry_block_use_argument_to_return(
+; RESULT-NEXT: ret i32 %arg
+; RESULT-NEXT: }
+define void @move_entry_block_use_argument_to_return(i32 %arg, ptr %ptr) {
+  store i32 %arg, ptr %ptr
+  ret void
+}
+
+; INTERESTING-LABEL: @move_entry_block_use_argument_to_return_existing_ret(i32 %arg, ptr %ptr) {
+; INTERESTING: %arg
+
+; RESULT-LABEL: define i32 @move_entry_block_use_argument_to_return_existing_ret(
+; RESULT-NEXT: ret i32 %arg
+; RESULT-NEXT: }
+define i32 @move_entry_block_use_argument_to_return_existing_ret(i32 %arg, ptr %ptr) {
+  store i32 %arg, ptr %ptr
+  ret i32 0
+}
+
+; INTERESTING-LABEL: @move_phi_block_use_argument_to_return(i32 %arg, ptr %ptr0, ptr %ptr1, i1 %cond0, i1 %cond1) {
+; INTERESTING: %arg
+
+; RESULT-LABEL: define i32 @move_phi_block_use_argument_to_return(
+; RESULT-NEXT: entry:
+; RESULT-NEXT: ret i32 %arg
+define void @move_phi_block_use_argument_to_return(i32 %arg, ptr %ptr0, ptr %ptr1, i1 %cond0, i1 %cond1) {
+entry:
+  br i1 %cond0, label %bb0, label %bb1
+
+bb0:
+  %phi = phi i32 [ %arg, %entry ], [ 123, %bb1 ]
+  store i32 %arg, ptr %ptr0
+  store i32 %phi, ptr %ptr1
+  br label %bb1
+
+bb1:
+  br i1 %cond1, label %bb0, label %bb2
+
+bb2:
+  ret void
+}
+
+; INTERESTING-LABEL: define {{.*}} @keep_second_arg(i32 %arg0, ptr %arg1) {
+; INTERESTING: %arg1
+
+; RESULT-LABEL: define ptr @keep_second_arg(
+; RESULT-NEXT: ret ptr %arg1
+; RESULT-NEXT: }
+define void @keep_second_arg(i32 %arg0, ptr %arg1) {
+  store i32 %arg0, ptr %arg1
+  ret void
+}
+
+; INTERESTING-LABEL: @multi_void_return_arg(i1 %arg0, ptr %arg1, i32 %arg2) {
+; INTERESTING: i32 %arg2
+
+; RESULT-LABEL: define i32 @multi_void_return_arg(i1 %arg0, ptr %arg1, i32 %arg2) {
+; RESULT-NEXT: entry:
+; RESULT-NEXT: ret i32 %arg2
+define void @multi_void_return_arg(i1 %arg0, ptr %arg1, i32 %arg2) {
+entry:
+  br i1 %arg0, label %bb0, label %bb1
+
+bb0:
+  store i32 %arg2, ptr %arg1
+  ret void
+
+bb1:
+  ret void
+}
diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-nonvoid-noncallee-use.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-nonvoid-noncallee-use.ll
index 215ea97a8be91..11166479318c6 100644
--- a/llvm/test/tools/llvm-reduce/reduce-values-to-return-nonvoid-noncallee-use.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-nonvoid-noncallee-use.ll
@@ -1,7 +1,7 @@
 ; Make sure we don't break on non-callee uses of funtions with a
 ; non-void return type.
 
-; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=values-to-return --test FileCheck --test-arg --check-prefix=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; 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
 
 ; INTERESTING-LABEL: @interesting(
diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return.ll
index 0c36db8ebc278..2af87aad05169 100644
--- a/llvm/test/tools/llvm-reduce/reduce-values-to-return.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return.ll
@@ -1,7 +1,7 @@
 ; Test that llvm-reduce can move intermediate values by inserting
 ; early returns
 ;
-; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=values-to-return --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions-to-return --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t
 ; RUN: FileCheck --check-prefixes=CHECK,RESULT %s < %t
 
 @gv = global i32 0, align 4
diff --git a/llvm/tools/llvm-reduce/DeltaPasses.def b/llvm/tools/llvm-reduce/DeltaPasses.def
index 589955eb95652..731d76c5c24c2 100644
--- a/llvm/tools/llvm-reduce/DeltaPasses.def
+++ b/llvm/tools/llvm-reduce/DeltaPasses.def
@@ -49,7 +49,10 @@ DELTA_PASS_IR("attributes", reduceAttributesDeltaPass, "Reducing Attributes")
 DELTA_PASS_IR("target-features-attr", reduceTargetFeaturesAttrDeltaPass, "Reducing target-features")
 DELTA_PASS_IR("module-data", reduceModuleDataDeltaPass, "Reducing Module Data")
 DELTA_PASS_IR("opcodes", reduceOpcodesDeltaPass, "Reducing Opcodes")
-DELTA_PASS_IR("values-to-return", reduceValuesToReturnDeltaPass, "Converting values to function return value")
+DELTA_PASS_IR("arguments-to-return", reduceArgumentsToReturnDeltaPass,
+              "Converting arguments to function return value")
+DELTA_PASS_IR("instructions-to-return", reduceInstructionsToReturnDeltaPass,
+              "Converting instructions to function return value")
 DELTA_PASS_IR("volatile", reduceVolatileInstructionsDeltaPass, "Reducing Volatile Instructions")
 DELTA_PASS_IR("atomic-ordering", reduceAtomicOrderingDeltaPass, "Reducing Atomic Ordering")
 DELTA_PASS_IR("syncscopes", reduceAtomicSyncScopesDeltaPass, "Reducing Atomic Sync Scopes")
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index 9ee0af3e1a69b..3e400ffc89482 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -48,10 +48,12 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
       FunctionType::get(NewRetTy, OldFuncTy->params(), OldFuncTy->isVarArg());
 
   LLVMContext &Ctx = OldF.getContext();
-  Instruction *NewRetI = cast<Instruction>(NewRetValue);
-  BasicBlock *NewRetBlock = NewRetI->getParent();
+  BasicBlock &EntryBB = OldF.getEntryBlock();
+  Instruction *NewRetI = dyn_cast<Instruction>(NewRetValue);
+  BasicBlock *NewRetBlock = NewRetI ? NewRetI->getParent() : &EntryBB;
 
-  BasicBlock::iterator NewValIt = NewRetI->getIterator();
+  BasicBlock::iterator NewValIt =
+      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()) {
@@ -226,6 +228,40 @@ static bool tryForwardingInstructionsToReturn(
   return false;
 }
 
+static bool tryForwardingArgumentsToReturn(
+    Function &F, Oracle &O,
+    std::vector<std::pair<Function *, Value *>> &FuncsToReplace) {
+
+  Type *RetTy = F.getReturnType();
+  BasicBlock &EntryBB = F.getEntryBlock();
+
+  for (Argument &A : F.args()) {
+    if (shouldForwardValueToReturn(EntryBB, &A, RetTy) && !O.shouldKeep()) {
+      FuncsToReplace.emplace_back(&F, &A);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void llvm::reduceArgumentsToReturnDeltaPass(Oracle &O,
+                                            ReducerWorkItem &WorkItem) {
+  Module &Program = WorkItem.getModule();
+
+  // We're going to chaotically hack on the other users of the function in other
+  // functions, so we need to collect a worklist of returns to replace.
+  std::vector<std::pair<Function *, Value *>> FuncsToReplace;
+
+  for (Function &F : Program.functions()) {
+    if (!F.isDeclaration() && canUseNonVoidReturnType(F))
+      tryForwardingArgumentsToReturn(F, O, FuncsToReplace);
+  }
+
+  for (auto [F, NewRetVal] : FuncsToReplace)
+    rewriteFuncWithReturnType(*F, NewRetVal);
+}
+
 void llvm::reduceInstructionsToReturnDeltaPass(Oracle &O,
                                                ReducerWorkItem &WorkItem) {
   Module &Program = WorkItem.getModule();
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.h b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.h
index 7bfde832555bc..f6dcb9b02df5d 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.h
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.h
@@ -12,7 +12,8 @@
 #include "Delta.h"
 
 namespace llvm {
-void reduceValuesToReturnDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
+void reduceArgumentsToReturnDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
+void reduceInstructionsToReturnDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
 } // namespace llvm
 
 #endif

>From 57ba2fd1f0aa06ba0f7e6da2f7a105365bf77c0a Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 8 Apr 2025 12:49:57 +0700
Subject: [PATCH 2/2] test work

---
 .../reduce-values-to-return-args.ll           | 26 ++++++++++++++-----
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll
index abbc643822033..e75eb9382e584 100644
--- a/llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-args.ll
@@ -1,26 +1,27 @@
 ; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=arguments-to-return --test FileCheck --test-arg --check-prefixes=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
 ; RUN: FileCheck --check-prefixes=RESULT %s < %t
 
+ at gv = global i32 0
 
-; INTERESTING-LABEL: @move_entry_block_use_argument_to_return(i32 %arg, ptr %ptr) {
-; INTERESTING: %arg
+; INTERESTING-LABEL: @move_entry_block_use_argument_to_return(i32 %arg) {
+; INTERESTING: i32 %arg
 
 ; RESULT-LABEL: define i32 @move_entry_block_use_argument_to_return(
 ; RESULT-NEXT: ret i32 %arg
 ; RESULT-NEXT: }
-define void @move_entry_block_use_argument_to_return(i32 %arg, ptr %ptr) {
-  store i32 %arg, ptr %ptr
+define void @move_entry_block_use_argument_to_return(i32 %arg) {
+  store i32 %arg, ptr @gv
   ret void
 }
 
-; INTERESTING-LABEL: @move_entry_block_use_argument_to_return_existing_ret(i32 %arg, ptr %ptr) {
+; INTERESTING-LABEL: @move_entry_block_use_argument_to_return_existing_ret(i32 %arg) {
 ; INTERESTING: %arg
 
 ; RESULT-LABEL: define i32 @move_entry_block_use_argument_to_return_existing_ret(
 ; RESULT-NEXT: ret i32 %arg
 ; RESULT-NEXT: }
-define i32 @move_entry_block_use_argument_to_return_existing_ret(i32 %arg, ptr %ptr) {
-  store i32 %arg, ptr %ptr
+define i32 @move_entry_block_use_argument_to_return_existing_ret(i32 %arg) {
+  store i32 %arg, ptr @gv
   ret i32 0
 }
 
@@ -47,6 +48,17 @@ bb2:
   ret void
 }
 
+; INTERESTING-LABEL: define {{.*}} @keep_first_arg(i32 %arg0, ptr %arg1) {
+; INTERESTING: %arg0
+
+; RESULT-LABEL: define i32 @keep_first_arg(
+; RESULT-NEXT: ret i32 %arg0
+; RESULT-NEXT: }
+define void @keep_first_arg(i32 %arg0, ptr %arg1) {
+  store i32 %arg0, ptr %arg1
+  ret void
+}
+
 ; INTERESTING-LABEL: define {{.*}} @keep_second_arg(i32 %arg0, ptr %arg1) {
 ; INTERESTING: %arg1
 



More information about the llvm-branch-commits mailing list