From 00e641f13e16cc2e1402b17f43df934014a95cfb Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Fri, 21 Nov 2014 14:04:25 +0000 Subject: [PATCH] Forward-port from 2014-10-30 4_9-branch r216934 PR target/63633 gcc/ Forward-port from 2014-10-30 4_9-branch r216934 PR target/63633 * config/avr/avr-protos.h (regmask): New inline function. (avr_fix_inputs, avr_emit3_fix_outputs): New protos. * config/avr/avr.c (avr_fix_operands, avr_move_fixed_operands) (avr_fix_inputs, avr_emit3_fix_outputs): New functions. * config/avr/avr-fixed.md (mulqq3_nomul, muluqq3_nomul) (mul3, mul3, 3, 3) (3, round3): Fix input operands. * config/avr/avr-dimode.md (add3, sub3) (3, 3, cbranch4) (3, mulsidi3): Fix input operands. * config/avr/avr.md (mulqi3_call, mulhi3_call, mulsi3, mulpsi3) (mulusi3, mulssi3, mulohisi3, mulhisi3) (usmulhisi3, mulhi3_highpart, mulsqipsi3) (fmul, fmuls, fmulsu): Fix operands. Turn insn into expander as needed. gcc/testsuite/ Forward-port from 2014-10-30 4_9-branch r216934 PR target/63633 * gcc.target/avr/torture/pr63633-ice-mult.c: New test. From-SVN: r217922 --- gcc/config/avr/avr-dimode.md | 7 ++ gcc/config/avr/avr-fixed.md | 41 +++++-- gcc/config/avr/avr-protos.h | 9 ++ gcc/config/avr/avr.c | 109 +++++++++++++++++ gcc/config/avr/avr.md | 113 ++++++++++++++++-- gcc/testsuite/ChangeLog | 7 ++ .../gcc.target/avr/torture/pr63633-ice-mult.c | 37 ++++++ 7 files changed, 307 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.target/avr/torture/pr63633-ice-mult.c diff --git a/gcc/config/avr/avr-dimode.md b/gcc/config/avr/avr-dimode.md index 639810518c9..56cd304582a 100644 --- a/gcc/config/avr/avr-dimode.md +++ b/gcc/config/avr/avr-dimode.md @@ -68,6 +68,7 @@ { rtx acc_a = gen_rtx_REG (mode, ACC_A); + avr_fix_inputs (operands, 1 << 2, regmask (mode, ACC_A)); emit_move_insn (acc_a, operands[1]); if (DImode == mode @@ -145,6 +146,7 @@ { rtx acc_a = gen_rtx_REG (mode, ACC_A); + avr_fix_inputs (operands, 1 << 2, regmask (mode, ACC_A)); emit_move_insn (acc_a, operands[1]); if (const_operand (operands[2], GET_MODE (operands[2]))) @@ -201,6 +203,7 @@ { rtx acc_a = gen_rtx_REG (mode, ACC_A); + avr_fix_inputs (operands, 1 << 2, regmask (mode, ACC_A)); emit_move_insn (acc_a, operands[1]); if (const_operand (operands[2], GET_MODE (operands[2]))) @@ -249,6 +252,7 @@ { rtx acc_a = gen_rtx_REG (mode, ACC_A); + avr_fix_inputs (operands, 1 << 2, regmask (mode, ACC_A)); emit_move_insn (acc_a, operands[1]); if (const_operand (operands[2], GET_MODE (operands[2]))) @@ -338,6 +342,7 @@ { rtx acc_a = gen_rtx_REG (mode, ACC_A); + avr_fix_inputs (operands, 1 << 2, regmask (mode, ACC_A)); emit_move_insn (acc_a, operands[1]); if (s8_operand (operands[2], VOIDmode)) @@ -424,6 +429,7 @@ { rtx acc_a = gen_rtx_REG (mode, ACC_A); + avr_fix_inputs (operands, 1 << 2, regmask (mode, ACC_A)); emit_move_insn (acc_a, operands[1]); emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]); emit_insn (gen_3_insn ()); @@ -457,6 +463,7 @@ (clobber (any_extend:SI (match_dup 1)))])] "avr_have_dimode" { + avr_fix_inputs (operands, 1 << 2, regmask (SImode, 22)); emit_move_insn (gen_rtx_REG (SImode, 22), operands[1]); emit_move_insn (gen_rtx_REG (SImode, 18), operands[2]); emit_insn (gen_mulsidi3_insn()); diff --git a/gcc/config/avr/avr-fixed.md b/gcc/config/avr/avr-fixed.md index 9c8489edd8e..6763f596e5f 100644 --- a/gcc/config/avr/avr-fixed.md +++ b/gcc/config/avr/avr-fixed.md @@ -231,7 +231,11 @@ (clobber (reg:HI 24))]) (set (match_operand:QQ 0 "register_operand" "") (reg:QQ 23))] - "!AVR_HAVE_MUL") + "!AVR_HAVE_MUL" + { + avr_fix_inputs (operands, 1 << 2, regmask (QQmode, 24)); + }) + (define_expand "muluqq3_nomul" [(set (reg:UQQ 22) @@ -246,7 +250,10 @@ (clobber (reg:HI 22))]) (set (match_operand:UQQ 0 "register_operand" "") (reg:UQQ 25))] - "!AVR_HAVE_MUL") + "!AVR_HAVE_MUL" + { + avr_fix_inputs (operands, 1 << 2, regmask (UQQmode, 22)); + }) (define_insn "*mulqq3.call" [(set (reg:QQ 23) @@ -274,7 +281,10 @@ (clobber (reg:HI 22))]) (set (match_operand:ALL2QA 0 "register_operand" "") (reg:ALL2QA 24))] - "AVR_HAVE_MUL") + "AVR_HAVE_MUL" + { + avr_fix_inputs (operands, 1 << 2, regmask (mode, 18)); + }) ;; "*mulhq3.call" "*muluhq3.call" ;; "*mulha3.call" "*muluha3.call" @@ -302,7 +312,10 @@ (reg:ALL4A 20))) (set (match_operand:ALL4A 0 "register_operand" "") (reg:ALL4A 24))] - "AVR_HAVE_MUL") + "AVR_HAVE_MUL" + { + avr_fix_inputs (operands, 1 << 2, regmask (mode, 16)); + }) ;; "*mulsa3.call" "*mulusa3.call" (define_insn "*mul3.call" @@ -330,7 +343,12 @@ (reg:ALL1Q 22))) (clobber (reg:QI 25))]) (set (match_operand:ALL1Q 0 "register_operand" "") - (reg:ALL1Q 24))]) + (reg:ALL1Q 24))] + "" + { + avr_fix_inputs (operands, 1 << 2, regmask (mode, 25)); + }) + ;; "*divqq3.call" "*udivuqq3.call" (define_insn "*3.call" @@ -356,7 +374,11 @@ (clobber (reg:HI 26)) (clobber (reg:QI 21))]) (set (match_operand:ALL2QA 0 "register_operand" "") - (reg:ALL2QA 24))]) + (reg:ALL2QA 24))] + "" + { + avr_fix_inputs (operands, 1 << 2, regmask (mode, 26)); + }) ;; "*divhq3.call" "*udivuhq3.call" ;; "*divha3.call" "*udivuha3.call" @@ -385,7 +407,11 @@ (clobber (reg:HI 26)) (clobber (reg:HI 30))]) (set (match_operand:ALL4A 0 "register_operand" "") - (reg:ALL4A 22))]) + (reg:ALL4A 22))] + "" + { + avr_fix_inputs (operands, 1 << 2, regmask (mode, 24)); + }) ;; "*divsa3.call" "*udivusa3.call" (define_insn "*3.call" @@ -435,6 +461,7 @@ operands[3] = gen_rtx_REG (mode, regno_out[(size_t) GET_MODE_SIZE (mode)]); operands[4] = gen_rtx_REG (mode, regno_in[(size_t) GET_MODE_SIZE (mode)]); + avr_fix_inputs (operands, 1 << 2, regmask (mode, REGNO (operands[4]))); operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0); // $2 is no more needed, but is referenced for expand. operands[2] = const0_rtx; diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 8a0e2bdcbbe..bdb754201b4 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -129,6 +129,15 @@ extern bool avr_load_libgcc_p (rtx); extern bool avr_xload_libgcc_p (machine_mode); extern rtx avr_eval_addr_attrib (rtx x); +static inline unsigned +regmask (machine_mode mode, unsigned regno) +{ + return ((1u << GET_MODE_SIZE (mode)) - 1) << regno; +} + +extern void avr_fix_inputs (rtx*, unsigned, unsigned); +extern bool avr_emit3_fix_outputs (rtx (*)(rtx,rtx,rtx), rtx*, unsigned, unsigned); + extern rtx lpm_reg_rtx; extern rtx lpm_addr_reg_rtx; extern rtx tmp_reg_rtx; diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index bbd8644e7bc..bc83adb7c3f 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -12201,6 +12201,115 @@ avr_convert_to_type (tree type, tree expr) } +/* PR63633: The middle-end might come up with hard regs as input operands. + + RMASK is a bit mask representing a subset of hard registers R0...R31: + Rn is an element of that set iff bit n of RMASK is set. + OPMASK describes a subset of OP[]: If bit n of OPMASK is 1 then + OP[n] has to be fixed; otherwise OP[n] is left alone. + + For each element of OPMASK which is a hard register overlapping RMASK, + replace OP[n] with a newly created pseudo register + + HREG == 0: Also emit a move insn that copies the contents of that + hard register into the new pseudo. + + HREG != 0: Also set HREG[n] to the hard register. */ + +static void +avr_fix_operands (rtx *op, rtx *hreg, unsigned opmask, unsigned rmask) +{ + for (; opmask; opmask >>= 1, op++) + { + rtx reg = *op; + + if (hreg) + *hreg = NULL_RTX; + + if ((opmask & 1) + && REG_P (reg) + && REGNO (reg) < FIRST_PSEUDO_REGISTER + // This hard-reg overlaps other prohibited hard regs? + && (rmask & regmask (GET_MODE (reg), REGNO (reg)))) + { + *op = gen_reg_rtx (GET_MODE (reg)); + if (hreg == NULL) + emit_move_insn (*op, reg); + else + *hreg = reg; + } + + if (hreg) + hreg++; + } +} + + +void +avr_fix_inputs (rtx *op, unsigned opmask, unsigned rmask) +{ + avr_fix_operands (op, NULL, opmask, rmask); +} + + +/* Helper for the function below: If bit n of MASK is set and + HREG[n] != NULL, then emit a move insn to copy OP[n] to HREG[n]. + Otherwise do nothing for that n. Return TRUE. */ + +static bool +avr_move_fixed_operands (rtx *op, rtx *hreg, unsigned mask) +{ + for (; mask; mask >>= 1, op++, hreg++) + if ((mask & 1) + && *hreg) + emit_move_insn (*hreg, *op); + + return true; +} + + +/* PR63633: The middle-end might come up with hard regs as output operands. + + GEN is a sequence generating function like gen_mulsi3 with 3 operands OP[]. + RMASK is a bit mask representing a subset of hard registers R0...R31: + Rn is an element of that set iff bit n of RMASK is set. + OPMASK describes a subset of OP[]: If bit n of OPMASK is 1 then + OP[n] has to be fixed; otherwise OP[n] is left alone. + + Emit the insn sequence as generated by GEN() with all elements of OPMASK + which are hard registers overlapping RMASK replaced by newly created + pseudo registers. After the sequence has been emitted, emit insns that + move the contents of respective pseudos to their hard regs. */ + +bool +avr_emit3_fix_outputs (rtx (*gen)(rtx,rtx,rtx), rtx *op, + unsigned opmask, unsigned rmask) +{ + const int n = 3; + rtx hreg[n]; + + /* It is letigimate for GEN to call this function, and in order not to + get self-recursive we use the following static kludge. This is the + only way not to duplicate all expanders and to avoid ugly and + hard-to-maintain C-code instead of the much more appreciated RTL + representation as supplied by define_expand. */ + static bool lock = false; + + gcc_assert (opmask < (1u << n)); + + if (lock) + return false; + + avr_fix_operands (op, hreg, opmask, rmask); + + lock = true; + emit_insn (gen (op[0], op[1], op[2])); + lock = false; + + return avr_move_fixed_operands (op, hreg, opmask); +} + + /* Worker function for movmemhi expander. XOP[0] Destination as MEM:BLK XOP[1] Source " " diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index a2c3872c948..9f722cb108e 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -1548,7 +1548,11 @@ (set (reg:QI 22) (match_operand:QI 2 "register_operand" "")) (parallel [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22))) (clobber (reg:QI 22))]) - (set (match_operand:QI 0 "register_operand" "") (reg:QI 24))]) + (set (match_operand:QI 0 "register_operand" "") (reg:QI 24))] + "" + { + avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); + }) (define_insn "*mulqi3_call" [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22))) @@ -2276,7 +2280,13 @@ (parallel [(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22))) (clobber (reg:HI 22)) (clobber (reg:QI 21))]) - (set (match_operand:HI 0 "register_operand" "") (reg:HI 24))]) + (set (match_operand:HI 0 "register_operand" "") + (reg:HI 24))] + "" + { + avr_fix_inputs (operands, (1 << 2), regmask (HImode, 24)); + }) + (define_insn "*mulhi3_call" [(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22))) @@ -2314,6 +2324,10 @@ emit_insn (gen_mulohisi3 (operands[0], operands[2], operands[1])); DONE; } + + if (avr_emit3_fix_outputs (gen_mulsi3, operands, 1 << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; }) (define_insn_and_split "*mulsi3" @@ -2353,7 +2367,23 @@ ;; "muluqisi3" ;; "muluhisi3" -(define_insn_and_split "mulusi3" +(define_expand "mulusi3" + [(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "") + (mult:SI (zero_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" "")) + (match_operand:SI 2 "pseudo_register_or_const_int_operand" ""))) + (clobber (reg:HI 26)) + (clobber (reg:DI 18))])] + "AVR_HAVE_MUL" + { + avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u); + if (avr_emit3_fix_outputs (gen_mulusi3, operands, 1 << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; + }) + +;; "*muluqisi3" +;; "*muluhisi3" +(define_insn_and_split "*mulusi3" [(set (match_operand:SI 0 "pseudo_register_operand" "=r") (mult:SI (zero_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" "r")) (match_operand:SI 2 "pseudo_register_or_const_int_operand" "rn"))) @@ -2389,7 +2419,23 @@ ;; "mulsqisi3" ;; "mulshisi3" -(define_insn_and_split "mulssi3" +(define_expand "mulssi3" + [(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "") + (mult:SI (sign_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" "")) + (match_operand:SI 2 "pseudo_register_or_const_int_operand" ""))) + (clobber (reg:HI 26)) + (clobber (reg:DI 18))])] + "AVR_HAVE_MUL" + { + avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u); + if (avr_emit3_fix_outputs (gen_mulssi3, operands, 1 << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; + }) + +;; "*mulsqisi3" +;; "*mulshisi3" +(define_insn_and_split "*mulssi3" [(set (match_operand:SI 0 "pseudo_register_operand" "=r") (mult:SI (sign_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" "r")) (match_operand:SI 2 "pseudo_register_or_const_int_operand" "rn"))) @@ -2432,7 +2478,22 @@ ;; One-extend operand 1 -(define_insn_and_split "mulohisi3" +(define_expand "mulohisi3" + [(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "") + (mult:SI (not:SI (zero_extend:SI + (not:HI (match_operand:HI 1 "pseudo_register_operand" "")))) + (match_operand:SI 2 "pseudo_register_or_const_int_operand" ""))) + (clobber (reg:HI 26)) + (clobber (reg:DI 18))])] + "AVR_HAVE_MUL" + { + avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u); + if (avr_emit3_fix_outputs (gen_mulohisi3, operands, 1 << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; + }) + +(define_insn_and_split "*mulohisi3" [(set (match_operand:SI 0 "pseudo_register_operand" "=r") (mult:SI (not:SI (zero_extend:SI (not:HI (match_operand:HI 1 "pseudo_register_operand" "r")))) @@ -2460,7 +2521,12 @@ (any_extend:SI (match_operand:HI 2 "register_operand" "")))) (clobber (reg:HI 26)) (clobber (reg:DI 18))])] - "AVR_HAVE_MUL") + "AVR_HAVE_MUL" + { + if (avr_emit3_fix_outputs (gen_mulhisi3, operands, 1 << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; + }) (define_expand "usmulhisi3" [(parallel [(set (match_operand:SI 0 "register_operand" "") @@ -2468,7 +2534,12 @@ (sign_extend:SI (match_operand:HI 2 "register_operand" "")))) (clobber (reg:HI 26)) (clobber (reg:DI 18))])] - "AVR_HAVE_MUL") + "AVR_HAVE_MUL" + { + if (avr_emit3_fix_outputs (gen_usmulhisi3, operands, 1 << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; + }) ;; "*uumulqihisi3" "*uumulhiqisi3" "*uumulhihisi3" "*uumulqiqisi3" ;; "*usmulqihisi3" "*usmulhiqisi3" "*usmulhihisi3" "*usmulqiqisi3" @@ -2540,7 +2611,10 @@ (clobber (reg:HI 22))]) (set (match_operand:HI 0 "register_operand" "") (reg:HI 24))] - "AVR_HAVE_MUL") + "AVR_HAVE_MUL" + { + avr_fix_inputs (operands, 1 << 2, regmask (HImode, 18)); + }) (define_insn "*mulsi3_call" @@ -2763,6 +2837,10 @@ emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1])); DONE; } + + if (avr_emit3_fix_outputs (gen_mulpsi3, operands, 1u << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; }) (define_insn "*umulqihipsi3" @@ -2795,7 +2873,21 @@ [(set_attr "length" "7") (set_attr "cc" "clobber")]) -(define_insn_and_split "mulsqipsi3" +(define_expand "mulsqipsi3" + [(parallel [(set (match_operand:PSI 0 "pseudo_register_operand" "") + (mult:PSI (sign_extend:PSI (match_operand:QI 1 "pseudo_register_operand" "")) + (match_operand:PSI 2 "pseudo_register_or_const_int_operand"""))) + (clobber (reg:HI 26)) + (clobber (reg:DI 18))])] + "AVR_HAVE_MUL" + { + avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u); + if (avr_emit3_fix_outputs (gen_mulsqipsi3, operands, 1 << 0, + regmask (DImode, 18) | regmask (HImode, 26))) + DONE; + }) + +(define_insn_and_split "*mulsqipsi3" [(set (match_operand:PSI 0 "pseudo_register_operand" "=r") (mult:PSI (sign_extend:PSI (match_operand:QI 1 "pseudo_register_operand" "r")) (match_operand:PSI 2 "pseudo_register_or_const_int_operand" "rn"))) @@ -6134,6 +6226,7 @@ emit_insn (gen_fmul_insn (operand0, operand1, operand2)); DONE; } + avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); }) (define_insn "fmul_insn" @@ -6177,6 +6270,7 @@ emit_insn (gen_fmuls_insn (operand0, operand1, operand2)); DONE; } + avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); }) (define_insn "fmuls_insn" @@ -6220,6 +6314,7 @@ emit_insn (gen_fmulsu_insn (operand0, operand1, operand2)); DONE; } + avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); }) (define_insn "fmulsu_insn" diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 55817df9a33..0885198b953 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2014-11-21 Georg-Johann Lay + + Forward-port from 2014-10-30 4_9-branch r216934 + + PR target/63633 + * gcc.target/avr/torture/pr63633-ice-mult.c: New test. + 2014-11-21 Francois-Xavier Coudert PR debug/63239 diff --git a/gcc/testsuite/gcc.target/avr/torture/pr63633-ice-mult.c b/gcc/testsuite/gcc.target/avr/torture/pr63633-ice-mult.c new file mode 100644 index 00000000000..a523424c325 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/pr63633-ice-mult.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ + +void ice_mult32 (int x) +{ + register long reg __asm ("22"); + __asm volatile (" " :: "r" (reg = 0x12345 * x)); +} + +void ice_mult24 (int x) +{ + register __int24 reg __asm ("20"); + __asm volatile (" " :: "r" (reg = 0x12345 * x)); +} + +void ice_sh24 (__int24 x) +{ + register __int24 reg __asm ("20"); + __asm volatile (" " :: "r" (reg = x << 3)); +} + +void ice_sh24b (__int24 x) +{ + register __int24 reg __asm ("20"); + __asm volatile (" " :: "r" (reg = x << 22)); +} + +void ice_s16s16 (int x) +{ + register long reg __asm ("20"); + __asm volatile (" " :: "r" (reg = (long) x*x)); +} + +void ice_u16s16 (int x) +{ + register long reg __asm ("20"); + __asm volatile (" " :: "r" (reg = (long) x*0x1234u)); +} -- 2.30.2