"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")
"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")
"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>"
(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)))