[llvm-branch-commits] [llvm] AMDGPU: Constant fold instructions with inline immediate operands (PR #208422)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jul 9 03:59:27 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
Previously we would only try to perform constant folding and simplifications
when an immediate was folded into an instruction, not if the input was already
a folded constant.
Co-authored-by: Claude (Opus 4.8) <noreply@<!-- -->anthropic.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/208422.diff
3 Files Affected:
- (modified) llvm/lib/Target/AMDGPU/SIFoldOperands.cpp (+9-18)
- (modified) llvm/test/CodeGen/AMDGPU/promote-constOffset-to-imm-gfx12.mir (-4)
- (added) llvm/test/CodeGen/AMDGPU/si-fold-operands-constant-fold-imm-operand.mir (+115)
``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
index 3fdbb74eb3342..5a6f0e710ae0f 100644
--- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
@@ -1806,24 +1806,6 @@ bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &MI,
MachineOperand &Dst = MI.getOperand(0);
bool Changed = false;
- if (OpToFold.isImm()) {
- for (auto &UseMI :
- make_early_inc_range(MRI->use_nodbg_instructions(Dst.getReg()))) {
- // Folding the immediate may reveal operations that can be constant
- // folded or replaced with a copy. This can happen for example after
- // frame indices are lowered to constants or from splitting 64-bit
- // constants.
- //
- // We may also encounter cases where one or both operands are
- // immediates materialized into a register, which would ordinarily not
- // be folded due to multiple uses or operand constraints.
- if (tryConstantFoldOp(&UseMI)) {
- LLVM_DEBUG(dbgs() << "Constant folded " << UseMI);
- Changed = true;
- }
- }
- }
-
SmallVector<MachineOperand *, 4> UsesToProcess(
llvm::make_pointer_range(MRI->use_nodbg_operands(Dst.getReg())));
for (auto *U : UsesToProcess) {
@@ -2832,6 +2814,15 @@ bool SIFoldOperandsImpl::run(MachineFunction &MF) {
for (auto &MI : make_early_inc_range(*MBB)) {
Changed |= tryFoldCndMask(MI);
+ // PeepholeOptimizer may have folded an inline immediate directly onto an
+ // instruction operand without materializing it into a register first.
+ // Such an instruction is never reached through a def->use edge in
+ // foldInstOperand, so try to constant fold it here.
+ if (tryConstantFoldOp(&MI)) {
+ Changed = true;
+ continue;
+ }
+
if (tryFoldZeroHighBits(MI)) {
Changed = true;
continue;
diff --git a/llvm/test/CodeGen/AMDGPU/promote-constOffset-to-imm-gfx12.mir b/llvm/test/CodeGen/AMDGPU/promote-constOffset-to-imm-gfx12.mir
index 5c043eadf6096..f232c3da15c18 100644
--- a/llvm/test/CodeGen/AMDGPU/promote-constOffset-to-imm-gfx12.mir
+++ b/llvm/test/CodeGen/AMDGPU/promote-constOffset-to-imm-gfx12.mir
@@ -22,7 +22,6 @@ body: |
; GFX1250-NEXT: renamable $vgpr1 = V_LSHLREV_B32_e32 8, $vgpr0, implicit $exec
; GFX1250-NEXT: renamable $vgpr2, renamable $vcc_lo = V_ADD_CO_U32_e64 256, $vgpr0, 0, implicit $exec
; GFX1250-NEXT: renamable $vgpr3, $sgpr_null = V_ADDC_U32_e64 0, killed $vgpr0, killed $vcc_lo, 0, implicit $exec
- ; GFX1250-NEXT: renamable $vgpr1 = disjoint V_OR_B32_e32 0, killed $vgpr1, implicit $exec
; GFX1250-NEXT: renamable $vgpr0 = V_ADD_U32_e32 -256, $vgpr1, implicit $exec
; GFX1250-NEXT: GLOBAL_LOAD_ASYNC_TO_LDS_B128 killed $vgpr1, $vgpr2_vgpr3, 0, 0, implicit-def $asynccnt, implicit $exec, implicit $asynccnt :: (load store (s128), align 1, addrspace 3)
; GFX1250-NEXT: GLOBAL_LOAD_ASYNC_TO_LDS_B128 killed $vgpr0, killed $vgpr2_vgpr3, 256, 0, implicit-def $asynccnt, implicit $exec, implicit $asynccnt :: (load store (s128), align 1, addrspace 3)
@@ -62,7 +61,6 @@ body: |
; GFX1250-NEXT: renamable $vgpr1 = V_LSHLREV_B32_e32 8, $vgpr0, implicit $exec
; GFX1250-NEXT: renamable $vgpr2, renamable $vcc_lo = V_ADD_CO_U32_e64 256, $vgpr0, 0, implicit $exec
; GFX1250-NEXT: renamable $vgpr3, $sgpr_null = V_ADDC_U32_e64 0, killed $vgpr0, killed $vcc_lo, 0, implicit $exec
- ; GFX1250-NEXT: renamable $vgpr1 = disjoint V_OR_B32_e32 0, killed $vgpr1, implicit $exec
; GFX1250-NEXT: renamable $vgpr0 = V_ADD_U32_e32 -256, $vgpr1, implicit $exec
; GFX1250-NEXT: renamable $vgpr4 = V_ADD_U32_e32 -260, $vgpr1, implicit $exec
; GFX1250-NEXT: GLOBAL_LOAD_ASYNC_TO_LDS_B128 killed $vgpr1, $vgpr2_vgpr3, 0, 0, implicit-def $asynccnt, implicit $exec, implicit $asynccnt :: (load store (s128), align 1, addrspace 3)
@@ -157,7 +155,6 @@ body: |
; GFX1250-NEXT: renamable $vgpr1 = V_LSHLREV_B32_e32 8, $vgpr0, implicit $exec
; GFX1250-NEXT: renamable $vgpr2, renamable $vcc_lo = V_ADD_CO_U32_e64 256, $vgpr0, 0, implicit $exec
; GFX1250-NEXT: renamable $vgpr3, $sgpr_null = V_ADDC_U32_e64 0, killed $vgpr0, killed $vcc_lo, 0, implicit $exec
- ; GFX1250-NEXT: renamable $vgpr1 = disjoint V_OR_B32_e32 0, killed $vgpr1, implicit $exec
; GFX1250-NEXT: renamable $vgpr0 = V_ADD_U32_e32 -256, $vgpr1, implicit $exec
; GFX1250-NEXT: renamable $vgpr4 = V_ADD_U32_e32 -512, $vgpr1, implicit $exec
; GFX1250-NEXT: GLOBAL_LOAD_ASYNC_TO_LDS_B128 killed $vgpr1, $vgpr2_vgpr3, 0, 0, implicit-def $asynccnt, implicit $exec, implicit $asynccnt :: (load store (s128), align 1, addrspace 3)
@@ -206,7 +203,6 @@ body: |
; GFX1250-NEXT: renamable $vgpr1 = V_LSHLREV_B32_e32 8, $vgpr0, implicit $exec
; GFX1250-NEXT: renamable $vgpr2, renamable $vcc_lo = V_ADD_CO_U32_e64 256, $vgpr0, 0, implicit $exec
; GFX1250-NEXT: renamable $vgpr3, $sgpr_null = V_ADDC_U32_e64 0, killed $vgpr0, killed $vcc_lo, 0, implicit $exec
- ; GFX1250-NEXT: renamable $vgpr1 = disjoint V_OR_B32_e32 0, killed $vgpr1, implicit $exec
; GFX1250-NEXT: renamable $vgpr0 = V_ADD_U32_e32 -256, $vgpr1, implicit $exec
; GFX1250-NEXT: GLOBAL_STORE_ASYNC_FROM_LDS_B128 $vgpr2_vgpr3, killed $vgpr1, 0, 0, implicit-def $asynccnt, implicit $exec, implicit $asynccnt :: (load store (s128), align 1, addrspace 3)
; GFX1250-NEXT: GLOBAL_STORE_ASYNC_FROM_LDS_B128 killed $vgpr2_vgpr3, killed $vgpr0, 256, 0, implicit-def $asynccnt, implicit $exec, implicit $asynccnt :: (load store (s128), align 1, addrspace 3)
diff --git a/llvm/test/CodeGen/AMDGPU/si-fold-operands-constant-fold-imm-operand.mir b/llvm/test/CodeGen/AMDGPU/si-fold-operands-constant-fold-imm-operand.mir
new file mode 100644
index 0000000000000..9206ffb149ca0
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-fold-operands-constant-fold-imm-operand.mir
@@ -0,0 +1,115 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgcn -mcpu=gfx900 -run-pass=si-fold-operands -o - %s | FileCheck %s
+
+# Check that si-fold-operands will perform simplifications and
+# constant folding of instructions that already have immediate
+# operands.
+
+---
+name: v_and_imm_zero_operand_to_mov
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ ; CHECK-LABEL: name: v_and_imm_zero_operand_to_mov
+ ; CHECK: liveins: $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+ ; CHECK-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG [[V_MOV_B32_e32_]]
+ %0:vgpr_32 = COPY $vgpr0
+ %1:vgpr_32 = V_AND_B32_e32 0, %0, implicit $exec
+ SI_RETURN_TO_EPILOG %1
+
+...
+
+---
+name: v_and_imm_neg1_operand_to_copy
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ ; CHECK-LABEL: name: v_and_imm_neg1_operand_to_copy
+ ; CHECK: liveins: $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr_32 = COPY [[COPY]]
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG [[COPY1]]
+ %0:vgpr_32 = COPY $vgpr0
+ %1:vgpr_32 = V_AND_B32_e32 -1, %0, implicit $exec
+ SI_RETURN_TO_EPILOG %1
+
+...
+
+---
+name: v_or_imm_neg1_operand_to_mov
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ ; CHECK-LABEL: name: v_or_imm_neg1_operand_to_mov
+ ; CHECK: liveins: $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+ ; CHECK-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 -1, implicit $exec
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG [[V_MOV_B32_e32_]]
+ %0:vgpr_32 = COPY $vgpr0
+ %1:vgpr_32 = V_OR_B32_e32 -1, %0, implicit $exec
+ SI_RETURN_TO_EPILOG %1
+
+...
+
+---
+name: v_xor_imm_zero_operand_to_copy
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ ; CHECK-LABEL: name: v_xor_imm_zero_operand_to_copy
+ ; CHECK: liveins: $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr_32 = COPY [[COPY]]
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG [[COPY1]]
+ %0:vgpr_32 = COPY $vgpr0
+ %1:vgpr_32 = V_XOR_B32_e32 0, %0, implicit $exec
+ SI_RETURN_TO_EPILOG %1
+
+...
+
+---
+name: s_add_imm_zero_operand_to_copy
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $sgpr0
+
+ ; CHECK-LABEL: name: s_add_imm_zero_operand_to_copy
+ ; CHECK: liveins: $sgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:sreg_32 = COPY [[COPY]]
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG [[COPY1]]
+ %0:sreg_32 = COPY $sgpr0
+ %1:sreg_32 = S_ADD_U32 %0, 0, implicit-def dead $scc
+ SI_RETURN_TO_EPILOG %1
+
+...
+
+---
+name: s_not_imm_operand_to_mov
+tracksRegLiveness: true
+body: |
+ bb.0:
+
+ ; CHECK-LABEL: name: s_not_imm_operand_to_mov
+ ; CHECK: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 -2
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG [[S_MOV_B32_]]
+ %0:sreg_32 = S_NOT_B32 1, implicit-def dead $scc
+ SI_RETURN_TO_EPILOG %0
+
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/208422
More information about the llvm-branch-commits
mailing list