rtl_opt_pass * make_pass_vsetvl (gcc::context *ctxt);
/* Routines implemented in riscv-string.c. */
+extern bool riscv_expand_block_compare (rtx, rtx, rtx, rtx);
extern bool riscv_expand_block_move (rtx, rtx, rtx);
extern bool riscv_expand_block_clear (rtx, rtx);
GEN_EMIT_HELPER2(th_tstnbz) /* do_th_tstnbz2 */
GEN_EMIT_HELPER3(xor) /* do_xor3 */
GEN_EMIT_HELPER2(zero_extendqi) /* do_zero_extendqi2 */
+GEN_EMIT_HELPER2(zero_extendhi) /* do_zero_extendhi2 */
#undef GEN_EMIT_HELPER2
#undef GEN_EMIT_HELPER3
-/* Helper function to load a byte or a Pmode register.
+/* Helper function to emit zero-extended loads.
- MODE is the mode to use for the load (QImode or Pmode).
+ MODE is the mode to use for the load.
DEST is the destination register for the data.
- ADDR_REG is the register that holds the address.
- ADDR is the address expression to load from.
-
- This function returns an rtx containing the register,
- where the ADDR is stored. */
+ MEM is the source to load from. */
-static rtx
-do_load_from_addr (machine_mode mode, rtx dest, rtx addr_reg, rtx addr)
+static void
+do_load (machine_mode mode, rtx dest, rtx mem)
{
- rtx mem = gen_rtx_MEM (mode, addr_reg);
- MEM_COPY_ATTRIBUTES (mem, addr);
- set_mem_size (mem, GET_MODE_SIZE (mode));
-
if (mode == QImode)
do_zero_extendqi2 (dest, mem);
+ else if (mode == HImode)
+ do_zero_extendhi2 (dest, mem);
+ else if (mode == SImode && TARGET_64BIT)
+ emit_insn (gen_zero_extendsidi2 (dest, mem));
else if (mode == Xmode)
emit_move_insn (dest, mem);
else
gcc_unreachable ();
+}
+
+/* Helper function to emit zero-extended loads.
+
+ MODE is the mode to use for the load (QImode or Pmode).
+ DEST is the destination register for the data.
+ ADDR_REG is the register that holds the address.
+ ADDR is the address expression to load from. */
+
+static void
+do_load_from_addr (machine_mode mode, rtx dest, rtx addr_reg, rtx addr)
+{
+ rtx mem = gen_rtx_MEM (mode, addr_reg);
+ MEM_COPY_ATTRIBUTES (mem, addr);
+ set_mem_size (mem, GET_MODE_SIZE (mode));
- return addr_reg;
+ do_load (mode, dest, mem);
}
/* Generate a sequence to compare single characters in data1 and data2.
DONE;
})
+(define_expand "cmpmemsi"
+ [(parallel [(set (match_operand:SI 0)
+ (compare:SI (match_operand:BLK 1)
+ (match_operand:BLK 2)))
+ (use (match_operand:SI 3))
+ (use (match_operand:SI 4))])]
+ "!optimize_size"
+{
+ if (riscv_expand_block_compare (operands[0], operands[1], operands[2],
+ operands[3]))
+ DONE;
+ else
+ FAIL;
+})
+
(define_expand "cpymem<mode>"
[(parallel [(set (match_operand:BLK 0 "general_operand")
(match_operand:BLK 1 "general_operand"))
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-march=rv32gc_zbb -save-temps -g0 -fno-lto" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_zbb -save-temps -g0 -fno-lto" { target { rv64 } } } */
+/* { dg-timeout-factor 2 } */
+
+#include "../../gcc.dg/memcmp-1.c"
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_zbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_zbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" "-Oz" } } */
+
+#include <stddef.h>
+#define aligned32 __attribute__ ((aligned (32)))
+
+const char myconst15[] aligned32 = { 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7 };
+const char myconst23[] aligned32 = { 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7 };
+const char myconst31[] aligned32 = { 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7 };
+
+/* No expansion (unknown alignment) */
+#define MY_MEM_CMP_N(N) \
+int my_mem_cmp_##N(const char *b1, const char *b2) \
+{ \
+ return __builtin_memcmp (b1, b2, N); \
+}
+
+/* No expansion (unknown alignment) */
+#define MY_MEM_CMP_CONST_N(N) \
+int my_mem_cmp_const_##N(const char *b1) \
+{ \
+ return __builtin_memcmp (b1, myconst##N, sizeof(myconst##N)); \
+}
+
+MY_MEM_CMP_N(15)
+MY_MEM_CMP_CONST_N(15)
+
+MY_MEM_CMP_N(23)
+MY_MEM_CMP_CONST_N(23)
+
+MY_MEM_CMP_N(31)
+MY_MEM_CMP_CONST_N(31)
+
+/* { dg-final { scan-assembler-times "\t(call|tail)\tmemcmp" 6 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_zbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_zbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" "-Oz" } } */
+
+#include <stddef.h>
+#define aligned32 __attribute__ ((aligned (32)))
+
+const char myconst15[] aligned32 = { 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7 };
+const char myconst23[] aligned32 = { 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7 };
+const char myconst31[] aligned32 = { 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7 };
+
+#define MY_MEM_CMP_ALIGNED_N(N) \
+int my_mem_cmp_aligned_##N(const char *b1, const char *b2) \
+{ \
+ b1 = __builtin_assume_aligned (b1, 4096); \
+ b2 = __builtin_assume_aligned (b2, 4096); \
+ return __builtin_memcmp (b1, b2, N); \
+}
+
+#define MY_MEM_CMP_ALIGNED_CONST_N(N) \
+int my_mem_cmp_aligned_const_##N(const char *b1) \
+{ \
+ b1 = __builtin_assume_aligned (b1, 4096); \
+ return __builtin_memcmp (b1, myconst##N, sizeof(myconst##N)); \
+}
+
+MY_MEM_CMP_ALIGNED_N(15)
+MY_MEM_CMP_ALIGNED_CONST_N(15)
+
+MY_MEM_CMP_ALIGNED_N(23)
+MY_MEM_CMP_ALIGNED_CONST_N(23)
+
+MY_MEM_CMP_ALIGNED_N(31)
+MY_MEM_CMP_ALIGNED_CONST_N(31)
+
+/* { dg-final { scan-assembler-not "\t(call|tail)\tmemcmp" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_zbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_zbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" "-Oz" } } */
+
+#include <stddef.h>
+
+/* No expansion (unknown size) */
+int my_mem_cmp_n(const char *b1, const char *b2, size_t n)
+{
+ return __builtin_memcmp (b1, b2, n);
+}
+
+/* No expansion (unknown size) */
+int my_mem_cmp_aligned(const char *b1, const char *b2, size_t n)
+{
+ b1 = __builtin_assume_aligned (b1, 4096);
+ b2 = __builtin_assume_aligned (b2, 4096);
+ return __builtin_memcmp (b1, b2, n);
+}
+
+/* { dg-final { scan-assembler-times "\t(call|tail)\tmemcmp" 2 } } */