+2019-04-02 Andreas Krebbel <krebbel@linux.ibm.com>
+
+ * config/s390/s390.c (s390_canonicalize_comparison): Convert
+ certain compares for arch13 in order to make use of the condition
+ code result produced by the new instructions.
+ (s390_rtx_costs): Adjust the costs for nnrk, nngrk, nork, nogrk,
+ nxrk, and nxgrk instruction patterns.
+ * config/s390/s390.md (ANDOR, bitops_name, inv_bitops_name)
+ (inv_no): Add new code iterator together with some attributes.
+ ("*andc_split_<mode>"): Disable splitter for arch13.
+ ("*<ANDOR:bitops_name>c<GPR:mode>_cc")
+ ("*<ANDOR:bitops_name>c<GPR:mode>_cconly")
+ ("*<ANDOR:bitops_name>c<GPR:mode>")
+ ("*n<ANDOR:inv_bitops_name><GPR:mode>_cc")
+ ("*n<ANDOR:inv_bitops_name><mode>_cconly")
+ ("*n<ANDOR:inv_bitops_name><mode>", "*nxor<GPR:mode>_cc")
+ ("*nxor<mode>_cconly", "*nxor<mode>"): New insn definitions.
+
2019-04-02 Andreas Krebbel <krebbel@linux.ibm.com>
* common/config/s390/s390-common.c (processor_flags_table): New
*op0 = XEXP (*op0, 0);
}
}
+
+ /* ~a==b -> ~(a^b)==0 ~a!=b -> ~(a^b)!=0 */
+ if (TARGET_ARCH13
+ && (*code == EQ || *code == NE)
+ && (GET_MODE (*op0) == DImode || GET_MODE (*op0) == SImode)
+ && GET_CODE (*op0) == NOT)
+ {
+ machine_mode mode = GET_MODE (*op0);
+ *op0 = gen_rtx_XOR (mode, XEXP (*op0, 0), *op1);
+ *op0 = gen_rtx_NOT (mode, *op0);
+ *op1 = const0_rtx;
+ }
+
+ /* a&b == -1 -> ~a|~b == 0 a|b == -1 -> ~a&~b == 0 */
+ if (TARGET_ARCH13
+ && (*code == EQ || *code == NE)
+ && (GET_CODE (*op0) == AND || GET_CODE (*op0) == IOR)
+ && (GET_MODE (*op0) == DImode || GET_MODE (*op0) == SImode)
+ && CONST_INT_P (*op1)
+ && *op1 == constm1_rtx)
+ {
+ machine_mode mode = GET_MODE (*op0);
+ rtx op00 = gen_rtx_NOT (mode, XEXP (*op0, 0));
+ rtx op01 = gen_rtx_NOT (mode, XEXP (*op0, 1));
+
+ if (GET_CODE (*op0) == AND)
+ *op0 = gen_rtx_IOR (mode, op00, op01);
+ else
+ *op0 = gen_rtx_AND (mode, op00, op01);
+
+ *op1 = const0_rtx;
+ }
}
return true;
}
case IOR:
+
+ /* nnrk, nngrk */
+ if (TARGET_ARCH13
+ && (mode == SImode || mode == DImode)
+ && GET_CODE (XEXP (x, 0)) == NOT
+ && GET_CODE (XEXP (x, 1)) == NOT)
+ {
+ *total = COSTS_N_INSNS (1);
+ if (!REG_P (XEXP (XEXP (x, 0), 0)))
+ *total += 1;
+ if (!REG_P (XEXP (XEXP (x, 1), 0)))
+ *total += 1;
+ return true;
+ }
+
/* risbg */
if (GET_CODE (XEXP (x, 0)) == AND
&& GET_CODE (XEXP (x, 1)) == ASHIFT
*total = COSTS_N_INSNS (1);
return true;
}
+
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ case AND:
+ /* nork, nogrk */
+ if (TARGET_ARCH13
+ && (mode == SImode || mode == DImode)
+ && GET_CODE (XEXP (x, 0)) == NOT
+ && GET_CODE (XEXP (x, 1)) == NOT)
+ {
+ *total = COSTS_N_INSNS (1);
+ if (!REG_P (XEXP (XEXP (x, 0), 0)))
+ *total += 1;
+ if (!REG_P (XEXP (XEXP (x, 1), 0)))
+ *total += 1;
+ return true;
+ }
/* fallthrough */
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
case ROTATE:
case ROTATERT:
- case AND:
case XOR:
case NEG:
case NOT:
- *total = COSTS_N_INSNS (1);
- return false;
-
case PLUS:
case MINUS:
*total = COSTS_N_INSNS (1);
case COMPARE:
*total = COSTS_N_INSNS (1);
+
+ /* nxrk, nxgrk ~(a^b)==0 */
+ if (TARGET_ARCH13
+ && GET_CODE (XEXP (x, 0)) == NOT
+ && XEXP (x, 1) == const0_rtx
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == XOR
+ && (GET_MODE (XEXP (x, 0)) == SImode || GET_MODE (XEXP (x, 0)) == DImode)
+ && mode == CCZmode)
+ {
+ if (!REG_P (XEXP (XEXP (XEXP (x, 0), 0), 0)))
+ *total += 1;
+ if (!REG_P (XEXP (XEXP (XEXP (x, 0), 0), 1)))
+ *total += 1;
+ return true;
+ }
+
+ /* nnrk, nngrk, nork, nogrk */
+ if (TARGET_ARCH13
+ && (GET_CODE (XEXP (x, 0)) == AND || GET_CODE (XEXP (x, 0)) == IOR)
+ && XEXP (x, 1) == const0_rtx
+ && (GET_MODE (XEXP (x, 0)) == SImode || GET_MODE (XEXP (x, 0)) == DImode)
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == NOT
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == NOT
+ && mode == CCZmode)
+ {
+ if (!REG_P (XEXP (XEXP (XEXP (x, 0), 0), 0)))
+ *total += 1;
+ if (!REG_P (XEXP (XEXP (XEXP (x, 0), 1), 0)))
+ *total += 1;
+ return true;
+ }
+
if (GET_CODE (XEXP (x, 0)) == AND
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
;; This iterator allows r[ox]sbg to be defined with the same template
(define_code_iterator IXOR [ior xor])
+;; This is used for merging the nand/nor and and/or with complement patterns
+(define_code_iterator ANDOR [and ior])
+(define_code_attr bitops_name [(and "and") (ior "or")])
+(define_code_attr inv_bitops_name [(and "or") (ior "and")])
+(define_code_attr inv_no [(and "o") (ior "n")])
+
;; This iterator is used to expand the patterns for the nearest
;; integer functions.
(define_int_iterator FPINT [UNSPEC_FPINT_FLOOR UNSPEC_FPINT_BTRUNC
(and:GPR (not:GPR (match_operand:GPR 1 "nonimmediate_operand" ""))
(match_operand:GPR 2 "general_operand" "")))
(clobber (reg:CC CC_REGNUM))]
- "! reload_completed
+ "!TARGET_ARCH13
+ && ! reload_completed
&& (GET_CODE (operands[0]) != MEM
/* Ensure that s390_logical_operator_ok_p will succeed even
on the split xor if (b & a) is stored into a pseudo. */
[(set_attr "op_type" "RR,SI,SS")
(set_attr "z10prop" "z10_super_E1,z10_super,*")])
+;
+; And/Or with complement
+;
+
+; ncrk, ncgrk, ocrk, ocgrk
+(define_insn "*<ANDOR:bitops_name>c<GPR:mode>_cc"
+ [(set (reg CC_REGNUM)
+ (compare
+ (ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
+ (match_operand:GPR 2 "register_operand" "d"))
+ (const_int 0)))
+ (set (match_operand:GPR 0 "register_operand" "=d")
+ (ANDOR:GPR (not:GPR (match_dup 1))
+ (match_dup 2)))]
+ "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "<ANDOR:noxa>c<GPR:g>rk\t%0,%2,%1"
+ [(set_attr "op_type" "RRF")])
+
+; ncrk, ncgrk, ocrk, ocgrk
+(define_insn "*<ANDOR:bitops_name>c<GPR:mode>_cconly"
+ [(set (reg CC_REGNUM)
+ (compare
+ (ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
+ (match_operand:GPR 2 "register_operand" "d"))
+ (const_int 0)))
+ (clobber (match_scratch:GPR 0 "=d"))]
+ "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "<ANDOR:noxa>c<GPR:g>rk\t%0,%2,%1"
+ [(set_attr "op_type" "RRF")])
+
+; ncrk, ncgrk, ocrk, ocgrk
+(define_insn "*<ANDOR:bitops_name>c<GPR:mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
+ (match_operand:GPR 2 "register_operand" "d")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARCH13"
+ "<ANDOR:noxa>c<GPR:g>rk\t%0,%2,%1"
+ [(set_attr "op_type" "RRF")])
+
+;
+;- Nand/Nor instructions.
+;
+
+; nnrk, nngrk, nork, nogrk
+(define_insn "*n<ANDOR:inv_bitops_name><GPR:mode>_cc"
+ [(set (reg CC_REGNUM)
+ (compare
+ (ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
+ (not:GPR (match_operand:GPR 2 "register_operand" "d")))
+ (const_int 0)))
+ (set (match_operand:GPR 0 "register_operand" "=d")
+ (ANDOR:GPR (not:GPR (match_dup 1))
+ (not:GPR (match_dup 2))))]
+ "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "n<ANDOR:inv_no><GPR:g>rk\t%0,%1,%2"
+ [(set_attr "op_type" "RRF")])
+
+; nnrk, nngrk, nork, nogrk
+(define_insn "*n<ANDOR:inv_bitops_name><mode>_cconly"
+ [(set (reg CC_REGNUM)
+ (compare
+ (ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
+ (not:GPR (match_operand:GPR 2 "register_operand" "d")))
+ (const_int 0)))
+ (clobber (match_scratch:GPR 0 "=d"))]
+ "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "n<ANDOR:inv_no><GPR:g>rk\t%0,%1,%2"
+ [(set_attr "op_type" "RRF")])
+
+; nnrk, nngrk, nork, nogrk
+(define_insn "*n<ANDOR:inv_bitops_name><mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
+ (not:GPR (match_operand:GPR 2 "register_operand" "d"))))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARCH13"
+ "n<ANDOR:inv_no><GPR:g>rk\t%0,%1,%2"
+ [(set_attr "op_type" "RRF")])
+
+
;
; Block inclusive or (OC) patterns.
;
"operands[4] = gen_rtx_MEM (BLKmode, XEXP (operands[0], 0));
operands[5] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[3]));")
+;
+;- Nxor instructions.
+;
+
+; nxrk, nxgrk
+(define_insn "*nxor<GPR:mode>_cc"
+ [(set (reg CC_REGNUM)
+ (compare
+ (not:GPR (xor:GPR (match_operand:GPR 1 "register_operand" "d")
+ (match_operand:GPR 2 "register_operand" "d")))
+ (const_int 0)))
+ (set (match_operand:GPR 0 "register_operand" "=d")
+ (xor:GPR (not:GPR (match_dup 1))
+ (match_dup 2)))]
+ "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "nx<GPR:g>rk\t%0,%1,%2"
+ [(set_attr "op_type" "RRF")])
+
+; nxrk, nxgrk
+(define_insn "*nxor<mode>_cconly"
+ [(set (reg CC_REGNUM)
+ (compare
+ (not:GPR (xor:GPR (match_operand:GPR 1 "register_operand" "d")
+ (match_operand:GPR 2 "register_operand" "d")))
+ (const_int 0)))
+ (clobber (match_scratch:GPR 0 "=d"))]
+ "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "nx<GPR:g>rk\t%0,%1,%2"
+ [(set_attr "op_type" "RRF")])
+
+; nxrk, nxgrk
+(define_insn "*nxor<mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (not:GPR (xor:GPR (match_operand:GPR 1 "register_operand" "d")
+ (match_operand:GPR 2 "register_operand" "d"))))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARCH13"
+ "nx<GPR:g>rk\t%0,%1,%2"
+ [(set_attr "op_type" "RRF")])
;;
;;- Negate instructions.
+2019-04-02 Andreas Krebbel <krebbel@linux.ibm.com>
+
+ * gcc.target/s390/arch13/bitops-1.c: New test.
+ * gcc.target/s390/arch13/bitops-2.c: New test.
+ * gcc.target/s390/md/andc-splitter-1.c: Add -march=z14 build
+ option and adjust line numbers.
+ * gcc.target/s390/md/andc-splitter-2.c: Likewise.
+
2019-04-02 Andreas Krebbel <krebbel@linux.ibm.com>
* gcc.target/s390/s390.exp: Run tests in arch13 subdir.
--- /dev/null
+/* { dg-compile } */
+
+/* and with complement */
+
+int
+ncrk (int a, int b)
+{
+ return a & ~b;
+}
+
+/* { dg-final { scan-assembler-times "\tncrk\t" 1 } } */
+
+long long
+ncgrk (long long a, long long b)
+{
+ return a & ~b;
+}
+
+/* { dg-final { scan-assembler-times "\tncgrk\t" 1 } } */
+
+/* or with complement */
+
+int
+ocrk (int a, int b)
+{
+ return a | ~b;
+}
+
+/* { dg-final { scan-assembler-times "\tocrk\t" 1 } } */
+
+long long
+ocgrk (long long a, long long b)
+{
+ return a | ~b;
+}
+
+/* { dg-final { scan-assembler-times "\tocgrk\t" 1 } } */
+
+/* nand */
+
+int
+nnrk (int a, int b)
+{
+ return ~(a & b);
+}
+
+/* { dg-final { scan-assembler-times "\tnnrk\t" 1 } } */
+
+long long
+nngrk (long long a, long long b)
+{
+ return ~(a & b);
+}
+
+/* { dg-final { scan-assembler-times "\tnngrk\t" 1 } } */
+
+/* nor */
+
+int
+nork (int a, int b)
+{
+ return ~(a | b);
+}
+
+/* { dg-final { scan-assembler-times "\tnork\t" 1 } } */
+
+long long
+nogrk (long long a, long long b)
+{
+ return ~(a | b);
+}
+
+/* { dg-final { scan-assembler-times "\tnogrk\t" 1 } } */
+
+/* nxor */
+
+int
+nxrk (int a, int b)
+{
+ return ~(a ^ b);
+}
+
+/* { dg-final { scan-assembler-times "\tnxrk\t" 1 } } */
+
+long long
+nxgrk (long long a, long long b)
+{
+ return ~(a ^ b);
+}
+
+/* { dg-final { scan-assembler-times "\tnxgrk\t" 1 } } */
--- /dev/null
+/* { dg-compile } */
+
+/* Check if the instruction are being used also for compares. */
+
+/* and with complement */
+
+int
+ncrk (int a, int b)
+{
+ return (a & ~b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tncrk\t" 1 } } */
+
+int
+ncgrk (long long a, long long b)
+{
+ return (a & ~b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tncgrk\t" 1 } } */
+
+/* or with complement */
+
+int
+ocrk (int a, int b)
+{
+ return (a | ~b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tocrk\t" 1 } } */
+
+int
+ocgrk (long long a, long long b)
+{
+ return (a | ~b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tocgrk\t" 1 } } */
+
+/* nand */
+
+int
+nnrk (int a, int b)
+{
+ return ~(a & b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tnnrk\t" 1 } } */
+
+int
+nngrk (long long a, long long b)
+{
+ return ~(a & b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tnngrk\t" 1 } } */
+
+/* nor */
+
+int
+nork (int a, int b)
+{
+ return ~(a | b);
+}
+
+/* { dg-final { scan-assembler-times "\tnork\t" 1 } } */
+
+int
+nogrk (long long a, long long b)
+{
+ return ~(a | b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tnogrk\t" 1 } } */
+
+/* nxor */
+
+int
+nxrk (int a, int b)
+{
+ return ~(a ^ b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tnxrk\t" 1 } } */
+
+int
+nxgrk (long long a, long long b)
+{
+ return ~(a ^ b) ? 23 : 42;
+}
+
+/* { dg-final { scan-assembler-times "\tnxgrk\t" 1 } } */
/* Machine description pattern tests. */
/* { dg-do compile { target { lp64 } } } */
-/* { dg-options "-mzarch -save-temps -dP" } */
+/* Starting with arch13 the and with complement instruction is
+ available and the splitter is disabled. */
+/* { dg-options "-march=z14 -mzarch -save-temps -dP" } */
/* { dg-do run { target { lp64 && s390_useable_hw } } } */
/* Skip test if -O0 is present on the command line:
__attribute__ ((noinline))
unsigned long andc_vv(unsigned long a, unsigned long b)
{ return ~b & a; }
-/* { dg-final { scan-assembler ":16:.\* \{\\*anddi3\}" } } */
-/* { dg-final { scan-assembler ":16:.\* \{\\*xordi3\}" } } */
+/* { dg-final { scan-assembler ":18:.\* \{\\*anddi3\}" } } */
+/* { dg-final { scan-assembler ":18:.\* \{\\*xordi3\}" } } */
__attribute__ ((noinline))
unsigned long andc_pv(unsigned long *a, unsigned long b)
{ return ~b & *a; }
-/* { dg-final { scan-assembler ":22:.\* \{\\*anddi3\}" } } */
-/* { dg-final { scan-assembler ":22:.\* \{\\*xordi3\}" } } */
+/* { dg-final { scan-assembler ":24:.\* \{\\*anddi3\}" } } */
+/* { dg-final { scan-assembler ":24:.\* \{\\*xordi3\}" } } */
__attribute__ ((noinline))
unsigned long andc_vp(unsigned long a, unsigned long *b)
{ return ~*b & a; }
-/* { dg-final { scan-assembler ":28:.\* \{\\*anddi3\}" } } */
-/* { dg-final { scan-assembler ":28:.\* \{\\*xordi3\}" } } */
+/* { dg-final { scan-assembler ":30:.\* \{\\*anddi3\}" } } */
+/* { dg-final { scan-assembler ":30:.\* \{\\*xordi3\}" } } */
__attribute__ ((noinline))
unsigned long andc_pp(unsigned long *a, unsigned long *b)
{ return ~*b & *a; }
-/* { dg-final { scan-assembler ":34:.\* \{\\*anddi3\}" } } */
-/* { dg-final { scan-assembler ":34:.\* \{\\*xordi3\}" } } */
+/* { dg-final { scan-assembler ":36:.\* \{\\*anddi3\}" } } */
+/* { dg-final { scan-assembler ":36:.\* \{\\*xordi3\}" } } */
/* { dg-final { scan-assembler-times "\tngr\?k\?\t" 4 } } */
/* { dg-final { scan-assembler-times "\txgr\?\t" 4 } } */
/* Machine description pattern tests. */
/* { dg-do compile } */
-/* { dg-options "-save-temps -dP" } */
+/* Starting with arch13 the and with complement instruction is
+ available and the splitter is disabled. */
+/* { dg-options "-march=z14 -save-temps -dP" } */
/* { dg-do run { target { s390_useable_hw } } } */
/* Skip test if -O0 is present on the command line:
__attribute__ ((noinline))
unsigned int andc_vv(unsigned int a, unsigned int b)
{ return ~b & a; }
-/* { dg-final { scan-assembler ":16:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
-/* { dg-final { scan-assembler ":16:.\* \{\\*xorsi3\}" } } */
+/* { dg-final { scan-assembler ":18:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
+/* { dg-final { scan-assembler ":18:.\* \{\\*xorsi3\}" } } */
__attribute__ ((noinline))
unsigned int andc_pv(unsigned int *a, unsigned int b)
{ return ~b & *a; }
-/* { dg-final { scan-assembler ":22:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
-/* { dg-final { scan-assembler ":22:.\* \{\\*xorsi3\}" } } */
+/* { dg-final { scan-assembler ":24:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
+/* { dg-final { scan-assembler ":24:.\* \{\\*xorsi3\}" } } */
__attribute__ ((noinline))
unsigned int andc_vp(unsigned int a, unsigned int *b)
{ return ~*b & a; }
-/* { dg-final { scan-assembler ":28:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
-/* { dg-final { scan-assembler ":28:.\* \{\\*xorsi3\}" } } */
+/* { dg-final { scan-assembler ":30:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
+/* { dg-final { scan-assembler ":30:.\* \{\\*xorsi3\}" } } */
__attribute__ ((noinline))
unsigned int andc_pp(unsigned int *a, unsigned int *b)
{ return ~*b & *a; }
-/* { dg-final { scan-assembler ":34:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
-/* { dg-final { scan-assembler ":34:.\* \{\\*xorsi3\}" } } */
+/* { dg-final { scan-assembler ":36:.\* \{\\*andsi3_\(esa\|zarch\)\}" } } */
+/* { dg-final { scan-assembler ":36:.\* \{\\*xorsi3\}" } } */
/* { dg-final { scan-assembler-times "\tnr\?k\?\t" 4 } } */
/* { dg-final { scan-assembler-times "\txr\?k\?\t" 4 } } */