From cae0bf4404f9e547505c9bbbae475563831e97f5 Mon Sep 17 00:00:00 2001 From: Axel Sorenson Date: Thu, 27 Feb 2025 17:41:41 -0800 Subject: [PATCH 1/2] pre-commit test --- .../include/llvm/Target/GlobalISel/Combine.td | 32 +++++++++++- llvm/test/CodeGen/RISCV/GlobalISel/shift.ll | 52 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td index 9564b581c5ebb..1b7c1235c9805 100644 --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -1040,6 +1040,34 @@ def funnel_shift_overshift: GICombineRule< (apply [{ Helper.applyFunnelShiftConstantModulo(*${root}); }]) >; +// Transform: fshl x, z, y | shl x, y -> fshl x, z, y +// Transform: shl x, y | fshl x, z, y -> fshl x, z, y +// FIXME: TableGen didn't handle G_OR commutativity on its own, +// necessitating the use of !foreach to handle it manually. +def funnel_shift_or_shift_to_funnel_shift_left_frags : GICombinePatFrag< + (outs root: $dst, $out1, $out2), (ins), + !foreach(inst, [(G_OR $dst, $out1, $out2), (G_OR $dst, $out2, $out1)], + (pattern (G_FSHL $out1, $x, $z, $y), (G_SHL $out2, $x, $y), inst))>; +def funnel_shift_or_shift_to_funnel_shift_left: GICombineRule< + (defs root:$root), + (match (funnel_shift_or_shift_to_funnel_shift_left_frags $root, $out1, $out2)), + (apply (GIReplaceReg $root, $out1)) +>; + +// Transform: fshr z, x, y | srl x, y -> fshr z, x, y +// Transform: srl x, y | fshr z, x, y -> fshr z, x, y +// FIXME: TableGen didn't handle G_OR commutativity on its own, +// necessitating the use of !foreach to handle it manually. +def funnel_shift_or_shift_to_funnel_shift_right_frags : GICombinePatFrag< + (outs root: $dst, $out1, $out2), (ins), + !foreach(inst, [(G_OR $dst, $out1, $out2), (G_OR $dst, $out2, $out1)], + (pattern (G_FSHR $out1, $z, $x, $y), (G_LSHR $out2, $x, $y), inst))>; +def funnel_shift_or_shift_to_funnel_shift_right: GICombineRule< + (defs root:$root), + (match (funnel_shift_or_shift_to_funnel_shift_right_frags $root, $out1, $out2)), + (apply (GIReplaceReg $root, $out1)) +>; + def rotate_out_of_range : GICombineRule< (defs root:$root), (match (wip_match_opcode G_ROTR, G_ROTL):$root, @@ -1112,7 +1140,9 @@ def funnel_shift_combines : GICombineGroup<[funnel_shift_from_or_shift, funnel_shift_to_rotate, funnel_shift_right_zero, funnel_shift_left_zero, - funnel_shift_overshift]>; + funnel_shift_overshift, + funnel_shift_or_shift_to_funnel_shift_left, + funnel_shift_or_shift_to_funnel_shift_right]>; def bitfield_extract_from_sext_inreg : GICombineRule< (defs root:$root, build_fn_matchinfo:$info), diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll b/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll index 75e318a58fd45..af86e7a0edd43 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll +++ b/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll @@ -105,3 +105,55 @@ define i16 @test_shl_i48_2(i48 %x, i48 %y) { %trunc = trunc i48 %shl to i16 ret i16 %trunc } + +define i32 @test_fshl_i32(i32 %x, i32 %_, i32 %y) { +; RV32-LABEL: test_fshl_i32: +; RV32: # %bb.0: +; RV32-NEXT: not a3, a2 +; RV32-NEXT: sll a0, a0, a2 +; RV32-NEXT: srli a1, a1, 1 +; RV32-NEXT: srl a1, a1, a3 +; RV32-NEXT: or a0, a0, a0 +; RV32-NEXT: or a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_fshl_i32: +; RV64: # %bb.0: +; RV64-NEXT: not a3, a2 +; RV64-NEXT: sllw a0, a0, a2 +; RV64-NEXT: srliw a1, a1, 1 +; RV64-NEXT: srlw a1, a1, a3 +; RV64-NEXT: or a0, a0, a0 +; RV64-NEXT: or a0, a0, a1 +; RV64-NEXT: ret + %fshl = call i32 @llvm.fshl.i32(i32 %x, i32 %_, i32 %y) + %shl = shl i32 %x, %y + %or = or i32 %fshl, %shl + ret i32 %or +} + +define i32 @test_fshr_i32(i32 %_, i32 %x, i32 %y) { +; RV32-LABEL: test_fshr_i32: +; RV32: # %bb.0: +; RV32-NEXT: not a3, a2 +; RV32-NEXT: slli a0, a0, 1 +; RV32-NEXT: srl a1, a1, a2 +; RV32-NEXT: sll a0, a0, a3 +; RV32-NEXT: or a1, a1, a1 +; RV32-NEXT: or a0, a1, a0 +; RV32-NEXT: ret +; +; RV64-LABEL: test_fshr_i32: +; RV64: # %bb.0: +; RV64-NEXT: not a3, a2 +; RV64-NEXT: slli a0, a0, 1 +; RV64-NEXT: srlw a1, a1, a2 +; RV64-NEXT: sllw a0, a0, a3 +; RV64-NEXT: or a1, a1, a1 +; RV64-NEXT: or a0, a1, a0 +; RV64-NEXT: ret + %fshr = call i32 @llvm.fshr.i32(i32 %_, i32 %x, i32 %y) + %lshr = lshr i32 %x, %y + %or = or i32 %lshr, %fshr + ret i32 %or +} From 75ad0e0f49946314a0244aaaf9f1ad0cec5b6a33 Mon Sep 17 00:00:00 2001 From: Axel Sorenson Date: Wed, 27 Aug 2025 18:43:20 -0600 Subject: [PATCH 2/2] [GISel] Funnel shift combiner port from SelectionDAG ISel to GlobalISel The funnel shift combiner rule from 4a3708c is currently missing from GlobalISel. The following is a port of that combiner to GlobalISel. --- llvm/test/CodeGen/AArch64/funnel-shift.ll | 24 +++++++++------------ llvm/test/CodeGen/RISCV/GlobalISel/shift.ll | 12 ++++------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/llvm/test/CodeGen/AArch64/funnel-shift.ll b/llvm/test/CodeGen/AArch64/funnel-shift.ll index e5aa360f804c1..f9fd2ad1b5b6c 100644 --- a/llvm/test/CodeGen/AArch64/funnel-shift.ll +++ b/llvm/test/CodeGen/AArch64/funnel-shift.ll @@ -674,14 +674,12 @@ define i32 @or_shl_fshl_simplify(i32 %x, i32 %y, i32 %s) { ; CHECK-GI-LABEL: or_shl_fshl_simplify: ; CHECK-GI: // %bb.0: ; CHECK-GI-NEXT: mov w8, #31 // =0x1f -; CHECK-GI-NEXT: and w9, w2, #0x1f -; CHECK-GI-NEXT: lsr w10, w0, #1 -; CHECK-GI-NEXT: lsl w11, w1, w2 +; CHECK-GI-NEXT: lsr w9, w0, #1 +; CHECK-GI-NEXT: and w10, w2, #0x1f ; CHECK-GI-NEXT: bic w8, w8, w2 -; CHECK-GI-NEXT: lsl w9, w1, w9 -; CHECK-GI-NEXT: lsr w8, w10, w8 -; CHECK-GI-NEXT: orr w9, w9, w11 -; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: lsl w10, w1, w10 +; CHECK-GI-NEXT: lsr w8, w9, w8 +; CHECK-GI-NEXT: orr w0, w10, w8 ; CHECK-GI-NEXT: ret %shy = shl i32 %y, %s %fun = call i32 @llvm.fshl.i32(i32 %y, i32 %x, i32 %s) @@ -702,14 +700,12 @@ define i32 @or_lshr_fshr_simplify(i32 %x, i32 %y, i32 %s) { ; CHECK-GI-LABEL: or_lshr_fshr_simplify: ; CHECK-GI: // %bb.0: ; CHECK-GI-NEXT: mov w8, #31 // =0x1f -; CHECK-GI-NEXT: and w9, w2, #0x1f -; CHECK-GI-NEXT: lsl w10, w0, #1 -; CHECK-GI-NEXT: lsr w11, w1, w2 +; CHECK-GI-NEXT: lsl w9, w0, #1 +; CHECK-GI-NEXT: and w10, w2, #0x1f ; CHECK-GI-NEXT: bic w8, w8, w2 -; CHECK-GI-NEXT: lsr w9, w1, w9 -; CHECK-GI-NEXT: lsl w8, w10, w8 -; CHECK-GI-NEXT: orr w9, w11, w9 -; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: lsl w8, w9, w8 +; CHECK-GI-NEXT: lsr w9, w1, w10 +; CHECK-GI-NEXT: orr w0, w8, w9 ; CHECK-GI-NEXT: ret %shy = lshr i32 %y, %s %fun = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %s) diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll b/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll index af86e7a0edd43..776eaedb2a5cc 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll +++ b/llvm/test/CodeGen/RISCV/GlobalISel/shift.ll @@ -113,7 +113,6 @@ define i32 @test_fshl_i32(i32 %x, i32 %_, i32 %y) { ; RV32-NEXT: sll a0, a0, a2 ; RV32-NEXT: srli a1, a1, 1 ; RV32-NEXT: srl a1, a1, a3 -; RV32-NEXT: or a0, a0, a0 ; RV32-NEXT: or a0, a0, a1 ; RV32-NEXT: ret ; @@ -123,7 +122,6 @@ define i32 @test_fshl_i32(i32 %x, i32 %_, i32 %y) { ; RV64-NEXT: sllw a0, a0, a2 ; RV64-NEXT: srliw a1, a1, 1 ; RV64-NEXT: srlw a1, a1, a3 -; RV64-NEXT: or a0, a0, a0 ; RV64-NEXT: or a0, a0, a1 ; RV64-NEXT: ret %fshl = call i32 @llvm.fshl.i32(i32 %x, i32 %_, i32 %y) @@ -137,20 +135,18 @@ define i32 @test_fshr_i32(i32 %_, i32 %x, i32 %y) { ; RV32: # %bb.0: ; RV32-NEXT: not a3, a2 ; RV32-NEXT: slli a0, a0, 1 -; RV32-NEXT: srl a1, a1, a2 ; RV32-NEXT: sll a0, a0, a3 -; RV32-NEXT: or a1, a1, a1 -; RV32-NEXT: or a0, a1, a0 +; RV32-NEXT: srl a1, a1, a2 +; RV32-NEXT: or a0, a0, a1 ; RV32-NEXT: ret ; ; RV64-LABEL: test_fshr_i32: ; RV64: # %bb.0: ; RV64-NEXT: not a3, a2 ; RV64-NEXT: slli a0, a0, 1 -; RV64-NEXT: srlw a1, a1, a2 ; RV64-NEXT: sllw a0, a0, a3 -; RV64-NEXT: or a1, a1, a1 -; RV64-NEXT: or a0, a1, a0 +; RV64-NEXT: srlw a1, a1, a2 +; RV64-NEXT: or a0, a0, a1 ; RV64-NEXT: ret %fshr = call i32 @llvm.fshr.i32(i32 %_, i32 %x, i32 %y) %lshr = lshr i32 %x, %y