[rs6000] Disable generation of scalar modulo instructions
Checks
Commit Message
Disable generation of scalar modulo instructions.
It was recently discovered that the scalar modulo instructions can suffer
noticeable performance issues for certain input values. This patch disables
their generation since the equivalent div/mul/sub sequence does not suffer
the same problem.
Bootstrapped and regression tested on powerpc64le (Power10).
Ok for master and backports after burn in?
-Pat
2023-04-07 Pat Haugen <pthaugen@linux.ibm.com>
gcc/
* config/rs6000/rs6000.h (RS6000_DISABLE_SCALAR_MODULO): New.
* config/rs6000/rs6000.md (mod<mode>3, *mod<mode>3): Use it.
(define_expand umod<mode>3): New.
(define_insn umod<mode>3): Rename to *umod<mode>3 and disable.
gcc/testsuite/
* gcc.target/powerpc/clone1.c: Add xfails.
* gcc.target/powerpc/clone3.c: Likewise.
* gcc.target/powerpc/mod-1.c: Likewise.
* gcc.target/powerpc/mod-2.c: Likewise.
@@ -2492,3 +2492,9 @@ while (0)
rs6000_asm_output_opcode (STREAM); \
} \
while (0)
+
+/* Disable generation of scalar modulo instructions for word/dword due to
+ performance issues with certain input values. This can be removed in the
+ future when the issues have been resolved. */
+#define RS6000_DISABLE_SCALAR_MODULO 1
+
@@ -3421,6 +3421,17 @@ (define_expand "mod<mode>3"
FAIL;
operands[2] = force_reg (<MODE>mode, operands[2]);
+
+ if (RS6000_DISABLE_SCALAR_MODULO)
+ {
+ temp1 = gen_reg_rtx (<MODE>mode);
+ temp2 = gen_reg_rtx (<MODE>mode);
+
+ emit_insn (gen_div<mode>3 (temp1, operands[1], operands[2]));
+ emit_insn (gen_mul<mode>3 (temp2, temp1, operands[2]));
+ emit_insn (gen_sub<mode>3 (operands[0], operands[1], temp2));
+ DONE;
+ }
}
else
{
@@ -3440,17 +3451,42 @@ (define_insn "*mod<mode>3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r,r")
(mod:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "gpc_reg_operand" "r,r")))]
- "TARGET_MODULO"
+ "TARGET_MODULO && !RS6000_DISABLE_SCALAR_MODULO"
"mods<wd> %0,%1,%2"
[(set_attr "type" "div")
(set_attr "size" "<bits>")])
+;; This define_expand can be removed when RS6000_DISABLE_SCALAR_MODULO is
+;; removed.
+(define_expand "umod<mode>3"
+ [(set (match_operand:GPR 0 "gpc_reg_operand")
+ (umod:GPR (match_operand:GPR 1 "gpc_reg_operand")
+ (match_operand:GPR 2 "gpc_reg_operand")))]
+ ""
+{
+ rtx temp1;
+ rtx temp2;
+
+ if (!TARGET_MODULO)
+ FAIL;
+
+ if (RS6000_DISABLE_SCALAR_MODULO)
+ {
+ temp1 = gen_reg_rtx (<MODE>mode);
+ temp2 = gen_reg_rtx (<MODE>mode);
+
+ emit_insn (gen_udiv<mode>3 (temp1, operands[1], operands[2]));
+ emit_insn (gen_mul<mode>3 (temp2, temp1, operands[2]));
+ emit_insn (gen_sub<mode>3 (operands[0], operands[1], temp2));
+ DONE;
+ }
+})
-(define_insn "umod<mode>3"
+(define_insn "*umod<mode>3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r,r")
(umod:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "gpc_reg_operand" "r,r")))]
- "TARGET_MODULO"
+ "TARGET_MODULO && !RS6000_DISABLE_SCALAR_MODULO"
"modu<wd> %0,%1,%2"
[(set_attr "type" "div")
(set_attr "size" "<bits>")])
b/gcc/testsuite/gcc.target/powerpc/clone1.c
@@ -21,6 +21,7 @@ long mod_func_or (long a, long b, long c)
return mod_func (a, b) | c;
}
-/* { dg-final { scan-assembler-times {\mdivd\M} 1 } } */
-/* { dg-final { scan-assembler-times {\mmulld\M} 1 } } */
-/* { dg-final { scan-assembler-times {\mmodsd\M} 1 } } */
+/* { Fail due to RS6000_DISABLE_SCALAR_MODULO. */
+/* { dg-final { scan-assembler-times {\mdivd\M} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\mmulld\M} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\mmodsd\M} 1 { xfail *-*-* } } } */
b/gcc/testsuite/gcc.target/powerpc/clone3.c
@@ -27,7 +27,8 @@ long mod_func_or (long a, long b, long c)
return mod_func (a, b) | c;
}
-/* { dg-final { scan-assembler-times {\mdivd\M} 1 } } */
-/* { dg-final { scan-assembler-times {\mmulld\M} 1 } } */
-/* { dg-final { scan-assembler-times {\mmodsd\M} 2 } } */
+/* { Fail due to RS6000_DISABLE_SCALAR_MODULO. */
+/* { dg-final { scan-assembler-times {\mdivd\M} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\mmulld\M} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\mmodsd\M} 2 { xfail *-*-* } } } */
/* { dg-final { scan-assembler-times {\mpld\M} 1 } } */
b/gcc/testsuite/gcc.target/powerpc/mod-1.c
@@ -7,13 +7,14 @@ long lsmod (long a, long b) { return a%b; }
unsigned int iumod (unsigned int a, unsigned int b) { return a%b; }
unsigned long lumod (unsigned long a, unsigned long b) { return a%b; }
-/* { dg-final { scan-assembler-times "modsw " 1 } } */
-/* { dg-final { scan-assembler-times "modsd " 1 } } */
-/* { dg-final { scan-assembler-times "moduw " 1 } } */
-/* { dg-final { scan-assembler-times "modud " 1 } } */
-/* { dg-final { scan-assembler-not "mullw " } } */
-/* { dg-final { scan-assembler-not "mulld " } } */
-/* { dg-final { scan-assembler-not "divw " } } */
-/* { dg-final { scan-assembler-not "divd " } } */
-/* { dg-final { scan-assembler-not "divwu " } } */
-/* { dg-final { scan-assembler-not "divdu " } } */
+/* { Fail due to RS6000_DISABLE_SCALAR_MODULO. */
+/* { dg-final { scan-assembler-times "modsw " 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times "modsd " 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times "moduw " 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times "modud " 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "mullw " { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "mulld " { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "divw " { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "divd " { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "divwu " { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "divdu " { xfail *-*-* } } } */
b/gcc/testsuite/gcc.target/powerpc/mod-2.c
@@ -5,8 +5,9 @@
int ismod (int a, int b) { return a%b; }
unsigned int iumod (unsigned int a, unsigned int b) { return a%b; }
-/* { dg-final { scan-assembler-times "modsw " 1 } } */
-/* { dg-final { scan-assembler-times "moduw " 1 } } */
-/* { dg-final { scan-assembler-not "mullw " } } */
-/* { dg-final { scan-assembler-not "divw " } } */
-/* { dg-final { scan-assembler-not "divwu " } } */
+/* { Fail due to RS6000_DISABLE_SCALAR_MODULO. */
+/* { dg-final { scan-assembler-times "modsw " 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times "moduw " 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "mullw " { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "divw " { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "divwu " { xfail *-*-* } } } */