aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/riscv/crypto.md63
-rw-r--r--gcc/config/riscv/iterators.md3
-rw-r--r--gcc/config/riscv/riscv.md9
-rw-r--r--gcc/testsuite/gcc.target/riscv/pack32.c18
-rw-r--r--gcc/testsuite/gcc.target/riscv/pack64.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/packh32.c13
-rw-r--r--gcc/testsuite/gcc.target/riscv/packh64.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/packw.c13
8 files changed, 139 insertions, 3 deletions
diff --git a/gcc/config/riscv/crypto.md b/gcc/config/riscv/crypto.md
index dd2bc94..b632312 100644
--- a/gcc/config/riscv/crypto.md
+++ b/gcc/config/riscv/crypto.md
@@ -104,6 +104,19 @@
"pack\t%0,%1,%2"
[(set_attr "type" "crypto")])
+;; This is slightly more complex than the other pack patterns
+;; that fully expose the RTL as it needs to self-adjust to
+;; rv32 and rv64. But it's not that hard.
+(define_insn "*riscv_xpack_<X:mode>_2"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (ior:X (ashift:X (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "immediate_operand" "n"))
+ (zero_extend:X
+ (match_operand:HX 3 "register_operand" "r"))))]
+ "TARGET_ZBKB && INTVAL (operands[2]) == BITS_PER_WORD / 2"
+ "pack\t%0,%3,%1"
+ [(set_attr "type" "crypto")])
+
(define_insn "riscv_packh_<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(unspec:X [(match_operand:QI 1 "register_operand" "r")
@@ -113,6 +126,29 @@
"packh\t%0,%1,%2"
[(set_attr "type" "crypto")])
+;; So this is both a useful pattern unto itself and a bridge to the
+;; general packh pattern below.
+(define_insn "*riscv_packh_<mode>_2"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (and:X (ashift:X (match_operand:X 1 "register_operand" "r")
+ (const_int 8))
+ (const_int 65280)))]
+ "TARGET_ZBKB"
+ "packh\t%0,x0,%1"
+ [(set_attr "type" "crypto")])
+
+;; While the two operands of the IOR could be swapped, this appears
+;; to be the canonical form. The other form doesn't seem to trigger.
+(define_insn "*riscv_packh_<mode>_3"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (ior:X (and:X (ashift:X (match_operand:X 1 "register_operand" "r")
+ (const_int 8))
+ (const_int 65280))
+ (zero_extend:X (match_operand:QI 2 "register_operand" "r"))))]
+ "TARGET_ZBKB"
+ "packh\t%0,%2,%1"
+ [(set_attr "type" "crypto")])
+
(define_insn "riscv_packw"
[(set (match_operand:DI 0 "register_operand" "=r")
(unspec:DI [(match_operand:HI 1 "register_operand" "r")
@@ -122,6 +158,33 @@
"packw\t%0,%1,%2"
[(set_attr "type" "crypto")])
+;; Implemented as a splitter for initial recognition. It generates
+;; new RTL with the extension moved to the outer position. This
+;; allows later code to eliminate subsequent explicit sign extensions.
+(define_split
+ [(set (match_operand:DI 0 "register_operand")
+ (ior:DI (ashift:DI
+ (sign_extend:DI (match_operand:HI 1 "register_operand"))
+ (const_int 16))
+ (zero_extend:DI (match_operand:HI 2 "register_operand"))))]
+ "TARGET_ZBKB && TARGET_64BIT"
+ [(set (match_dup 0)
+ (sign_extend:DI (ior:SI (ashift:SI (match_dup 1) (const_int 16))
+ (zero_extend:SI (match_dup 2)))))]
+ "operands[1] = gen_lowpart (SImode, operands[1]);")
+
+;; And this patches the result of the splitter above.
+(define_insn "*riscv_packw_2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI
+ (ior:SI
+ (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 16))
+ (zero_extend:SI (match_operand:HI 2 "register_operand" "r")))))]
+ "TARGET_ZBKB && TARGET_64BIT"
+ "packw\t%0,%2,%1"
+ [(set_attr "type" "crypto")])
+
;; ZBKX extension
(define_insn "riscv_xperm4_<mode>"
diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index 8a9d198..3c139bc 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -37,6 +37,9 @@
;; Likewise, but for XLEN-sized quantities.
(define_mode_iterator X [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")])
+;; Likewise, but for XLEN/2 -sized quantities.
+(define_mode_iterator HX [(HI "!TARGET_64BIT") (SI "TARGET_64BIT")])
+
;; Branches operate on XLEN-sized quantities, but for RV64 we accept
;; QImode values so we can force zero-extension.
(define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index fe74b8d..25d341e 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2844,9 +2844,12 @@
(match_operand 2 "immediate_operand" "n"))
(match_operand 3 "immediate_operand" "n")))]
"(!SMALL_OPERAND (INTVAL (operands[3]))
- && SMALL_OPERAND (INTVAL (operands[3]) >> INTVAL (operands[2]))
- && (popcount_hwi (INTVAL (operands[3]))
- <= popcount_hwi (INTVAL (operands[3]) >> INTVAL (operands[2]))))"
+ && SMALL_OPERAND (INTVAL (operands[3]) >> INTVAL (operands[2]))
+ && popcount_hwi (INTVAL (operands[3])) > 1
+ && (!TARGET_64BIT
+ || (exact_log2 ((INTVAL (operands[3]) >> INTVAL (operands[2])) + 1)
+ == -1))
+ && (INTVAL (operands[3]) & ((1ULL << INTVAL (operands[2])) - 1)) == 0)"
"#"
"&& 1"
[(set (match_dup 0) (any_bitwise:X (match_dup 1) (match_dup 3)))
diff --git a/gcc/testsuite/gcc.target/riscv/pack32.c b/gcc/testsuite/gcc.target/riscv/pack32.c
new file mode 100644
index 0000000..24304d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pack32.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv32gc_zbkb -mabi=ilp32" } */
+/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" } } */
+
+#include <stdint-gcc.h>
+
+uint32_t foo1(uint32_t rs1, uint32_t rs2)
+{
+ return (rs1 << 16) | ((rs2 << 16) >> 16);
+}
+
+uint32_t foo2(uint32_t rs1, uint32_t rs2)
+{
+ return (rs1 << 16) | (rs2 & 65535);
+}
+
+/* { dg-final { scan-assembler-times "\\spack\\s" 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/pack64.c b/gcc/testsuite/gcc.target/riscv/pack64.c
new file mode 100644
index 0000000..7f54baa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pack64.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc_zbkb -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" } } */
+#include <stdint-gcc.h>
+
+uint64_t foo1(uint64_t rs1, uint64_t rs2)
+{
+ return (rs1 << 32) | ((rs2 << 32) >> 32);
+}
+
+uint64_t foo2(uint64_t rs1, uint64_t rs2)
+{
+ return (rs1 << 32) | (rs2 & 4294967295);
+}
+
+/* { dg-final { scan-assembler-times "\\spack\\s" 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/packh32.c b/gcc/testsuite/gcc.target/riscv/packh32.c
new file mode 100644
index 0000000..8032241
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/packh32.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv32gc_zbkb -mabi=ilp32" } */
+/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" } } */
+
+#include <stdint-gcc.h>
+
+int32_t foo1(int32_t rs1, int32_t rs2)
+{
+ return (rs1 & 255) | ((rs2 & 255) << 8);
+}
+
+/* { dg-final { scan-assembler-times "\\spackh\\s" 1 } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/packh64.c b/gcc/testsuite/gcc.target/riscv/packh64.c
new file mode 100644
index 0000000..b91d401
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/packh64.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc_zbkb -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" } } */
+#include "packh32.c"
+/* { dg-final { scan-assembler-times "\\spackh\\s" 1 } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/packw.c b/gcc/testsuite/gcc.target/riscv/packw.c
new file mode 100644
index 0000000..c178738
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/packw.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc_zbkb -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" } } */
+#include <stdint-gcc.h>
+
+uint32_t foo1(uint32_t rs1, uint32_t rs2)
+{
+ return (rs1 << 16) | ((rs2 << 16) >> 16);
+}
+
+/* { dg-final { scan-assembler-times "\\spackw\\s" 1 } } */
+/* { dg-final { scan-assembler-not "\\ssext\\s" } } */
+