[llvm] 097e0e1 - llvm-reduce: Add pass to sink defs to uses (#170317)

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 4 12:33:07 PST 2025


Author: Matt Arsenault
Date: 2025-12-04T21:33:03+01:00
New Revision: 097e0e116aa42f114d6e7dd166069f90d85cce97

URL: https://github.com/llvm/llvm-project/commit/097e0e116aa42f114d6e7dd166069f90d85cce97
DIFF: https://github.com/llvm/llvm-project/commit/097e0e116aa42f114d6e7dd166069f90d85cce97.diff

LOG: llvm-reduce: Add pass to sink defs to uses (#170317)

The intent is to reduce live ranges and reduce
the impact on later scheduling on the testcase.

Added: 
    llvm/test/tools/llvm-reduce/reduce-sink-defs-to-uses.ll
    llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.cpp
    llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.h

Modified: 
    llvm/tools/llvm-reduce/CMakeLists.txt
    llvm/tools/llvm-reduce/DeltaManager.cpp
    llvm/tools/llvm-reduce/DeltaPasses.def
    llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-reduce/reduce-sink-defs-to-uses.ll b/llvm/test/tools/llvm-reduce/reduce-sink-defs-to-uses.ll
new file mode 100644
index 0000000000000..5c972640ac200
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-sink-defs-to-uses.ll
@@ -0,0 +1,264 @@
+; Test that llvm-reduce can move def instructions down to uses.
+;
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=sink-defs-to-uses --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
+
+declare i32 @leaf()
+declare void @func()
+declare void @use(i32)
+declare void @use0(i32)
+declare void @use1(i32)
+declare void @use2(i32)
+declare i32 @leaf_with_arg(i32)
+
+; CHECK-LABEL: define i32 @sink_leaf_to_ret() {
+; INTERESTING: call i32 @leaf()
+
+; RESULT-NEXT: call void @func()
+; RESULT-NEXT: %ret = call i32 @leaf()
+; RESULT-NEXT: ret i32 %ret
+define i32 @sink_leaf_to_ret() {
+  %ret = call i32 @leaf()
+  call void @func()
+  ret i32 %ret
+}
+
+; CHECK-LABEL: define i32 @no_sink_leaf_to_ret() {
+; INTERESTING: call i32 @leaf()
+; INTERESTING: call void @func()
+
+; RESULT: %ret = call i32 @leaf()
+; RESULT-NEXT: call void @func()
+; RESULT-NEXT: ret i32 %ret
+define i32 @no_sink_leaf_to_ret() {
+  %ret = call i32 @leaf()
+  call void @func()
+  ret i32 %ret
+}
+
+; CHECK-LABEL: define i32 @sink_across_trivial_block() {
+; RESULT: {{^}}entry:
+; RESULT-NEXT: br label %ret
+; RESULT: {{^}}ret:
+; RESULT-NEXT: call void @func
+; RESULT-NEXT: %val = call i32 @leaf()
+; RESULT-NEXT: ret i32 %val
+define i32 @sink_across_trivial_block() {
+entry:
+  %val = call i32 @leaf()
+  br label %ret
+
+ret:
+  call void @func()
+  ret i32 %val
+}
+
+; CHECK-LABEL: define i32 @cannot_sink_phi_def(
+; INTERESTING: phi i32
+
+; RESULT: {{^}}b:
+; RESULT-NEXT: %phi = phi i32
+; RESULT-NEXT: call void @func(
+; RESULT-NEXT: ret i32 %phi
+define i32 @cannot_sink_phi_def(i1 %cond) {
+entry:
+  br i1 %cond, label %a, label %b
+
+a:
+  br label %b
+
+b:
+  %phi = phi i32 [ 0, %entry ], [ 1, %a ]
+  call void @func()
+  ret i32 %phi
+}
+
+; CHECK-LABEL: define i32 @cannot_sink_phi_use(
+; INTERESTING: phi i32
+define i32 @cannot_sink_phi_use(ptr %arg) {
+entry:
+  call void @func()
+  br label %loop
+
+loop:
+  %phi = phi i32 [ 0, %entry ], [ %add, %loop ]
+  call void @func()
+  %def0 = call i32 @leaf()
+  call void @func()
+  %add = add i32 %phi, 1
+  %loop.cond = load volatile i1, ptr %arg
+  br i1 %loop.cond, label %loop, label %exit
+
+exit:
+  ret i32 %phi
+}
+
+; CHECK-LABEL: define i32 @cannot_sink_past_other_use(
+; INTERESTING: call i32 @leaf
+
+; RESULT-NEXT: %val = call i32
+; RESULT-NEXT: call void @use(i32 %val)
+; RESULT-NEXT: ret i32 %val
+define i32 @cannot_sink_past_other_use() {
+  %val = call i32 @leaf()
+  call void @use(i32 %val)
+  ret i32 %val
+}
+
+; CHECK-LABEL: define void @no_sink_alloca(
+; CHECK-NEXT: alloca
+; RESULT-NEXT: call void @func
+; RESULT-NEXT: store i32
+; RESULT-NEXT: ret
+define void @no_sink_alloca() {
+  %alloca = alloca i32
+  call void @func()
+  store i32 0, ptr %alloca
+  ret void
+}
+
+; CHECK-LABEL: define i32 @cannot_sink_callbr(
+; CHECK: callbr i32
+
+; RESULT: store i32 1
+; RESULT-NEXT: ret i32 %load0
+
+; RESULT: store i32 2
+; RESULT-NEXT: ret i32 2
+
+; RESULT: store i32 3
+; RESULT-NEXT: ret i32 3
+define i32 @cannot_sink_callbr(ptr %arg0, ptr %ptr1) {
+entry:
+  %load0 = load i32, ptr %arg0
+  %callbr = callbr i32 asm "", "=r,r,!i,!i"(i32 %load0)
+              to label %one [label %two, label %three]
+one:
+  store i32 1, ptr %ptr1
+  ret i32 %load0
+
+two:
+  store i32 2, ptr %ptr1
+  ret i32 2
+
+three:
+  store i32 3, ptr %ptr1
+  ret i32 3
+}
+
+declare i32 @__gxx_personality_v0(...)
+declare i32 @maybe_throwing_callee(i32)
+declare void @did_not_throw(i32)
+
+; landingpad must be first in the block, so it cannot be sunk.
+; CHECK-LABEL: @cannot_sink_landingpad(
+; INTERESTING: landingpad
+
+; RESULT: %landing = landingpad { ptr, i32 }
+; RESULT-NEXT: catch ptr
+; RESULT-NEXT: call void @func(
+; RESULT-NEXT: call void @func(
+; RESULT-NEXT: extractvalue { ptr, i32 } %landing, 1
+define void @cannot_sink_landingpad(i32 %arg) personality ptr @__gxx_personality_v0 {
+bb:
+  %i0 = invoke i32 @maybe_throwing_callee(i32 %arg)
+          to label %bb3 unwind label %bb1
+
+bb1:                                              ; preds = %bb
+  %landing = landingpad { ptr, i32 }
+          catch ptr null
+  call void @func()
+  call void @func()
+  %extract0 = extractvalue { ptr, i32 } %landing, 1
+  call void @use(i32 %extract0)
+  br label %bb4
+
+bb3:                                              ; preds = %bb
+  call void @did_not_throw(i32 %i0)
+  br label %bb4
+
+bb4:                                              ; preds = %bb3, %bb1
+  ret void
+}
+
+; CHECK-LABEL: define void @sink_multiple_uses() {
+; INTERESTING: call i32 @leaf(
+; INTERESTING: call void @use0(
+
+; RESULT-NEXT: call void @func(
+; RESULT-NEXT: %ret = call i32 @leaf()
+; RESULT-NEXT: call void @use0(i32 %ret)
+define void @sink_multiple_uses() {
+  %ret = call i32 @leaf()
+  call void @func()
+  call void @use0(i32 %ret)
+  call void @func()
+  call void @use1(i32 %ret)
+  call void @func()
+  call void @use2(i32 %ret)
+  ret void
+}
+
+; CHECK-LABEL: define i32 @can_sink_end_diamond(
+; RESULT: entry:
+; RESULT-NEXT: br i1
+
+; RESULT: endif:
+; RESULT-NEXT: %val = call i32 @leaf()
+; RESULT-NEXT: call void @use(i32 %val)
+; RESULT-NEXT: ret i32 %val
+define i32 @can_sink_end_diamond(i1 %cond) {
+entry:
+  %val = call i32 @leaf()
+  br i1 %cond, label %a, label %b
+
+a:
+  br label %endif
+
+b:
+  br label %endif
+
+endif:
+  call void @use(i32 %val)
+  ret i32 %val
+}
+
+; CHECK-LABEL: define i32 @cannot_sink_diamond_end_0(
+; RESULT: entry:
+; RESULT-NEXT: %val = call i32 @leaf()
+define i32 @cannot_sink_diamond_end_0(i1 %cond) {
+entry:
+  %val = call i32 @leaf()
+  br i1 %cond, label %a, label %b
+
+a:
+  call void @use0(i32 %val)
+  br label %endif
+
+b:
+  call void @use1(i32 %val)
+  br label %endif
+
+endif:
+  ret i32 %val
+}
+
+; CHECK-LABEL: define void @cannot_sink_diamond_end_1(
+; RESULT: entry:
+; RESULT-NEXT: %val = call i32 @leaf()
+define void @cannot_sink_diamond_end_1(i1 %cond) {
+entry:
+  %val = call i32 @leaf()
+  br i1 %cond, label %a, label %b
+
+a:
+  call void @use0(i32 %val)
+  br label %endif
+
+b:
+  call void @use1(i32 %val)
+  br label %endif
+
+endif:
+  ret void
+}

diff  --git a/llvm/tools/llvm-reduce/CMakeLists.txt b/llvm/tools/llvm-reduce/CMakeLists.txt
index c8673b42bee74..cf6701a3f0d5f 100644
--- a/llvm/tools/llvm-reduce/CMakeLists.txt
+++ b/llvm/tools/llvm-reduce/CMakeLists.txt
@@ -60,6 +60,7 @@ add_llvm_tool(llvm-reduce
   deltas/ReduceRegisterMasks.cpp
   deltas/ReduceRegisterDefs.cpp
   deltas/ReduceRegisterUses.cpp
+  deltas/ReduceSinkDefsToUses.cpp
   deltas/ReduceTargetFeaturesAttr.cpp
   deltas/ReduceUsingSimplifyCFG.cpp
   deltas/RunIRPasses.cpp

diff  --git a/llvm/tools/llvm-reduce/DeltaManager.cpp b/llvm/tools/llvm-reduce/DeltaManager.cpp
index 9b13202f9fec4..769e8a0730138 100644
--- a/llvm/tools/llvm-reduce/DeltaManager.cpp
+++ b/llvm/tools/llvm-reduce/DeltaManager.cpp
@@ -45,6 +45,7 @@
 #include "deltas/ReduceRegisterDefs.h"
 #include "deltas/ReduceRegisterMasks.h"
 #include "deltas/ReduceRegisterUses.h"
+#include "deltas/ReduceSinkDefsToUses.h"
 #include "deltas/ReduceSpecialGlobals.h"
 #include "deltas/ReduceTargetFeaturesAttr.h"
 #include "deltas/ReduceUsingSimplifyCFG.h"

diff  --git a/llvm/tools/llvm-reduce/DeltaPasses.def b/llvm/tools/llvm-reduce/DeltaPasses.def
index 845b1061592ef..1ec73544343e0 100644
--- a/llvm/tools/llvm-reduce/DeltaPasses.def
+++ b/llvm/tools/llvm-reduce/DeltaPasses.def
@@ -59,6 +59,7 @@ DELTA_PASS_IR("atomic-ordering", reduceAtomicOrderingDeltaPass, "Reducing Atomic
 DELTA_PASS_IR("syncscopes", reduceAtomicSyncScopesDeltaPass, "Reducing Atomic Sync Scopes")
 DELTA_PASS_IR("instruction-flags", reduceInstructionFlagsDeltaPass, "Reducing Instruction Flags")
 DELTA_PASS_IR("inline-call-sites", reduceInlineCallSitesDeltaPass, "Inlining callsites")
+DELTA_PASS_IR("sink-defs-to-uses", reduceSinkDefsToUsesDeltaPass, "Sinking defs to uses")
 
 #ifndef DELTA_PASS_MIR
 #define DELTA_PASS_MIR(NAME, FUNC, DESC)

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.cpp b/llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.cpp
new file mode 100644
index 0000000000000..454a6e4c4e7d0
--- /dev/null
+++ b/llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.cpp
@@ -0,0 +1,61 @@
+//===- ReduceSinkDefsToUses.cpp - Specialized Delta Pass ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Try to move defs to be next to their uses
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceSinkDefsToUses.h"
+#include "Utils.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Instructions.h"
+
+using namespace llvm;
+
+static bool shouldPreserveUsePosition(const Instruction &I) {
+  return isa<AllocaInst>(I) || isa<PHINode>(I) || I.isEHPad();
+}
+
+static bool shouldPreserveDefPosition(const Instruction &I) {
+  return shouldPreserveUsePosition(I) || I.isTerminator();
+}
+
+static void sinkDefsToUsesInFunction(Oracle &O, Function &F) {
+  DominatorTree DT(F);
+
+  for (BasicBlock &BB : F) {
+    for (Instruction &UseInst : make_early_inc_range(reverse(BB))) {
+      if (shouldPreserveUsePosition(UseInst))
+        continue;
+
+      for (Value *UseOp : UseInst.operands()) {
+        Instruction *DefInst = dyn_cast<Instruction>(UseOp);
+        if (!DefInst || shouldPreserveDefPosition(*DefInst))
+          continue;
+
+        if (!all_of(DefInst->users(), [&](const User *DefUser) {
+              return DefUser == &UseInst ||
+                     DT.dominates(&UseInst, cast<Instruction>(DefUser));
+            })) {
+          continue;
+        }
+
+        if (!O.shouldKeep())
+          DefInst->moveBeforePreserving(UseInst.getIterator());
+      }
+    }
+  }
+}
+
+void llvm::reduceSinkDefsToUsesDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
+  Module &M = WorkItem.getModule();
+  for (Function &F : M) {
+    if (!F.isDeclaration())
+      sinkDefsToUsesInFunction(O, F);
+  }
+}

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.h b/llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.h
new file mode 100644
index 0000000000000..422d0ea2ded80
--- /dev/null
+++ b/llvm/tools/llvm-reduce/deltas/ReduceSinkDefsToUses.h
@@ -0,0 +1,18 @@
+//===- ReduceSinkDefsToUses.h - Specialized Delta Pass ----------*- C++- *-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_SINKDEFSTOUSES_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_SINKDEFSTOUSES_H
+
+#include "Delta.h"
+
+namespace llvm {
+void reduceSinkDefsToUsesDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
+} // namespace llvm
+
+#endif

diff  --git a/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn
index 0c7affba2b4c5..5d5d9f0dbd840 100644
--- a/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn
@@ -48,6 +48,7 @@ executable("llvm-reduce") {
     "deltas/ReduceRegisterDefs.cpp",
     "deltas/ReduceRegisterMasks.cpp",
     "deltas/ReduceRegisterUses.cpp",
+    "deltas/ReduceSinkDefsToUses.cpp",
     "deltas/ReduceSpecialGlobals.cpp",
     "deltas/ReduceTargetFeaturesAttr.cpp",
     "deltas/ReduceUsingSimplifyCFG.cpp",


        


More information about the llvm-commits mailing list