PR83926 shows a problem in expanding the _builtin_vsx_{div,udiv,mul}_2di builtins in 32-bit mode. The problem is that the splitters for the patterns explicitly call gen_{div,udiv,mul}di3 patterns, even in 32-bit mode and those patterns assume the associated 64-bit HW instructions exist when they do not. The "fix" implemented here is to modify gen_{div,udiv,mul} to catch the case when we have DImode operands in 32-bit mode (and not using -mpowerpc64) and do the right thing. In the case of gen_{div,udiv}di3, that means calling their lib functions and for gen_muldi3, we call expand_mult() which emits code that does the 64-bit multiply.
This passes bootstrap and regtesting on powerpc64le-linux, as well as on powerpc64-linux (running the testsuite in both 32-bit and 64-bit modes). Ok for trunk? Peter gcc/ PR target/83926 * config/rs6000/rs6000.md (*mul<mode>3): Rename to this... (mul<mode>3): ...from this. Declare new define_expand. (*udiv<mode>3): Rename to this... (udiv<mode>3): ...from this. Declare new define_expand. (div<mode>3): Handle DImode operands in 32-bit mode. gcc/testsuite/ PR target/83926 * gcc.target/powerpc/pr83926.c: New test. Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 257390) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -2872,8 +2872,21 @@ DONE; }") +(define_expand "mul<mode>3" + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (mult:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "reg_or_short_operand" "")))] + "" +{ + if (<MODE>mode == DImode && !TARGET_POWERPC64) + { + rtx ret = expand_mult (DImode, operands[1], operands[2], NULL, 0, false); + emit_move_insn (operands[0], ret); + DONE; + } +}) -(define_insn "mul<mode>3" +(define_insn "*mul<mode>3" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r") (mult:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r") (match_operand:GPR 2 "reg_or_short_operand" "r,I")))] @@ -3040,7 +3053,25 @@ "maddld %0,%1,%2,%3" [(set_attr "type" "mul")]) -(define_insn "udiv<mode>3" +(define_expand "udiv<mode>3" + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (udiv:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "gpc_reg_operand" "")))] + "" +{ + if (<MODE>mode == DImode && !TARGET_POWERPC64) + { + rtx libfunc = optab_libfunc (udiv_optab, <MODE>mode); + rtx target = emit_library_call_value (libfunc, + operands[0], LCT_NORMAL, <MODE>mode, + operands[1], <MODE>mode, + operands[2], <MODE>mode); + emit_move_insn (operands[0], target); + DONE; + } +}) + +(define_insn "*udiv<mode>3" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (udiv:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") (match_operand:GPR 2 "gpc_reg_operand" "r")))] @@ -3066,7 +3097,16 @@ emit_insn (gen_div<mode>3_sra (operands[0], operands[1], operands[2])); DONE; } - + else if (<MODE>mode == DImode && !TARGET_POWERPC64) + { + rtx libfunc = optab_libfunc (sdiv_optab, <MODE>mode); + rtx target = emit_library_call_value (libfunc, + operands[0], LCT_NORMAL, <MODE>mode, + operands[1], <MODE>mode, + operands[2], <MODE>mode); + emit_move_insn (operands[0], target); + DONE; + } operands[2] = force_reg (<MODE>mode, operands[2]); }) Index: gcc/testsuite/gcc.target/powerpc/pr83926.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/pr83926.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr83926.c (working copy) @@ -0,0 +1,22 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */ +/* { dg-options "-O2 -mcpu=power8 -mno-fold-gimple" } */ + +__attribute__ ((altivec(vector__))) long long +sdiv (__attribute__ ((altivec(vector__))) long long a, + __attribute__ ((altivec(vector__))) long long b) +{ + return __builtin_vsx_div_2di (a, b); +} +__attribute__ ((altivec(vector__))) unsigned long long +udiv (__attribute__ ((altivec(vector__))) unsigned long long a, + __attribute__ ((altivec(vector__))) unsigned long long b) +{ + return __builtin_vsx_udiv_2di (a, b); +} +__attribute__ ((altivec(vector__))) long long +smul (__attribute__ ((altivec(vector__))) long long a, + __attribute__ ((altivec(vector__))) long long b) +{ + return __builtin_vsx_mul_2di (a, b); +}