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.
jeff
* config/riscv/riscv.cc (riscv_extend_to_xmode_reg): Simplify
by using convert_modes + force_reg.
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 7d723fc4d695..2b2fada592f0 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -14144,84 +14144,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.