(ctz "ctz")
(popcount "cpop")])
+(define_mode_attr shiftm1 [(SI "const31_operand") (DI "const63_operand")])
;; ZBA extension.
"TARGET_ZBB"
"<bitmanip_insn>\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
+
+;; ZBS extension.
+
+(define_insn "*bset<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (ior:X (ashift:X (const_int 1)
+ (match_operand:QI 2 "register_operand" "r"))
+ (match_operand:X 1 "register_operand" "r")))]
+ "TARGET_ZBS"
+ "bset\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bset<mode>_mask"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (ior:X (ashift:X (const_int 1)
+ (subreg:QI
+ (and:X (match_operand:X 2 "register_operand" "r")
+ (match_operand 3 "<X:shiftm1>" "i")) 0))
+ (match_operand:X 1 "register_operand" "r")))]
+ "TARGET_ZBS"
+ "bset\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bset<mode>_1"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (ashift:X (const_int 1)
+ (match_operand:QI 1 "register_operand" "r")))]
+ "TARGET_ZBS"
+ "bset\t%0,x0,%1"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bset<mode>_1_mask"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (ashift:X (const_int 1)
+ (subreg:QI
+ (and:X (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "<X:shiftm1>" "i")) 0)))]
+ "TARGET_ZBS"
+ "bset\t%0,x0,%1"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bseti<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (ior:X (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "single_bit_mask_operand" "i")))]
+ "TARGET_ZBS"
+ "bseti\t%0,%1,%S2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bclr<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (and:X (rotate:X (const_int -2)
+ (match_operand:QI 2 "register_operand" "r"))
+ (match_operand:X 1 "register_operand" "r")))]
+ "TARGET_ZBS"
+ "bclr\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bclri<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (and:X (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "not_single_bit_mask_operand" "i")))]
+ "TARGET_ZBS"
+ "bclri\t%0,%1,%T2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*binv<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (xor:X (ashift:X (const_int 1)
+ (match_operand:QI 2 "register_operand" "r"))
+ (match_operand:X 1 "register_operand" "r")))]
+ "TARGET_ZBS"
+ "binv\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*binvi<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (xor:X (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "single_bit_mask_operand" "i")))]
+ "TARGET_ZBS"
+ "binvi\t%0,%1,%S2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bext<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (zero_extract:X (match_operand:X 1 "register_operand" "r")
+ (const_int 1)
+ (zero_extend:X
+ (match_operand:QI 2 "register_operand" "r"))))]
+ "TARGET_ZBS"
+ "bext\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+(define_insn "*bexti"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (zero_extract:X (match_operand:X 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand 2 "immediate_operand" "i")))]
+ "TARGET_ZBS"
+ "bexti\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
return false;
+ /* Check whether the constant can be loaded in a single
+ instruction with zbs extensions. */
+ if (TARGET_64BIT && TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (INTVAL (op)))
+ return false;
+
/* Otherwise check whether the constant can be loaded in a single
instruction. */
return !LUI_OPERAND (INTVAL (op)) && !SMALL_OPERAND (INTVAL (op));
{
return riscv_gpr_save_operation_p (op);
})
+
+;; Predicates for the ZBS extension.
+(define_predicate "single_bit_mask_operand"
+ (and (match_code "const_int")
+ (match_test "pow2p_hwi (INTVAL (op))")))
+
+(define_predicate "not_single_bit_mask_operand"
+ (and (match_code "const_int")
+ (match_test "pow2p_hwi (~INTVAL (op))")))
+
+(define_predicate "const31_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL (op) == 31")))
+
+(define_predicate "const63_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL (op) == 63")))
codes[0].value = value;
return 1;
}
+ if (TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (value))
+ {
+ /* Simply BSETI. */
+ codes[0].code = UNKNOWN;
+ codes[0].value = value;
+ return 1;
+ }
/* End with ADDI. When constructing HImode constants, do not generate any
intermediate value that is not itself a valid HImode constant. The
}
if (src_code == CONST_INT)
- return "li\t%0,%1";
+ {
+ if (SMALL_OPERAND (INTVAL (src)) || LUI_OPERAND (INTVAL (src)))
+ return "li\t%0,%1";
+
+ if (TARGET_ZBS
+ && SINGLE_BIT_MASK_OPERAND (INTVAL (src)))
+ return "bseti\t%0,zero,%S1";
+
+ /* Should never reach here. */
+ abort ();
+ }
if (src_code == HIGH)
return "lui\t%0,%h1";
'A' Print the atomic operation suffix for memory model OP.
'F' Print a FENCE if the memory model requires a release.
'z' Print x0 if OP is zero, otherwise print OP normally.
- 'i' Print i if the operand is not a register. */
+ 'i' Print i if the operand is not a register.
+ 'S' Print shift-index of single-bit mask OP.
+ 'T' Print shift-index of inverted single-bit mask OP. */
static void
riscv_print_operand (FILE *file, rtx op, int letter)
fputs ("i", file);
break;
+ case 'S':
+ {
+ rtx newop = GEN_INT (ctz_hwi (INTVAL (op)));
+ output_addr_const (file, newop);
+ break;
+ }
+ case 'T':
+ {
+ rtx newop = GEN_INT (ctz_hwi (~INTVAL (op)));
+ output_addr_const (file, newop);
+ break;
+ }
default:
switch (code)
{
(((VALUE) | ((1UL<<31) - IMM_REACH)) == ((1UL<<31) - IMM_REACH) \
|| ((VALUE) | ((1UL<<31) - IMM_REACH)) + IMM_REACH == 0)
+/* If this is a single bit mask, then we can load it with bseti. But this
+ is not useful for any of the low 31 bits because we can use addi or lui
+ to load them. It is wrong for loading SImode 0x80000000 on rv64 because it
+ needs to be sign-extended. So we restrict this to the upper 32-bits
+ only. */
+#define SINGLE_BIT_MASK_OPERAND(VALUE) \
+ (pow2p_hwi (VALUE) && (ctz_hwi (VALUE) >= 32))
+
/* Stack layout; function entry, exit and calling. */
#define STACK_GROWS_DOWNWARD 1
/* { dg-do compile } */
-/* { dg-options "-march=rv64gc_zba -mabi=lp64 -O2" } */
+/* { dg-options "-march=rv64gc_zba_zbs -mabi=lp64 -O2" } */
long
foo (long i)
}
/* XXX: This pattern need combine improvement or intermediate instruction
* from zbs. */
-/* { dg-final { scan-assembler-not "slli.uw" } } */
+/* { dg-final { scan-assembler "slli.uw" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* bclr */
+long
+foo0 (long i, long j)
+{
+ return i & ~(1L << j);
+}
+
+/* bclri */
+long
+foo1 (long i)
+{
+ return i & ~(1L << 20);
+}
+
+/* { dg-final { scan-assembler-times "bclr\t" 1 } } */
+/* { dg-final { scan-assembler-times "bclri\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* bext */
+long
+foo0 (long i, long j)
+{
+ return 1L & (i >> j);
+}
+
+/* bexti */
+long
+foo1 (long i)
+{
+ return 1L & (i >> 20);
+}
+
+/* { dg-final { scan-assembler-times "bexti\t" 1 } } */
+/* { dg-final { scan-assembler-times "bext\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* binv */
+long
+foo0 (long i, long j)
+{
+ return i ^ (1L << j);
+}
+
+/* binvi */
+long
+foo1 (long i)
+{
+ return i ^ (1L << 20);
+}
+
+/* { dg-final { scan-assembler-times "binv\t" 1 } } */
+/* { dg-final { scan-assembler-times "binvi\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* bset */
+long
+sub0 (long i, long j)
+{
+ return i | (1L << j);
+}
+
+/* bset_mask */
+long
+sub1 (long i, long j)
+{
+ return i | (1L << (j & 0x3f));
+}
+
+/* bset_1 */
+long
+sub2 (long i)
+{
+ return 1L << i;
+}
+
+/* bset_1_mask */
+long
+sub3 (long i)
+{
+ return 1L << (i & 0x3f);
+}
+
+/* bseti */
+long
+sub4 (long i)
+{
+ return i | (1L << 20);
+}
+
+/* { dg-final { scan-assembler-times "bset\t" 4 } } */
+/* { dg-final { scan-assembler-times "bseti\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */