https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/208422
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) <[email protected]> >From e94d245e5ed738400debfea724ca906f576d5596 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Thu, 9 Jul 2026 11:17:14 +0200 Subject: [PATCH] AMDGPU: Constant fold instructions with inline immediate operands 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) <[email protected]> --- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 27 ++-- .../promote-constOffset-to-imm-gfx12.mir | 4 - ...old-operands-constant-fold-imm-operand.mir | 115 ++++++++++++++++++ 3 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 llvm/test/CodeGen/AMDGPU/si-fold-operands-constant-fold-imm-operand.mir 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 + +... _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
