[PATCH-2v2,rs6000] Enable vector mode for memory equality compare [PR111449]
Checks
Commit Message
Hi,
This patch enables vector mode for memory equality compare by adding
a new expand cbranchv16qi4 and implementing it. Also the corresponding
CC reg and compare code is set in rs6000_generate_compare. With the
patch, 16-byte equality compare can be implemented by one vector compare
instructions other than two 8-byte compares with branches.
The vector mode compare is only enabled on powerpc64 as TImode hasn't
be supported on 32 bit platform. By setting MOVE_MAX_PIECES to 16, TImode
compare might be generated.
Compared to last version, the main change is to add guard "TARGET_VSX"
to the expand as it's required by unaligned vector load.
Bootstrapped and tested on powerpc64-linux BE and LE with no
regressions.
Thanks
Gui Haochen
ChangeLog
rs6000: Enable vector compare for memory equality compare
gcc/
PR target/111449
* config/rs6000/altivec.md (cbranchv16qi4): New expand pattern.
* config/rs6000/rs6000.cc (rs6000_generate_compare): Generate insn
sequence for V16QImode equality compare.
* config/rs6000/rs6000.h (MOVE_MAX_PIECES): Define.
(COMPARE_MAX_PIECES): Define.
(STORE_MAX_PIECES): Define.
gcc/testsuite/
PR target/111449
* gcc.target/powerpc/pr111449.c: New.
patch.diff
@@ -2605,6 +2605,42 @@ (define_insn "altivec_vupklpx"
}
[(set_attr "type" "vecperm")])
+(define_expand "cbranchv16qi4"
+ [(use (match_operator 0 "equality_operator"
+ [(match_operand:V16QI 1 "reg_or_mem_operand")
+ (match_operand:V16QI 2 "reg_or_mem_operand")]))
+ (use (match_operand 3))]
+ "VECTOR_UNIT_ALTIVEC_P (V16QImode)
+ && TARGET_VSX"
+{
+ if (!TARGET_P9_VECTOR
+ && !BYTES_BIG_ENDIAN
+ && MEM_P (operands[1])
+ && !altivec_indexed_or_indirect_operand (operands[1], V16QImode)
+ && MEM_P (operands[2])
+ && !altivec_indexed_or_indirect_operand (operands[2], V16QImode))
+ {
+ /* Use direct move for P8 little endian to skip bswap, as the byte
+ order doesn't matter for equality compare. */
+ rtx reg_op1 = gen_reg_rtx (V16QImode);
+ rtx reg_op2 = gen_reg_rtx (V16QImode);
+ rs6000_emit_le_vsx_permute (reg_op1, operands[1], V16QImode);
+ rs6000_emit_le_vsx_permute (reg_op2, operands[2], V16QImode);
+ operands[1] = reg_op1;
+ operands[2] = reg_op2;
+ }
+ else
+ {
+ operands[1] = force_reg (V16QImode, operands[1]);
+ operands[2] = force_reg (V16QImode, operands[2]);
+ }
+
+ rtx_code code = GET_CODE (operands[0]);
+ operands[0] = gen_rtx_fmt_ee (code, V16QImode, operands[1], operands[2]);
+ rs6000_emit_cbranch (V16QImode, operands);
+ DONE;
+})
+
;; Compare vectors producing a vector result and a predicate, setting CR6 to
;; indicate a combined status
(define_insn "altivec_vcmpequ<VI_char>_p"
@@ -15264,6 +15264,15 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
else
emit_insn (gen_stack_protect_testsi (compare_result, op0, op1b));
}
+ else if (mode == V16QImode)
+ {
+ gcc_assert (code == EQ || code == NE);
+
+ rtx result_vector = gen_reg_rtx (V16QImode);
+ compare_result = gen_rtx_REG (CCmode, CR6_REGNO);
+ emit_insn (gen_altivec_vcmpequb_p (result_vector, op0, op1));
+ code = (code == NE) ? GE : LT;
+ }
else
emit_insn (gen_rtx_SET (compare_result,
gen_rtx_COMPARE (comp_mode, op0, op1)));
@@ -1730,6 +1730,9 @@ typedef struct rs6000_args
in one reasonably fast instruction. */
#define MOVE_MAX (! TARGET_POWERPC64 ? 4 : 8)
#define MAX_MOVE_MAX 8
+#define MOVE_MAX_PIECES (!TARGET_POWERPC64 ? 4 : 16)
+#define COMPARE_MAX_PIECES (!TARGET_POWERPC64 ? 4 : 16)
+#define STORE_MAX_PIECES (!TARGET_POWERPC64 ? 4 : 8)
/* Nonzero if access to memory by bytes is no faster than for words.
Also nonzero if doing byte operations (specifically shifts) in registers
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-maltivec -O2" } */
+/* { dg-require-effective-target has_arch_ppc64 } */
+
+/* Ensure vector comparison is used for 16-byte memory equality compare. */
+
+int compare1 (const char* s1, const char* s2)
+{
+ return __builtin_memcmp (s1, s2, 16) == 0;
+}
+
+int compare2 (const char* s1)
+{
+ return __builtin_memcmp (s1, "0123456789012345", 16) == 0;
+}
+
+/* { dg-final { scan-assembler-times {\mvcmpequb\.} 2 } } */
+/* { dg-final { scan-assembler-not {\mcmpd\M} } } */