https://gcc.gnu.org/g:097d4b8470de9e8eaa5a230b33486c1639cb6181
commit 097d4b8470de9e8eaa5a230b33486c1639cb6181 Author: Jeff Law <[email protected]> Date: Tue Nov 11 07:17:12 2025 -0700 [RISC-V] Simplify riscv_extend_to_xmode_reg So I was trying to untangle our define_insn_and_split situation for zero-extensions and stumbled over some code we need to adjust & simplify in the RISC-V backend. I probably should have caught this earlier. riscv_extend_to_xmode_reg is just a poor implementation of convert_modes; we can replace the whole thing will a call to convert_modes + force_reg. Why is this important beyond code hygene? convert_modes works with the expansion code wheres extend_to_xmode_reg makes assumptions about the kinds of insns the target directly supports. This shows up if you try to untangle the zero-extension support where the base ISA doesn't support zero extensions and should be going through an expander rather than using a define_insn_and_split. The define_insn_and_split for the reg->reg case isn't split until after reload. Naturally this inhibits some optimizations and forces further work in this space that should be simple define_splits into also needing to be define_insn_and_splits. Anyway, without going further into the zero-extend rathole, this removes the assumption that the target is providing a single insn zero/sign extension thus allowing me to continue to untangle that mess. Bootstrapped and regression tested on the Pioneer (which thoroughly exercises this code as it does not have the B extension. I don't think the BPI has picked up this one yet. Also built and regression tested riscv32-elf and riscv64-elf. Waiting on pre-commit CI before moving forward. * config/riscv/riscv.cc (riscv_extend_to_xmode_reg): Simplify by using convert_modes + force_reg. (cherry picked from commit 225661f15bad3d4545c8afe056160bceb19a4bad) Diff: --- gcc/config/riscv/riscv.cc | 76 ++--------------------------------------------- 1 file changed, 3 insertions(+), 73 deletions(-) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 72035b618acd..1e594c34ad28 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -14128,84 +14128,14 @@ riscv_get_raw_result_mode (int regno) return default_get_reg_raw_mode (regno); } -/* Generate a REG rtx of Xmode from the given rtx and mode. - The rtx x can be REG (QI/HI/SI/DI) or const_int. - The machine_mode mode is the original mode from define pattern. - The rtx_code can be ZERO_EXTEND or SIGN_EXTEND. - - If rtx is REG: - - 1. If rtx Xmode, the RTX x will be returned directly. - 2. If rtx non-Xmode, the value extended into a new REG of Xmode will be - returned. - - The scalar ALU like add don't support non-Xmode like QI/HI. Then the - gen_lowpart will have problem here. For example, when we would like - to add -1 (0xff if QImode) and 2 (0x2 if QImode). The 0xff and 0x2 will - be loaded to register for adding. Aka: - - 0xff + 0x2 = 0x101 instead of -1 + 2 = 1. - - Thus we need to sign extend 0xff to 0xffffffffffffffff if Xmode is DImode - for correctness. Similar the unsigned also need zero extend. - - If rtx is const_int: - - 1. A new REG rtx will be created to hold the value of const_int. - - According to the gccint doc, the constants generated for modes with fewer - bits than in HOST_WIDE_INT must be sign extended to full width. Thus there - will be two cases here, take QImode as example. - - For .SAT_SUB (127, y) in QImode, we have (const_int 127) and one simple - mov from const_int to the new REG rtx is good enough here. - - For .SAT_SUB (254, y) in QImode, we have (const_int -2) after define_expand. - Aka 0xfffffffffffffffe in Xmode of RV64 but we actually need 0xfe in Xmode - of RV64. So we need to cleanup the highest 56 bits of the new REG rtx moved - from the (const_int -2). - - Then the underlying expanding can perform the code generation based on - the REG rtx of Xmode, instead of taking care of these in expand func. */ - +/* Force X into an Xmode register. */ static rtx riscv_extend_to_xmode_reg (rtx x, machine_mode mode, enum rtx_code rcode) { gcc_assert (rcode == ZERO_EXTEND || rcode == SIGN_EXTEND); - rtx xmode_reg = gen_reg_rtx (Xmode); - - if (CONST_INT_P (x)) - { - if (mode == Xmode) - emit_move_insn (xmode_reg, x); - else if (rcode == ZERO_EXTEND) - { - /* Combine deliberately does not simplify extensions of constants - (long story). So try to generate the zero extended constant - efficiently. - - First extract the constant and mask off all the bits not in - MODE. */ - HOST_WIDE_INT val = INTVAL (x); - val &= GET_MODE_MASK (mode); - - /* X may need synthesis, so do not blindly copy it. */ - xmode_reg = force_reg (Xmode, gen_int_mode (val, Xmode)); - } - else /* SIGN_EXTEND. */ - { - rtx x_reg = gen_reg_rtx (mode); - emit_move_insn (x_reg, x); - riscv_emit_unary (rcode, xmode_reg, x_reg); - } - } - else if (mode == Xmode) - return x; - else - riscv_emit_unary (rcode, xmode_reg, x); - - return xmode_reg; + rtx t = convert_modes (Xmode, mode, x, rcode == ZERO_EXTEND); + return force_reg (Xmode, t); } /* Implements the unsigned saturation add standard name usadd for int mode.
