]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
LoongArch: Add bit reverse operations
authorXi Ruoyao <xry111@xry111.site>
Mon, 2 Dec 2024 02:53:27 +0000 (10:53 +0800)
committerXi Ruoyao <xry111@xry111.site>
Wed, 18 Dec 2024 08:43:37 +0000 (16:43 +0800)
LoongArch supports native bit reverse operation for QI, SI, DI, and for
HI we can expand it into a shift and a bit reverse in word_mode.

I was reluctant to add them because until PR50481 is fixed these
operations will be just useless.  But now it turns out we can use them
to optimize the bit reversing CRC calculation if recognized by the
generic CRC pass.  So add them in prepare for the next patch adding CRC
expanders.

gcc/ChangeLog:

* config/loongarch/loongarch.md (@rbit<mode:GPR>): New
define_insn template.
(rbitsi_extended): New define_insn.
(rbitqi): New define_insn.
(rbithi): New define_expand.

gcc/config/loongarch/loongarch.md

index bf322240271ce3333b491224e3dcd3dbd1bae4b6..fe1678c5891b98c971178567a43720a401e37777 100644 (file)
   [(set_attr "type" "unknown")
    (set_attr "mode" "DI")])
 
+(define_insn "@rbit<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+       (bitreverse:GPR (match_operand:GPR 1 "register_operand" "r")))]
+  ""
+  "bitrev.<size>\t%0,%1"
+  [(set_attr "type" "unknown")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "rbitsi_extended"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (sign_extend:DI
+         (bitreverse:SI (match_operand:SI 1 "register_operand" "r"))))]
+  "TARGET_64BIT"
+  "bitrev.w\t%0,%1"
+  [(set_attr "type" "unknown")
+   (set_attr "mode" "SI")])
+
+;; If we don't care high bits, bitrev.4b can reverse bits of values in
+;; QImode.
+(define_insn "rbitqi"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (bitreverse:QI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "bitrev.4b\t%0,%1"
+  [(set_attr "type" "unknown")
+   (set_attr "mode" "SI")])
+
+;; For HImode it's a little complicated...
+(define_expand "rbithi"
+  [(match_operand:HI 0 "register_operand")
+   (match_operand:HI 1 "register_operand")]
+  ""
+  {
+    rtx t = gen_reg_rtx (word_mode);
+
+    /* Oh, using paradoxical subreg.  I learnt the trick from RISC-V,
+       hoping we won't be blown up altogether one day.  */
+    emit_insn (gen_rbit(word_mode, t,
+                       gen_lowpart (word_mode, operands[1])));
+    t = expand_simple_binop (word_mode, LSHIFTRT, t,
+                            GEN_INT (GET_MODE_BITSIZE (word_mode) - 16),
+                            NULL_RTX, false, OPTAB_DIRECT);
+
+    t = gen_lowpart (HImode, t);
+    SUBREG_PROMOTED_VAR_P (t) = 1;
+    SUBREG_PROMOTED_SET (t, SRP_UNSIGNED);
+    emit_move_insn (operands[0], t);
+
+    DONE;
+  })
+
 (define_insn "@stack_tie<mode>"
   [(set (mem:BLK (scratch))
        (unspec:BLK [(match_operand:X 0 "register_operand" "r")