https://gcc.gnu.org/g:145e462d557af537d90ef6da1391a57603c6fcf0

commit r15-6407-g145e462d557af537d90ef6da1391a57603c6fcf0
Author: Jeff Law <j...@ventanamicro.com>
Date:   Sat Dec 21 08:33:36 2024 -0700

    [RISC-V][PR middle-end/118084] Fix brev based reflection code
    
    The fuzzer tripped over a risc-v target issue in the expansion of CRCs.
    In particular we want to use brev instruction to improve the reflection
    code.
    
    In the case where the item to be reflected is smaller than a word we
    would end up triggering an ICE due to mode mismatching since the
    expansion code asks for the operation in word_mode.
    
    I was briefly confused by the multiple calls into this code, but we have
    to reflect multiple values and those calls may be reflecting different
    sized items.  So seeing one in SI, then another in QI is sensible.
    
    The fix is pretty simple.  In theory the item being reflected should
    always be word_size or smaller.  So an assertion is added to verify
    that.  If the item's size is smaller than a word, we can use a
    paradoxical subreg.  The logical right shift after the brev should zero
    out any extraneous bits.
    
    It's unclear why we're passing a pointer to an RTX in this code.  I left
    that as-is, but we can simplify the code a little bit by doing the
    dereference early and using the dereferenced value.
    
            PR middle-end/118084
    gcc/
            * config/riscv/riscv.cc (generate_reflecting_code_using_brev): 
Handle
            sub-word sized objects correctly.
    
    gcc/testsuite/
            * gcc.target/riscv/pr118084.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                 | 21 +++++++++++++++------
 gcc/testsuite/gcc.target/riscv/pr118084.c | 13 +++++++++++++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 4f1f9defc801..1374868eddfb 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -13602,18 +13602,27 @@ riscv_use_by_pieces_infrastructure_p (unsigned 
HOST_WIDE_INT size,
    we will get the desired one: 1000 1111.  */
 
 void
-generate_reflecting_code_using_brev (rtx *op)
+generate_reflecting_code_using_brev (rtx *op_p)
 {
-  machine_mode op_mode = GET_MODE (*op);
+  rtx op = *op_p;
+  machine_mode op_mode = GET_MODE (op);
+
+  /* OP may be smaller than a word.  We can use a paradoxical subreg
+     to compensate for that.  It should never be larger than a word
+     for RISC-V.  */
+  gcc_assert (op_mode <= word_mode);
+  if (op_mode != word_mode)
+    op = gen_lowpart (word_mode, op);
+
   HOST_WIDE_INT shift_val = (BITS_PER_WORD
                             - GET_MODE_BITSIZE (op_mode).to_constant ());
-  riscv_expand_op (BSWAP, word_mode, *op, *op, *op);
-  riscv_expand_op (LSHIFTRT, word_mode, *op, *op,
+  riscv_expand_op (BSWAP, word_mode, op, op, op);
+  riscv_expand_op (LSHIFTRT, word_mode, op, op,
                   gen_int_mode (shift_val, word_mode));
   if (TARGET_64BIT)
-    emit_insn (gen_riscv_brev8_di (*op, *op));
+    emit_insn (gen_riscv_brev8_di (op, op));
   else
-    emit_insn (gen_riscv_brev8_si (*op, *op));
+    emit_insn (gen_riscv_brev8_si (op, op));
 }
 
 
diff --git a/gcc/testsuite/gcc.target/riscv/pr118084.c 
b/gcc/testsuite/gcc.target/riscv/pr118084.c
new file mode 100644
index 000000000000..2ffa1d76c9b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr118084.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv32izk -mabi=ilp32 -Os" } */
+unsigned a;
+int main() {
+  int b = 8;
+  for (; b; b--)
+    if (a & 1)
+      a = a >> 1 ^ 30196000;
+    else
+      a >>= 1;
+}
+
+

Reply via email to