From patchwork Tue Oct 28 12:34:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 404220 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 0AF7014003E for ; Tue, 28 Oct 2014 23:34:34 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=UJMCzE8XJADvSnCcJPAGF3Z+Ds7FbcnWIFKhS1NStHh i5WcWxY2W2v4HRNu0J58J5Sa5OUpo3tI1vxiqpOI1e7rZJz8wVmMQtZe0hAK5eIW xyiwCAep2vzr3Jnp7TSGyGC3Cuf465I260ba1kfRMvzgP2n5IEzFx1WU+1PM2Bsg = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=jcx0pCPrJ5ttI8kvmvDZfl3U8y4=; b=QvlEhZO27o3PJJtnm QSPMyTzOGaWkHaWdXSjClD2Ea++8HPNrUpHxd9eip7IsqFhhDyutwavycafoTERI Xr5PalaXCQ2WNUfOJs1X/Vhfp9kVQo6GkbnZ2MNMQ4yWNU5wH4kG4sSpj3ePhF1i vfEjTVuxsQYqvwvqkr4nFiEUXI= Received: (qmail 18928 invoked by alias); 28 Oct 2014 12:34:26 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 18918 invoked by uid 89); 28 Oct 2014 12:34:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.6 required=5.0 tests=AWL, BAYES_00, LIKELY_SPAM_BODY, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.2 X-HELO: mo4-p00-ob.smtp.rzone.de Received: from mo4-p00-ob.smtp.rzone.de (HELO mo4-p00-ob.smtp.rzone.de) (81.169.146.219) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 28 Oct 2014 12:34:23 +0000 X-RZG-AUTH: :LXoWVUeid/7A29J/hMvvT3ol15ykJcYwTPLBCxG2Pg6JVq6JhQ== X-RZG-CLASS-ID: mo00 Received: from [192.168.0.22] (ip5f5818d3.dynamic.kabel-deutschland.de [95.88.24.211]) by smtp.strato.de (RZmta 35.10 DYNA|AUTH) with ESMTPSA id u0336cq9SCYCbwG (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate); Tue, 28 Oct 2014 13:34:12 +0100 (CET) Message-ID: <544F8D44.1060000@gjlay.de> Date: Tue, 28 Oct 2014 13:34:12 +0100 From: Georg-Johann Lay User-Agent: Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 MIME-Version: 1.0 To: GCC Patches CC: Jakub Jelinek , Denis Chertykov , Jeff Law Subject: [patch,avr,4.9] Fix PR63633 ICEs for expanders colliding hard-regs X-IsSubscribed: yes Middle-end might come up with hard registers as operands for expanders which clobber respective hard regs. This patch uses freshly created pseudos for respective expander operands and emits pseudo <-> hard move insn. Ok for 4.9.2? It's not yet for trunk because avr trunk backend is currently broken. Johann gcc/ PR63633 * 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/ PR63633 * gcc.target/avr/torture/pr63633-ice-mult.c: New test. Index: testsuite/gcc.target/avr/torture/pr63633-ice-mult.c =================================================================== --- testsuite/gcc.target/avr/torture/pr63633-ice-mult.c (revision 0) +++ testsuite/gcc.target/avr/torture/pr63633-ice-mult.c (revision 0) @@ -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)); +} Index: config/avr/avr-fixed.md =================================================================== --- config/avr/avr-fixed.md (revision 215212) +++ config/avr/avr-fixed.md (working copy) @@ -231,7 +231,11 @@ (define_expand "mulqq3_nomul" (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 @@ (define_expand "muluqq3_nomul" (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 @@ (define_expand "mul3" (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 @@ (define_expand "mul3" (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 @@ (define_expand "3" (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 @@ (define_expand "3" (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 @@ (define_expand "3" (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 @@ (define_expand "round3" 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; Index: config/avr/avr-dimode.md =================================================================== --- config/avr/avr-dimode.md (revision 215212) +++ config/avr/avr-dimode.md (working copy) @@ -68,6 +68,7 @@ (define_expand "add3" { 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 @@ (define_expand "sub3" { 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 @@ (define_expand "3" { 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 @@ (define_expand "3" { 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 @@ (define_expand "cbranch4" { 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 @@ (define_expand "3" { 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 @@ (define_expand "mulsidi3" (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()); Index: config/avr/avr.md =================================================================== --- config/avr/avr.md (revision 215212) +++ config/avr/avr.md (working copy) @@ -1482,7 +1482,11 @@ (define_expand "mulqi3_call" (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))) @@ -2210,7 +2214,13 @@ (define_expand "mulhi3_call" (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))) @@ -2248,6 +2258,10 @@ (define_expand "mulsi3" 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" @@ -2287,7 +2301,23 @@ (define_insn_and_split "*mulsi3" ;; "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"))) @@ -2323,7 +2353,23 @@ (define_insn_and_split "mulusi3" ;; "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"))) @@ -2366,7 +2412,22 @@ (define_insn_and_split "mulssi3" ;; 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")))) @@ -2394,7 +2455,12 @@ (define_expand "mulhisi3" (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" "") @@ -2402,7 +2468,12 @@ (define_expand "usmulhisi3" (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" @@ -2474,7 +2545,10 @@ (define_expand "mulhi3_highpa (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" @@ -2697,6 +2771,10 @@ (define_expand "mulpsi3" 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" @@ -2729,7 +2807,21 @@ (define_insn "*umulhiqipsi3" [(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"))) @@ -6064,6 +6156,7 @@ (define_expand "fmul" emit_insn (gen_fmul_insn (operand0, operand1, operand2)); DONE; } + avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); }) (define_insn "fmul_insn" @@ -6107,6 +6200,7 @@ (define_expand "fmuls" emit_insn (gen_fmuls_insn (operand0, operand1, operand2)); DONE; } + avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); }) (define_insn "fmuls_insn" @@ -6150,6 +6244,7 @@ (define_expand "fmulsu" emit_insn (gen_fmulsu_insn (operand0, operand1, operand2)); DONE; } + avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24)); }) (define_insn "fmulsu_insn" Index: config/avr/avr-protos.h =================================================================== --- config/avr/avr-protos.h (revision 215212) +++ config/avr/avr-protos.h (working copy) @@ -124,6 +124,15 @@ extern bool avr_mem_memx_p (rtx); extern bool avr_load_libgcc_p (rtx); extern bool avr_xload_libgcc_p (enum machine_mode); +static inline unsigned +regmask (enum 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; Index: config/avr/avr.c =================================================================== --- config/avr/avr.c (revision 215212) +++ config/avr/avr.c (working copy) @@ -11118,6 +11118,115 @@ avr_convert_to_type (tree type, tree exp } +/* 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 " "