From patchwork Tue Jul 9 10:03:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 1958277 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gjlay.de header.i=@gjlay.de header.a=rsa-sha256 header.s=strato-dkim-0002 header.b=GqXHIu1h; dkim=pass header.d=gjlay.de header.i=@gjlay.de header.a=ed25519-sha256 header.s=strato-dkim-0003 header.b=YjOydCfG; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WJGmX0tHFz1xqc for ; Tue, 9 Jul 2024 20:04:12 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 503C63846096 for ; Tue, 9 Jul 2024 10:04:10 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [85.215.255.23]) by sourceware.org (Postfix) with ESMTPS id 9902D3858420 for ; Tue, 9 Jul 2024 10:03:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9902D3858420 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gjlay.de Authentication-Results: sourceware.org; spf=none smtp.mailfrom=gjlay.de ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9902D3858420 Authentication-Results: server2.sourceware.org; arc=pass smtp.remote-ip=85.215.255.23 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1720519423; cv=pass; b=IAH1A3QFWKBNoKg20G+d3HTawJsipG2YyuAUO5UPE5dfrULl+jANZZQueOLx3KKIBJqBmaPMWsxJ0/4wygBoVflySmq//TQsS/B8wF6gXwm9W5PTu2bgFwtoRh3NcIFJuXSoGOr5aDKKVlGoxkIVYf92ZMVpnHg3CcwMZNzw/F8= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1720519423; c=relaxed/simple; bh=YdmIhVt+hap0Es1YfMF7SXo7bzyvxfydCj6uymvFVeE=; h=DKIM-Signature:DKIM-Signature:Message-ID:Date:MIME-Version:From: To:Subject; b=gzy5Evo/gQukfLMCslb9EagUG9bcIIc2zR/Yr4LEY5st1V8GMXU2Cnqxf+TK4XxJsQhfW9Rw+DEtAEZKqORgEaHFblqxEsSTui9eGfCmT/OjNtKeiKPIfrZ/b9Dyk366RxE86Qeh89gPZeldbY4qy1s78ZEbMhI2VYZPGss5VEE= ARC-Authentication-Results: i=2; server2.sourceware.org ARC-Seal: i=1; a=rsa-sha256; t=1720519414; cv=none; d=strato.com; s=strato-dkim-0002; b=htLuBCqJXzcctAMaanVHVqyQhXCIXqG4oPEafYdVx3duZB2fZlESvv83y4HMIihSYy 6feuPNWvVwvCHra2ON81+HMO87FBPei0qp2vOfaebOHXzhMyHB5ne2XRMHZpKnvU8kzy JT4y9y6oyIWqJoAcYAJKER1xZfvjKwUZlC2uQ6uZTSNcCAjUMVsyKX/Ly+J/Vud+JrKB MrHgslJB2s5hIUXgN5O4K66PLmfVU7QjRDUgJe1T5X10+2C05kGagufOLatgf+hQlSOK CSPpi6drZePG/emJYrClvSh9+PSu9FmgT2Rbqp+fpzULXjYDDubrSuWfzITcL+p+5e0O dRiA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1720519414; s=strato-dkim-0002; d=strato.com; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=3Q1cTLJVKU13sKA2Bd3nj8n2y3TXOt4npnAWi3oIE9I=; b=cVkjAFXx0LCo44bgWmVIggkhZvFSwxWk3ICjkiKBkUm6R6uxZt+SeLVxeDVYRwmJT9 jPFqJSk6Sx863GVh3BimJVOAB+2OIouJulZCNSplkcfVRtE8p3gm5EmUMFnCHzntDMCZ VS9U2toiV/VzVBwkzahDfZoDMveIE6utcDRlMp1PJIetrgvwk2ZFNzBeSf/iXJA/GBf1 TD6u/1CID2uaP2QlYM+Lv7IRIJDVqeaEcl9A5gC4nIAuxdVjHOM3xTHaVYMVFDQpaPpa aS0eCn82BpTjkfcFeUs9whPyckf8WuOfuO79mMrBineF/nOH2+r7xp5+5Ts0loKwKoAs 9+jA== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo00 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1720519414; s=strato-dkim-0002; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=3Q1cTLJVKU13sKA2Bd3nj8n2y3TXOt4npnAWi3oIE9I=; b=GqXHIu1hQ288XhAAx/hNSl0oBi69nrq4/pSdCewqDt2DnLi7ZgdD3BHGPrg4GJPI6W 29EdRDh2D7YoVbKXXu5hWVLo/JokGZ2BaxOKshxh40VIYGjlh7ZGKzkvv1x8/KyCmEuk ulIUfbHOH+rmX9u0yct7sdDNflgBytOISuFuq/wM1RMO9kpclcDLW6RSxC/HW9rYmNnx 9oFfawyTYyiP4bMenq2tbKhYjST5oTcc1QKg5pPFFJPgL0xwn92WawHHFz4lvK1ggGno HVL2Zn1KdvXdwzWoQiSUn/O9b5SYruXUgzQ6MfL4PyoSzpMfZiICSRhCJoSF2Bx1R3oZ vq1w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1720519414; s=strato-dkim-0003; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=3Q1cTLJVKU13sKA2Bd3nj8n2y3TXOt4npnAWi3oIE9I=; b=YjOydCfGrFPOqGEkXNzcS2+rFWbAnhp9MkGDbv6+wZRkp9a9CkTOfFxwng63jGkrYY YazH/rQG6RhuLdTvh0BA== X-RZG-AUTH: ":LXoWVUeid/7A29J/hMvvT3koxZnKT7Qq0xotTetVnKkbjtK7q2y9LkX3jYYP" Received: from [192.168.2.102] by smtp.strato.de (RZmta 50.5.0 DYNA|AUTH) with ESMTPSA id x05778069A3Xppx (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Tue, 9 Jul 2024 12:03:33 +0200 (CEST) Message-ID: <5ee3499e-7557-48e1-b23b-44eed5aabc9c@gjlay.de> Date: Tue, 9 Jul 2024 12:03:32 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Georg-Johann Lay Content-Language: en-US To: "gcc-patches@gcc.gnu.org" , Jeff Law Subject: [patch,avr] PR115830: Improve code by using more condition code X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Hi Jeff, This patch adds peephole2s and insns to make better use of instructions that set condition code (SREG) as a byproduct. Of course with cc0 all this was *much* simpler... so here we go; adding CCNmode and CCZNmode, and extra insns that do arith + CC. No new regressions. Ok for master? Johann --- AVR: target/115830 - Make better use of SREG.N and SREG.Z. This patch adds new CC modes CCN and CCZN for operations that set SREG.N, resp. SREG.Z and SREG.N. Add a bunch of peephole2 patterns to generate new compute + branch insns that make use of the Z and N flags. Most of these patterns need their own asm output routines that don't do all the micro-optimizations that the ordinary outputs may perform, as the latter have no requirement to set CC in a usable way. Pass peephole2 is run a second time so all patterns get a chance to match. PR target/115830 gcc/ * config/avr/avr-modes.def (CCN, CCZN): New CC_MODEs. * config/avr/avr-protos.h (ret_cond_branch): Adjust. (avr_out_plus_set_N, avr_op8_ZN_operator, avr_out_op8_set_ZN, avr_len_op8_set_ZN): New protos. * config/avr/avr.cc (ret_cond_branch): Remove "reverse" argument (was always false) and respective code. Pass cc_overflow_unusable as an argument. (cond_string): Add bool cc_overflow_unusable argument. (avr_print_operand) ['L']: Like 'j' but overflow unusable. ['K']: Like 'k' but overflow unusable. (avr_out_plus_set_ZN): Also support adding -2 and +2. (avr_out_plus_set_N, avr_op8_ZN_operator): New functions. (avr_out_op8_set_ZN, avr_len_op8_set_ZN): New functions. (avr_adjust_insn_length) [ADJUST_LEN_ADD_SET_N]: Hande case. (avr_class_max_nregs): All MODE_CCs occupy one hard reg. (avr_hard_regno_nregs): Same. (avr_hard_regno_mode_ok) [REG_CC]: Allow all MODE_CC. (pass_manager.h): Include it. (avr_option_override): Run peephole2 a second time. * config/avr/avr.md (adjust_len) [add_set_N]: New. (ALLCC, CCN_CCZN): New mode iterators. (CCname): New mode attribute. (eqnegtle, cmp_signed, op8_ZN): New code iterators. (swap, SWAP, tstMSB): New code attributes. (branch): Handle CCNmode and CCZNmode. Assimilate... (difficult_branch): ...this insn. (p1m1): Turn into p2m2. (gen_add_for__): Adjust to CCNmode and CCZNmode. Extend peephole2s that produce them. (*add.for.eqne.): Extend to *add.for... (*ashift.for.ccn.): New insns and peephole2s to make them. (*op8.for.cczn.): New insns and peephole2s to make them. * config/avr/predicates.md (const_1_to_3_operand) (abs1_abs2_operand, signed_comparison_operator) (op8_ZN_operator): New predicates. gcc/testsuite/ * gcc.target/avr/pr115830-add-c.c: New test. * gcc.target/avr/pr115830-add-i.c: New test. * gcc.target/avr/pr115830-and.c: New test. * gcc.target/avr/pr115830-asl.c: New test. * gcc.target/avr/pr115830-asr.c: New test. * gcc.target/avr/pr115830-ior.c: New test. * gcc.target/avr/pr115830-lsr.c: New test. * gcc.target/avr/pr115830-asl32.c: New test. diff --git a/gcc/config/avr/avr-modes.def b/gcc/config/avr/avr-modes.def index e0633d680d5..77b05dd8509 100644 --- a/gcc/config/avr/avr-modes.def +++ b/gcc/config/avr/avr-modes.def @@ -18,6 +18,11 @@ FRACTIONAL_INT_MODE (PSI, 24, 3); +/* Used when the N (and Z) flag(s) of SREG are set. + The N flag indicates whether the value is negative. */ +CC_MODE (CCN); +CC_MODE (CCZN); + /* Make TA and UTA 64 bits wide. 128 bit wide modes would be insane on a 8-bit machine. This needs special treatment in avr.cc and avr-lib.h. */ diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index dc23cfbf461..664513864fe 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -54,7 +54,7 @@ extern const char *avr_out_tsthi (rtx_insn *, rtx*, int*); extern const char *avr_out_tstpsi (rtx_insn *, rtx*, int*); extern const char *avr_out_compare (rtx_insn *, rtx*, int*); extern const char *avr_out_compare64 (rtx_insn *, rtx*, int*); -extern const char *ret_cond_branch (rtx x, int len, int reverse); +extern const char *ret_cond_branch (rtx x, int len, machine_mode); extern const char *avr_out_movpsi (rtx_insn *, rtx*, int*); extern const char *avr_out_sign_extend (rtx_insn *, rtx*, int*); extern const char *avr_out_insert_notbit (rtx_insn *, rtx*, int*); @@ -62,6 +62,10 @@ extern const char *avr_out_insv (rtx_insn *, rtx*, int*); extern const char *avr_out_extr (rtx_insn *, rtx*, int*); extern const char *avr_out_extr_not (rtx_insn *, rtx*, int*); extern const char *avr_out_plus_set_ZN (rtx*, int*); +extern const char *avr_out_plus_set_N (rtx*, int*); +extern const char *avr_out_op8_set_ZN (RTX_CODE, rtx*, int*); +extern int avr_len_op8_set_ZN (RTX_CODE, rtx*); +extern bool avr_op8_ZN_operator (rtx); extern const char *avr_out_cmp_ext (rtx*, enum rtx_code, int*); extern const char *ashlqi3_out (rtx_insn *insn, rtx operands[], int *len); diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index d299fceb782..270fa0f49ba 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -54,6 +54,7 @@ #include "builtins.h" #include "context.h" #include "tree-pass.h" +#include "pass_manager.h" #include "print-rtl.h" #include "rtl-iter.h" @@ -157,7 +158,6 @@ static const char *out_movsi_mr_r (rtx_insn *, rtx[], int *); static int get_sequence_length (rtx_insn *insns); static int sequent_regs_live (void); static const char *ptrreg_to_str (int); -static const char *cond_string (enum rtx_code); static int avr_num_arg_regs (machine_mode, const_tree); static int avr_operand_rtx_cost (rtx, machine_mode, enum rtx_code, int, bool); @@ -1185,6 +1185,18 @@ avr_option_override (void) init_machine_status = avr_init_machine_status; avr_log_set_avr_log(); + + /* As long as peep2_rescan is not implemented, see + http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html + we add a second peephole2 run to get best results. */ + { + opt_pass *extra_peephole2 + = g->get_passes ()->get_pass_peephole2 ()->clone (); + struct register_pass_info peep2_2_info + = { extra_peephole2, "peephole2", 1, PASS_POS_INSERT_AFTER }; + + register_pass (&peep2_2_info); + } } /* Function to set up the backend function structure. */ @@ -3623,10 +3635,8 @@ ptrreg_to_str (int regno) Used in conditional jump constructing */ static const char * -cond_string (enum rtx_code code) +cond_string (enum rtx_code code, bool cc_overflow_unusable) { - bool cc_overflow_unusable = false; - switch (code) { case NE: @@ -3955,10 +3965,11 @@ avr_print_operand (FILE *file, rtx x, int code) } else if (GET_CODE (x) == CONST_STRING) fputs (XSTR (x, 0), file); - else if (code == 'j') - fputs (cond_string (GET_CODE (x)), file); - else if (code == 'k') - fputs (cond_string (reverse_condition (GET_CODE (x))), file); + else if (code == 'j' || code == 'L') + fputs (cond_string (GET_CODE (x), code == 'L'), file); + else if (code == 'k' || code == 'K') + fputs (cond_string (reverse_condition (GET_CODE (x)), code == 'K'), + file); else avr_print_operand_address (file, VOIDmode, x); } @@ -4008,13 +4019,17 @@ avr_jump_mode (rtx x, rtx_insn *insn) /* Return an AVR condition jump commands. X is a comparison RTX. LEN is a number returned by avr_jump_mode function. - If REVERSE nonzero then condition code in X must be reversed. */ + CCMODE is the mode of the comparison in CCmode, CCNmode, CCZNmode. */ const char * -ret_cond_branch (rtx x, int len, int reverse) +ret_cond_branch (rtx x, int len, machine_mode ccmode) { - RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x); - bool cc_overflow_unusable = false; + bool cc_overflow_unusable = ccmode != CCmode; + RTX_CODE cond = GET_CODE (x); + + if (ccmode == CCNmode) + // The N flag can only do < 0 and >= 0. + gcc_assert (cond == GE || cond == LT); switch (cond) { @@ -4076,33 +4091,20 @@ ret_cond_branch (rtx x, int len, int reverse) "brsh .+4" CR_TAB "jmp %0")); default: - if (reverse) + switch (len) { - switch (len) - { - case 1: - return "br%k1 %0"; - case 2: - return ("br%j1 .+2" CR_TAB - "rjmp %0"); - default: - return ("br%j1 .+4" CR_TAB - "jmp %0"); - } - } - else - { - switch (len) - { - case 1: - return "br%j1 %0"; - case 2: - return ("br%k1 .+2" CR_TAB - "rjmp %0"); - default: - return ("br%k1 .+4" CR_TAB - "jmp %0"); - } + case 1: + return cc_overflow_unusable + ? "br%L1 %0" + : "br%j1 %0"; + case 2: + return cc_overflow_unusable + ? "br%K1 .+2" CR_TAB "rjmp %0" + : "br%k1 .+2" CR_TAB "rjmp %0"; + default: + return cc_overflow_unusable + ? "br%K1 .+4" CR_TAB "jmp %0" + : "br%k1 .+4" CR_TAB "jmp %0"; } } return ""; @@ -9455,6 +9457,41 @@ avr_out_plus (rtx insn, rtx *xop, int *plen, bool out_label) } +/* Output an addition with a compile-time constant that sets SREG.N: + + XOP[0] += XOP[1] + + where XOP[0] is a QI, HI, PSI or SI register, and XOP[1] is a compile-time + constant. XOP[2] is SCRATCH or a QI clobber reg. Return "". + + If PLEN == NULL output the instructions. + If PLEN != NULL set *PLEN to the length of the sequence in words. */ + +const char * +avr_out_plus_set_N (rtx *xop, int *plen) +{ + gcc_assert (xop[1] != const0_rtx); + + if (GET_MODE_SIZE (GET_MODE (xop[0])) == 1 + && ! test_hard_reg_class (LD_REGS, xop[0])) + return avr_out_plus_set_ZN (xop, plen); + + // The output function for vanilla additions, avr_out_plus_1, can be + // used because it always issues an operation on the MSB (except when + // the addend is zero). + + rtx op[] = { xop[0], xop[0], xop[1], xop[2] }; + int len_plus, len_minus; + + avr_out_plus_1 (NULL_RTX, op, &len_plus, PLUS, UNKNOWN, 0, false); + avr_out_plus_1 (NULL_RTX, op, &len_minus, MINUS, UNKNOWN, 0, false); + + avr_out_plus_1 (NULL_RTX, op, plen, len_minus < len_plus ? MINUS : PLUS, + UNKNOWN, 0, false); + return ""; +} + + /* Output an instruction sequence for addition of REG in XOP[0] and CONST_INT in XOP[1] in such a way that SREG.Z and SREG.N are set according to the result. XOP[2] might be a d-regs clobber register. If XOP[2] is SCRATCH, @@ -9478,13 +9515,17 @@ avr_out_plus_set_ZN (rtx *xop, int *plen) // Number of bytes to operate on. int n_bytes = GET_MODE_SIZE (mode); - if (n_bytes == 1) + if (n_bytes == 1 + && ! test_hard_reg_class (LD_REGS, xreg)) { - if (INTVAL (xval) == 1) - return avr_asm_len ("inc %0", xop, plen, 1); + gcc_assert (abs1_abs2_operand (xval, QImode)); + int ival = (int) INTVAL (xval); - if (INTVAL (xval) == -1) - return avr_asm_len ("dec %0", xop, plen, 1); + if (ival >= +1) avr_asm_len ("inc %0", xop, plen, 1); + if (ival == +2) avr_asm_len ("inc %0", xop, plen, 1); + if (ival <= -1) avr_asm_len ("dec %0", xop, plen, 1); + if (ival == -2) avr_asm_len ("dec %0", xop, plen, 1); + return ""; } if (n_bytes == 2 @@ -9571,6 +9612,136 @@ avr_out_plus_set_ZN (rtx *xop, int *plen) } +/* A helper worker for op8_ZN_operator. Allow + + OP0 op1 + + QImode operations that set SREG.N and SREG.Z in a usable way. + these are: + + * OP0 is a QImode register, and + * OP1 is a QImode register or CONST_INT, and + + the allowed operations is one of: + + * SHIFTs with a const_int offset in { 1, 2, 3 }. + * MINUS and XOR with a register operand + * IOR and AND with a register operand, or d-reg + const_int + * PLUS with a register operand, or d-reg + const_int, + or a const_int in { -2, -1, 1, 2 }. */ + +bool +avr_op8_ZN_operator (rtx op) +{ + const RTX_CODE code = GET_CODE (op); + rtx op0 = XEXP (op, 0); + rtx op1 = XEXP (op, 1); + + if (! register_operand (op0, QImode) + || ! (register_operand (op1, QImode) + || const_int_operand (op1, QImode))) + return false; + + const bool reg1_p = REG_P (op1); + const bool ld_reg0_p = test_hard_reg_class (LD_REGS, op0); + + switch (code) + { + default: + break; + + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + return const_1_to_3_operand (op1, QImode); + + case MINUS: + case XOR: + return reg1_p; + + case IOR: + case AND: + return reg1_p || ld_reg0_p; + + case PLUS: + return reg1_p || ld_reg0_p || abs1_abs2_operand (op1, QImode); + } + + return false; +} + + +/* Output a QImode instruction sequence for + + XOP[0] = XOP[0] XOP[2] + + where XOP[0] is a register, and the possible operands and CODEs + are according to avr_op8_ZN_operator() from above. Return "". + + If PLEN == NULL, then output the instructions. + If PLEN != NULL, then set *PLEN to the length of the sequence in words. */ + +const char * +avr_out_op8_set_ZN (RTX_CODE code, rtx *xop, int *plen) +{ + const bool reg2_p = REG_P (xop[2]); + const int ival = CONST_INT_P (xop[2]) ? (int) INTVAL (xop[2]) : 0; + + gcc_assert (op8_ZN_operator (gen_rtx_fmt_ee (code, QImode, xop[0], xop[2]), + QImode)); + if (plen) + *plen = 0; + + const char *tpl = nullptr; + int times = 1; + + if (code == ASHIFT) + tpl = "lsl %0", times = ival; + else if (code == LSHIFTRT) + tpl = "lsr %0", times = ival; + else if (code == ASHIFTRT) + tpl = "asr %0", times = ival; + else if (code == MINUS) + tpl = "sub %0,%2"; + else if (code == XOR) + tpl = "eor %0,%2"; + else if (code == AND) + tpl = reg2_p ? "and %0,%2" : "andi %0,lo8(%2)"; + else if (code == IOR) + tpl = reg2_p ? "or %0,%2" : "ori %0,lo8(%2)"; + else if (code == PLUS) + { + if (ival + && ! test_hard_reg_class (LD_REGS, xop[0])) + { + tpl = ival > 0 ? "inc %0" : "dec %0"; + times = ival > 0 ? ival : -ival; + } + else + tpl = reg2_p ? "add %0,%2" : "subi %0,lo8(%n2)"; + } + else + gcc_unreachable(); + + for (int i = 0; i < times; ++i) + avr_asm_len (tpl, xop, plen, 1); + + return ""; +} + + +/* Used in the "length" attribute of insn "*op8.for.cczn.". */ + +int +avr_len_op8_set_ZN (RTX_CODE code, rtx *xop) +{ + int len; + (void) avr_out_op8_set_ZN (code, xop, &len); + + return len; +} + + /* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile time constant XOP[2]: @@ -11022,6 +11193,7 @@ avr_adjust_insn_length (rtx_insn *insn, int len) case ADJUST_LEN_INSERT_BITS: avr_out_insert_bits (op, &len); break; case ADJUST_LEN_ADD_SET_ZN: avr_out_plus_set_ZN (op, &len); break; + case ADJUST_LEN_ADD_SET_N: avr_out_plus_set_N (op, &len); break; case ADJUST_LEN_INSV_NOTBIT: avr_out_insert_notbit (insn, op, &len); break; @@ -11210,7 +11382,7 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p) static unsigned char avr_class_max_nregs (reg_class_t rclass, machine_mode mode) { - if (rclass == CC_REG && mode == CCmode) + if (rclass == CC_REG && GET_MODE_CLASS (mode) == MODE_CC) return 1; return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD); @@ -13750,7 +13922,7 @@ jump_over_one_insn_p (rtx_insn *insn, rtx dest) static unsigned int avr_hard_regno_nregs (unsigned int regno, machine_mode mode) { - if (regno == REG_CC && mode == CCmode) + if (regno == REG_CC && GET_MODE_CLASS (mode) == MODE_CC) return 1; return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD); @@ -13765,7 +13937,7 @@ static bool avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode) { if (regno == REG_CC) - return mode == CCmode; + return GET_MODE_CLASS (mode) == MODE_CC; /* NOTE: 8-bit values must not be disallowed for R28 or R29. Disallowing QI et al. in these regs might lead to code like diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 2783b8c986f..e4f55fb7f4f 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -171,7 +171,7 @@ (define_attr "adjust_len" ashlsi, ashrsi, lshrsi, ashlpsi, ashrpsi, lshrpsi, insert_bits, insv_notbit, insv, - add_set_ZN, cmp_uext, cmp_sext, + add_set_ZN, add_set_N, cmp_uext, cmp_sext, no" (const_string "no")) @@ -277,6 +277,11 @@ (define_mode_iterator ALLs4 [SI SQ SA]) (define_mode_iterator ALLs234 [HI SI PSI HQ HA SQ SA]) +(define_mode_iterator ALLCC [CC CCN CCZN]) +(define_mode_iterator CCN_CCZN [CCN CCZN]) + +(define_mode_attr CCname [(CC "") (CCN "_N") (CCZN "_ZN")]) + ;; All supported move-modes (define_mode_iterator MOVMODE [QI QQ UQQ HI HQ UHQ HA UHA @@ -319,6 +324,9 @@ (define_code_iterator bitop [xor ior and]) (define_code_iterator xior [xor ior]) (define_code_iterator eqne [eq ne]) (define_code_iterator gelt [ge lt]) +(define_code_iterator eqnegtle [eq ne gt le]) +(define_code_iterator cmp_signed [eq ne ge lt gt le]) +(define_code_iterator op8_ZN [plus minus and ior xor ashift ashiftrt lshiftrt]) (define_code_iterator ss_addsub [ss_plus ss_minus]) (define_code_iterator us_addsub [us_plus us_minus]) @@ -350,6 +358,20 @@ (define_code_attr gelt_eqne [(ge "eq") (lt "ne")]) +(define_code_attr swap + [(eq "eq") (ne "ne") + (lt "gt") (gt "lt") + (le "ge") (ge "le")]) + +(define_code_attr SWAP + [(eq "EQ") (ne "NE") + (lt "GT") (gt "LT") + (le "GE") (ge "LE")]) + +;; Convert test of MSB to < 0 resp. >= 0. +(define_code_attr tstMSB + [(eq "ge") (ne "lt")]) + ;; Map RTX code to its standard insn name (define_code_attr code_stdname [(ashift "ashl") @@ -7199,32 +7221,26 @@ (define_peephole2 ; "*sbrx_branch" ;; Compare with 0 (test) jumps ;; ************************************************************************ -(define_insn "branch" +;; "branch" +;; "branch_N" +;; "branch_ZN" +(define_insn "branch" [(set (pc) - (if_then_else (match_operator 1 "simple_comparison_operator" - [(reg:CC REG_CC) + (if_then_else (match_operator 1 "ordered_comparison_operator" + [(reg:ALLCC REG_CC) (const_int 0)]) (label_ref (match_operand 0)) (pc)))] "reload_completed" { - return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn), 0); - } - [(set_attr "type" "branch")]) - - -(define_insn "difficult_branch" - [(set (pc) - (if_then_else (match_operator 1 "difficult_comparison_operator" - [(reg:CC REG_CC) - (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "reload_completed" - { - return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn), 0); + return ret_cond_branch (operands[1], avr_jump_mode (operands[0], insn), + mode); } - [(set_attr "type" "branch1")]) + [(set (attr "type") + (if_then_else + (match_test "simple_comparison_operator (operands[1], VOIDmode)") + (const_string "branch") + (const_string "branch1")))]) ;; ************************************************************************** @@ -9547,8 +9563,8 @@ (define_peephole2 ;; by a comparison of the result against zero, we can output the addition ;; in such a way that SREG.N and SREG.Z are set according to the result. -;; { -1, +1 } for QImode, otherwise the empty set. -(define_mode_attr p1m1 [(QI "N P") +;; { -2, -1, +1, +2 } for QImode, otherwise the empty set. +(define_mode_attr p2m2 [(QI "Cm2 N P K") (HI "Yxx") (PSI "Yxx") (SI "Yxx")]) ;; FIXME: reload1.cc::do_output_reload() does not support output reloads @@ -9587,46 +9603,72 @@ (define_mode_attr p1m1 [(QI "N P") ;; doloop_end doesn't reload either, so doloop_end also won't work. (define_expand "gen_add_for__" - ; "*add.for.eqne." - [(parallel [(set (reg:CC REG_CC) - (compare:CC (plus:QISI (match_operand:QISI 0 "register_operand") - (match_operand:QISI 1 "const_int_operand")) - (const_int 0))) + ; "*add.for.cczn." + [(parallel [(set (reg:CCZN REG_CC) + (compare:CCZN (plus:QISI (match_operand:QISI 0 "register_operand") + (match_operand:QISI 1 "const_int_operand")) + (const_int 0))) (set (match_dup 0) (plus:QISI (match_dup 0) (match_dup 1))) (clobber (match_operand:QI 3))]) - ; "branch" + ; "branch_ZN" (set (pc) - (if_then_else (eqne (reg:CC REG_CC) + (if_then_else (eqnegtle (reg:CCZN REG_CC) + (const_int 0)) + (label_ref (match_dup 2)) + (pc)))]) + +(define_expand "gen_add_for__" + ; "*add.for.ccn." + [(parallel [(set (reg:CCN REG_CC) + (compare:CCN (plus:QISI (match_operand:QISI 0 "register_operand") + (match_operand:QISI 1 "const_int_operand")) + (const_int 0))) + (set (match_dup 0) + (plus:QISI (match_dup 0) + (match_dup 1))) + (clobber (match_operand:QI 3))]) + ; "branch_N" + (set (pc) + (if_then_else (gelt (reg:CCN REG_CC) (const_int 0)) (label_ref (match_dup 2)) (pc)))]) -;; 1/3: A version without clobber: d-reg or 8-bit adds +/-1. +;; 1/3: A version without clobber: d-reg or 8-bit adds -2, -1, 1 or 2. (define_peephole2 [(parallel [(set (match_operand:QISI 0 "register_operand") (plus:QISI (match_dup 0) (match_operand:QISI 1 "const_int_operand"))) (clobber (reg:CC REG_CC))]) (set (reg:CC REG_CC) - (compare:CC (match_dup 0) - (const_int 0))) + (compare:CC (match_operand:QISI 3 "reg_or_0_operand") ; 0 or $0 + (match_operand:QISI 4 "reg_or_0_operand"))) ; 0 or $0 (set (pc) - (if_then_else (eqne (reg:CC REG_CC) - (const_int 0)) + (if_then_else (cmp_signed (reg:CC REG_CC) + (const_int 0)) (label_ref (match_operand 2)) (pc)))] "peep2_regno_dead_p (3, REG_CC) && (d_register_operand (operands[0], mode) || (mode == QImode - && (INTVAL (operands[1]) == 1 - || INTVAL (operands[1]) == -1)))" + && abs1_abs2_operand (operands[1], QImode)))" [(scratch)] { - emit (gen_gen_add_for__ (operands[0], operands[1], operands[2], - gen_rtx_SCRATCH (QImode))); + rtx (*gen)(rtx, rtx, rtx, rtx); + + if (rtx_equal_p (operands[0], operands[3]) + && const0_operand (operands[4], mode)) + gen = gen_gen_add_for__; + else if (const0_operand (operands[3], mode) + && rtx_equal_p (operands[0], operands[4])) + gen = gen_gen_add_for__; + else + FAIL; + + emit (gen (operands[0], operands[1], operands[2], gen_rtx_SCRATCH (QImode))); DONE; }) @@ -9638,30 +9680,39 @@ (define_peephole2 (clobber (match_operand:QI 3 "scratch_or_d_register_operand")) (clobber (reg:CC REG_CC))]) (parallel [(set (reg:CC REG_CC) - (compare:CC (match_dup 0) - (const_int 0))) + (compare:CC (match_operand:QISI 5 "reg_or_0_operand") ; 0 or $0 + (match_operand:QISI 6 "reg_or_0_operand"))) ; 0 or $0 (clobber (match_operand:QI 4 "scratch_or_d_register_operand"))]) (set (pc) - (if_then_else (eqne (reg:CC REG_CC) - (const_int 0)) + (if_then_else (cmp_signed (reg:CC REG_CC) + (const_int 0)) (label_ref (match_operand 2)) (pc)))] "peep2_regno_dead_p (3, REG_CC)" [(scratch)] { rtx scratch = REG_P (operands[3]) ? operands[3] : operands[4]; + rtx (*gen)(rtx, rtx, rtx, rtx); // We need either a d-register or a scratch register to clobber. if (! REG_P (scratch) && ! d_register_operand (operands[0], mode) && ! (QImode == mode - && (INTVAL (operands[1]) == 1 - || INTVAL (operands[1]) == -1))) + && abs1_abs2_operand (operands[1], QImode))) { FAIL; } - emit (gen_gen_add_for__ (operands[0], operands[1], operands[2], - scratch)); + + if (rtx_equal_p (operands[0], operands[5]) + && const0_operand (operands[6], mode)) + gen = gen_gen_add_for__; + else if (const0_operand (operands[5], mode) + && rtx_equal_p (operands[0], operands[6])) + gen = gen_gen_add_for__; + else + FAIL; + + emit (gen (operands[0], operands[1], operands[2], scratch)); DONE; }) @@ -9673,41 +9724,255 @@ (define_peephole2 (match_operand:QISI 1 "const_int_operand"))) (clobber (reg:CC REG_CC))]) (set (reg:CC REG_CC) - (compare:CC (match_dup 0) - (const_int 0))) + (compare:CC (match_operand:QISI 4 "reg_or_0_operand") ; 0 or $0 + (match_operand:QISI 5 "reg_or_0_operand"))) ; 0 or $0 (set (pc) - (if_then_else (eqne (reg:CC REG_CC) - (const_int 0)) + (if_then_else (cmp_signed (reg:CC REG_CC) + (const_int 0)) (label_ref (match_operand 2)) (pc)))] "peep2_regno_dead_p (3, REG_CC)" [(scratch)] { - emit (gen_gen_add_for__ (operands[0], operands[1], operands[2], - operands[3])); + rtx (*gen)(rtx, rtx, rtx, rtx); + + if (rtx_equal_p (operands[0], operands[4]) + && const0_operand (operands[5], mode)) + gen = gen_gen_add_for__; + else if (const0_operand (operands[4], mode) + && rtx_equal_p (operands[0], operands[5])) + gen = gen_gen_add_for__; + else + FAIL; + + emit (gen (operands[0], operands[1], operands[2], operands[3])); DONE; }) ;; Result of the above three peepholes is an addition that also -;; performs an EQ or NE comparison (of the result) against zero. +;; performs a signed comparison (of the result) against zero. ;; FIXME: Using (match_dup 0) instead of operands[3/4] makes rnregs ;; barf in regrename.cc::merge_overlapping_regs(). For now, use the ;; fix from PR50788: Constrain as "0". -(define_insn "*add.for.eqne." - [(set (reg:CC REG_CC) - (compare:CC - (plus:QISI (match_operand:QISI 3 "register_operand" "0,0 ,0") - (match_operand:QISI 1 "const_int_operand" "n,,n")) +; "*add.for.ccn.qi" "*add.for.cczn.qi" +; "*add.for.ccn.hi" "*add.for.cczn.hi" +; "*add.for.ccn.psi" "*add.for.cczn.psi" +; "*add.for.ccn.si" "*add.for.cczn.si" +(define_insn "*add.for.." + [(set (reg:CCN_CCZN REG_CC) + (compare:CCN_CCZN + (plus:QISI (match_operand:QISI 3 "register_operand" "0,0 ,0") + (match_operand:QISI 1 "const_int_operand" "n,,n")) (const_int 0))) - (set (match_operand:QISI 0 "register_operand" "=d,*r ,r") - (plus:QISI (match_operand:QISI 4 "register_operand" "0,0 ,0") + (set (match_operand:QISI 0 "register_operand" "=d,*r ,r") + (plus:QISI (match_operand:QISI 4 "register_operand" "0,0 ,0") (match_dup 1))) - (clobber (match_scratch:QI 2 "=X,X ,&d"))] + (clobber (match_scratch:QI 2 "=X,X ,&d"))] + "reload_completed" + { + return avr_out_plus_set (operands, nullptr); + } + [(set_attr "adjust_len" "add_set")]) + + + +;; Operations other that PLUS can set the condition code in +;; a meaningful way, too. + +;; 1/2 Left shift sets the N bit. +(define_peephole2 + [(parallel [(set (match_operand:HISI 0 "register_operand") + (ashift:HISI (match_dup 0) + (const_int 1))) + (clobber (match_operand:QI 3 "scratch_operand")) + (clobber (reg:CC REG_CC))]) + (set (reg:CC REG_CC) + (compare:CC (match_dup 0) + (const_int 0))) + (set (pc) + (if_then_else (gelt (reg:CC REG_CC) + (const_int 0)) + (label_ref (match_operand 2)) + (pc)))] + "peep2_regno_dead_p (3, REG_CC)" + [; "*ashift.for.ccn." + (parallel [(set (reg:CCN REG_CC) + (compare:CCN (ashift:HISI (match_dup 0) + (const_int 1)) + (const_int 0))) + (set (match_dup 0) + (ashift:HISI (match_dup 0) + (const_int 1)))]) + ; "branch_N" + (set (pc) + (if_then_else (gelt (reg:CCN REG_CC) + (const_int 0)) + (label_ref (match_operand 2)) + (pc)))]) + + +;; 2/2 Left shift sets the N bit. Same like above, but with ZERO_EXTRACT +(define_peephole2 + [(parallel [(set (match_operand:HISI 0 "register_operand") + (ashift:HISI (match_dup 0) + (const_int 1))) + (clobber (match_operand:QI 3 "scratch_operand")) + (clobber (reg:CC REG_CC))]) + (parallel [(set (pc) + (if_then_else + (eqne (zero_extract (match_dup 0) + (const_int 1) + (match_operand 4 "const_operand")) + (const_int 0)) + (label_ref (match_operand 2)) + (pc))) + (clobber (reg:CC REG_CC))])] + "" + [; "*ashift.for.ccn." + (parallel [(set (reg:CCN REG_CC) + (compare:CCN (ashift:HISI (match_dup 0) + (const_int 1)) + (const_int 0))) + (set (match_dup 0) + (ashift:HISI (match_dup 0) + (const_int 1)))]) + ; "branch_N" + (set (pc) + (if_then_else ( (reg:CCN REG_CC) + (const_int 0)) + (label_ref (match_operand 2)) + (pc)))]) + + +(define_insn "*ashift.for.ccn." + [(set (reg:CCN REG_CC) + (compare:CCN (ashift:HISI (match_operand:HISI 2 "register_operand" "0") + (const_int 1)) + (const_int 0))) + (set (match_operand:HISI 0 "register_operand" "=r") + (ashift:HISI (match_operand:HISI 1 "register_operand" "0") + (const_int 1)))] "reload_completed" { - return avr_out_plus_set_ZN (operands, nullptr); + output_asm_insn ("lsl %A0", operands); + if ( >= 2) output_asm_insn ("rol %B0", operands); + if ( >= 3) output_asm_insn ("rol %C0", operands); + if ( >= 4) output_asm_insn ("rol %D0", operands); + return ""; + } + [(set_attr "length" "")]) + + +;; 1/2 QImode operations that set Z and N in a meaningful way. +(define_peephole2 + [(parallel [(set (match_operand:QI 0 "register_operand") + (match_operator:QI 2 "op8_ZN_operator" [(match_dup 0) + (match_operand:QI 1)])) + (clobber (reg:CC REG_CC))]) + (parallel [(set (pc) + (if_then_else (eqne (zero_extract (match_dup 0) + (const_int 1) + (const_int 7)) + (const_int 0)) + (label_ref (match_operand 3)) + (pc))) + (clobber (reg:CC REG_CC))])] + "" + [; "*op8.for.cczn." + (parallel [(set (reg:CCZN REG_CC) + (compare:CCZN (match_op_dup 2 [(match_dup 0) + (match_dup 1)]) + (const_int 0))) + (set (match_dup 0) + (match_op_dup 2 [(match_dup 0) + (match_dup 1)]))]) + ; "branch_ZN" + (set (pc) + (if_then_else ( (reg:CCZN REG_CC) + (const_int 0)) + (label_ref (match_operand 3)) + (pc)))]) + + +;; 2/2 QImode operations that set Z and N in a meaningful way. +(define_peephole2 + [(parallel [(set (match_operand:QI 0 "register_operand") + (match_operator:QI 2 "op8_ZN_operator" [(match_dup 0) + (match_operand:QI 1)])) + (clobber (reg:CC REG_CC))]) + (set (reg:CC REG_CC) + (compare:CC (match_operand:QI 4 "reg_or_0_operand") ; 0 or $0 + (match_operand:QI 5 "reg_or_0_operand"))) ; 0 or $0 + (set (pc) + (if_then_else (cmp_signed (reg:CC REG_CC) + (const_int 0)) + (label_ref (match_operand 3)) + (pc)))] + "peep2_regno_dead_p (3, REG_CC)" + [; "*op8.for.cczn." + (parallel [(set (reg:CCZN REG_CC) + (compare:CCZN (match_op_dup 2 [(match_dup 0) + (match_dup 1)]) + (const_int 0))) + (set (match_dup 0) + (match_op_dup 2 [(match_dup 0) + (match_dup 1)]))]) + ; "branch_ZN" + (set (pc) + (if_then_else (match_dup 6) + (label_ref (match_operand 3)) + (pc)))] + { + RTX_CODE code = UNKNOWN; + + if (rtx_equal_p (operands[4], operands[0]) + && const0_operand (operands[5], QImode)) + code = ; + else if (const0_operand (operands[4], QImode) + && rtx_equal_p (operands[5], operands[0])) + code = ; + else + FAIL; + + operands[6] = gen_rtx_fmt_ee (code, VOIDmode, + gen_rtx_REG (CCZNmode, REG_CC), const0_rtx); + }) + +;; Constraints and predicate for the insn below. +;; This is what op8_ZN_operator allows. +;; Note again that due to nregs, match_dup's won't work. +(define_code_attr c0_op8 + [(minus "r") (xor "r") (and "d,r") (ior "d,r") (plus "d,r") (ashift "r") (ashiftrt "r") (lshiftrt "r")]) +(define_code_attr c1_op8 + [(minus "0") (xor "0") (and "0,0") (ior "0,0") (plus "0,0") (ashift "0") (ashiftrt "0") (lshiftrt "0")]) +(define_code_attr c4_op8 + [(minus "2") (xor "2") (and "2,2") (ior "2,2") (plus "2,2") (ashift "2") (ashiftrt "2") (lshiftrt "2")]) +(define_code_attr c2_op8 + [(minus "r") (xor "r") (and "n,r") (ior "n,r") (plus "n,rPNKCm2") + (ashift "PKC03") (ashiftrt "PKC03") (lshiftrt "PKC03")]) + +(define_code_attr p2_op8 + [(ashift "const_1_to_3") (ashiftrt "const_1_to_3") (lshiftrt "const_1_to_3") + (minus "register") (xor "register") + (plus "nonmemory") (and "nonmemory") (ior "nonmemory")]) + +;; Result of the two peephole2's above: An 8-bit operation that +;; sets Z and N. The allowed operations are: +;; PLUS, MINUS, AND, IOR, XOR and SHIFTs. +(define_insn "*op8.for.cczn." + [(parallel [(set (reg:CCZN REG_CC) + (compare:CCZN (op8_ZN:QI (match_operand:QI 3 "register_operand" "") + (match_operand:QI 4 "_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "register_operand" "=") + (op8_ZN:QI (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "_operand" "")))])] + "reload_completed" + { + return avr_out_op8_set_ZN (, operands, nullptr); } - [(set_attr "adjust_len" "add_set_ZN")]) + [(set (attr "length") + (symbol_ref ("avr_len_op8_set_ZN (, operands)")))]) ;; Swapping both comparison and branch condition. This can turn difficult diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md index 12013660ed1..0a35c8c31c1 100644 --- a/gcc/config/avr/predicates.md +++ b/gcc/config/avr/predicates.md @@ -147,6 +147,11 @@ (define_predicate "const_2_to_7_operand" (and (match_code "const_int") (match_test "IN_RANGE (INTVAL (op), 2, 7)"))) +;; Return true if OP is constant integer 1..3 for MODE. +(define_predicate "const_1_to_3_operand" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 1, 3)"))) + ;; Return 1 if OP is constant integer 1..6 for MODE. (define_predicate "const_1_to_6_operand" (and (match_code "const_int") @@ -162,6 +167,12 @@ (define_predicate "const_m255_to_m1_operand" (and (match_code "const_int") (match_test "IN_RANGE (INTVAL (op), -255, -1)"))) +;; Return true if OP is a CONST_INT in { -2, -1, 1, 2 }. +(define_predicate "abs1_abs2_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) != 0") + (match_test "IN_RANGE (INTVAL (op), -2, 2)"))) + ;; Returns true if OP is either the constant zero or a register. (define_predicate "reg_or_0_operand" (ior (match_operand 0 "register_operand") @@ -228,10 +239,30 @@ (define_predicate "simple_comparison_operator" (and (match_operand 0 "comparison_operator") (not (match_code "gt,gtu,le,leu")))) +;; True for EQ, NE, GE, LT, GT, LE +(define_predicate "signed_comparison_operator" + (match_code "eq,ne,ge,lt,gt,le")) + ;; True for SIGN_EXTEND, ZERO_EXTEND. (define_predicate "extend_operator" (match_code "sign_extend,zero_extend")) +;; True for 8-bit operations that set SREG.N and SREG.Z in a +;; usable way: +;; * OP0 is a QImode register, and +;; * OP1 is a QImode register or CONST_INT, and +;; +;; the allowed operations is one of: +;; +;; * SHIFTs with a const_int offset in { 1, 2, 3 }. +;; * MINUS and XOR with a register operand +;; * IOR and AND with a register operand, or d-reg + const_int +;; * PLUS with a register operand, or d-reg + const_int, +;; or a const_int in { -2, -1, 1, 2 }. */ +(define_predicate "op8_ZN_operator" + (and (match_code "plus,minus,ashift,ashiftrt,lshiftrt,and,ior,xor") + (match_test "avr_op8_ZN_operator (op)"))) + ;; Return true if OP is a valid call operand. (define_predicate "call_insn_operand" (and (match_code "mem") diff --git a/gcc/testsuite/gcc.target/avr/pr115830-add-c.c b/gcc/testsuite/gcc.target/avr/pr115830-add-c.c new file mode 100644 index 00000000000..4f269293590 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-add-c.c @@ -0,0 +1,79 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT8_TYPE__ uint8_t; +typedef __INT8_TYPE__ int8_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP int8_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 42; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 42; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (ADD_01, += 1, != 0) +MK_FUN (ADD_02, += 1, == 0) +MK_FUN (ADD_03, += 1, >= 0) +MK_FUN (ADD_04, += 1, <= 0) +MK_FUN (ADD_05, += 1, > 0) +MK_FUN (ADD_06, += 1, < 0) +MK_FUN (ADD_07, -= 2, != 0) +MK_FUN (ADD_08, -= 2, == 0) +MK_FUN (ADD_09, -= 2, >= 0) +MK_FUN (ADD_10, -= 2, <= 0) +MK_FUN (ADD_11, -= 2, > 0) +MK_FUN (ADD_12, -= 2, < 0) +MK_FUN (ADD_13, += 42, != 0) +MK_FUN (ADD_14, += 42, == 0) +MK_FUN (ADD_15, += 42, >= 0) +MK_FUN (ADD_16, += 42, <= 0) +MK_FUN (ADD_17, += 42, > 0) +MK_FUN (ADD_18, += 42, < 0) + + +int main (void) +{ + uint8_t c = 0; + do { + if (func1_ADD_01 (c) != func2_ADD_01 (c)) __builtin_exit (__LINE__); + if (func1_ADD_02 (c) != func2_ADD_02 (c)) __builtin_exit (__LINE__); + if (func1_ADD_03 (c) != func2_ADD_03 (c)) __builtin_exit (__LINE__); + if (func1_ADD_04 (c) != func2_ADD_04 (c)) __builtin_exit (__LINE__); + if (func1_ADD_05 (c) != func2_ADD_05 (c)) __builtin_exit (__LINE__); + if (func1_ADD_06 (c) != func2_ADD_06 (c)) __builtin_exit (__LINE__); + if (func1_ADD_07 (c) != func2_ADD_07 (c)) __builtin_exit (__LINE__); + if (func1_ADD_08 (c) != func2_ADD_08 (c)) __builtin_exit (__LINE__); + if (func1_ADD_09 (c) != func2_ADD_09 (c)) __builtin_exit (__LINE__); + if (func1_ADD_10 (c) != func2_ADD_10 (c)) __builtin_exit (__LINE__); + if (func1_ADD_11 (c) != func2_ADD_11 (c)) __builtin_exit (__LINE__); + if (func1_ADD_12 (c) != func2_ADD_12 (c)) __builtin_exit (__LINE__); + if (func1_ADD_13 (c) != func2_ADD_13 (c)) __builtin_exit (__LINE__); + if (func1_ADD_14 (c) != func2_ADD_14 (c)) __builtin_exit (__LINE__); + if (func1_ADD_15 (c) != func2_ADD_15 (c)) __builtin_exit (__LINE__); + if (func1_ADD_16 (c) != func2_ADD_16 (c)) __builtin_exit (__LINE__); + if (func1_ADD_17 (c) != func2_ADD_17 (c)) __builtin_exit (__LINE__); + if (func1_ADD_18 (c) != func2_ADD_18 (c)) __builtin_exit (__LINE__); + } while (++c); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/pr115830-add-i.c b/gcc/testsuite/gcc.target/avr/pr115830-add-i.c new file mode 100644 index 00000000000..f3b4df95fd7 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-add-i.c @@ -0,0 +1,103 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT16_TYPE__ uint16_t; +typedef __INT16_TYPE__ int16_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP int16_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 42; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 42; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (ADD_01, += 1, != 0) +MK_FUN (ADD_02, += 1, == 0) +MK_FUN (ADD_03, += 1, >= 0) +MK_FUN (ADD_04, += 1, <= 0) +MK_FUN (ADD_05, += 1, > 0) +MK_FUN (ADD_06, += 1, < 0) +MK_FUN (ADD_07, -= 2, != 0) +MK_FUN (ADD_08, -= 2, == 0) +MK_FUN (ADD_09, -= 2, >= 0) +MK_FUN (ADD_10, -= 2, <= 0) +MK_FUN (ADD_11, -= 2, > 0) +MK_FUN (ADD_12, -= 2, < 0) +MK_FUN (ADD_13, += 42, != 0) +MK_FUN (ADD_14, += 42, == 0) +MK_FUN (ADD_15, += 42, >= 0) +MK_FUN (ADD_16, += 42, <= 0) +MK_FUN (ADD_17, += 42, > 0) +MK_FUN (ADD_18, += 42, < 0) +MK_FUN (ADD_19, += 256, != 0) +MK_FUN (ADD_20, += 256, == 0) +MK_FUN (ADD_21, += 256, >= 0) +MK_FUN (ADD_22, += 256, <= 0) +MK_FUN (ADD_23, += 256, > 0) +MK_FUN (ADD_24, += 256, < 0) +MK_FUN (ADD_25, += 512, != 0) +MK_FUN (ADD_26, += 512, == 0) +MK_FUN (ADD_27, += 512, >= 0) +MK_FUN (ADD_28, += 512, <= 0) +MK_FUN (ADD_29, += 512, > 0) +MK_FUN (ADD_30, += 512, < 0) + + +int main (void) +{ + uint16_t c = 0; + do { + if (func1_ADD_01 (c) != func2_ADD_01 (c)) __builtin_exit (__LINE__); + if (func1_ADD_02 (c) != func2_ADD_02 (c)) __builtin_exit (__LINE__); + if (func1_ADD_03 (c) != func2_ADD_03 (c)) __builtin_exit (__LINE__); + if (func1_ADD_04 (c) != func2_ADD_04 (c)) __builtin_exit (__LINE__); + if (func1_ADD_05 (c) != func2_ADD_05 (c)) __builtin_exit (__LINE__); + if (func1_ADD_06 (c) != func2_ADD_06 (c)) __builtin_exit (__LINE__); + if (func1_ADD_07 (c) != func2_ADD_07 (c)) __builtin_exit (__LINE__); + if (func1_ADD_08 (c) != func2_ADD_08 (c)) __builtin_exit (__LINE__); + if (func1_ADD_09 (c) != func2_ADD_09 (c)) __builtin_exit (__LINE__); + if (func1_ADD_10 (c) != func2_ADD_10 (c)) __builtin_exit (__LINE__); + if (func1_ADD_11 (c) != func2_ADD_11 (c)) __builtin_exit (__LINE__); + if (func1_ADD_12 (c) != func2_ADD_12 (c)) __builtin_exit (__LINE__); + if (func1_ADD_13 (c) != func2_ADD_13 (c)) __builtin_exit (__LINE__); + if (func1_ADD_14 (c) != func2_ADD_14 (c)) __builtin_exit (__LINE__); + if (func1_ADD_15 (c) != func2_ADD_15 (c)) __builtin_exit (__LINE__); + if (func1_ADD_16 (c) != func2_ADD_16 (c)) __builtin_exit (__LINE__); + if (func1_ADD_17 (c) != func2_ADD_17 (c)) __builtin_exit (__LINE__); + if (func1_ADD_18 (c) != func2_ADD_18 (c)) __builtin_exit (__LINE__); + if (func1_ADD_19 (c) != func2_ADD_19 (c)) __builtin_exit (__LINE__); + if (func1_ADD_20 (c) != func2_ADD_20 (c)) __builtin_exit (__LINE__); + if (func1_ADD_21 (c) != func2_ADD_21 (c)) __builtin_exit (__LINE__); + if (func1_ADD_22 (c) != func2_ADD_22 (c)) __builtin_exit (__LINE__); + if (func1_ADD_23 (c) != func2_ADD_23 (c)) __builtin_exit (__LINE__); + if (func1_ADD_24 (c) != func2_ADD_24 (c)) __builtin_exit (__LINE__); + if (func1_ADD_25 (c) != func2_ADD_25 (c)) __builtin_exit (__LINE__); + if (func1_ADD_26 (c) != func2_ADD_26 (c)) __builtin_exit (__LINE__); + if (func1_ADD_27 (c) != func2_ADD_27 (c)) __builtin_exit (__LINE__); + if (func1_ADD_28 (c) != func2_ADD_28 (c)) __builtin_exit (__LINE__); + if (func1_ADD_29 (c) != func2_ADD_29 (c)) __builtin_exit (__LINE__); + if (func1_ADD_30 (c) != func2_ADD_30 (c)) __builtin_exit (__LINE__); + } while (++c); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/pr115830-and.c b/gcc/testsuite/gcc.target/avr/pr115830-and.c new file mode 100644 index 00000000000..317486feb03 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-and.c @@ -0,0 +1,67 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT8_TYPE__ uint8_t; +typedef __INT8_TYPE__ int8_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP int8_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 42; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 42; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (AND_01, &= 0x80, != 0) +MK_FUN (AND_02, &= 0x80, == 0) +MK_FUN (AND_03, &= 0x80, >= 0) +MK_FUN (AND_04, &= 0x80, <= 0) +MK_FUN (AND_05, &= 0x80, > 0) +MK_FUN (AND_06, &= 0x80, < 0) +MK_FUN (AND_07, &= 0xef, != 0) +MK_FUN (AND_08, &= 0xef, == 0) +MK_FUN (AND_09, &= 0xef, >= 0) +MK_FUN (AND_10, &= 0xef, <= 0) +MK_FUN (AND_11, &= 0xef, > 0) +MK_FUN (AND_12, &= 0xef, < 0) + + +int main (void) +{ + uint8_t c = 0; + do { + if (func1_AND_01 (c) != func2_AND_01 (c)) __builtin_exit (__LINE__); + if (func1_AND_02 (c) != func2_AND_02 (c)) __builtin_exit (__LINE__); + if (func1_AND_03 (c) != func2_AND_03 (c)) __builtin_exit (__LINE__); + if (func1_AND_04 (c) != func2_AND_04 (c)) __builtin_exit (__LINE__); + if (func1_AND_05 (c) != func2_AND_05 (c)) __builtin_exit (__LINE__); + if (func1_AND_06 (c) != func2_AND_06 (c)) __builtin_exit (__LINE__); + if (func1_AND_07 (c) != func2_AND_07 (c)) __builtin_exit (__LINE__); + if (func1_AND_08 (c) != func2_AND_08 (c)) __builtin_exit (__LINE__); + if (func1_AND_09 (c) != func2_AND_09 (c)) __builtin_exit (__LINE__); + if (func1_AND_10 (c) != func2_AND_10 (c)) __builtin_exit (__LINE__); + if (func1_AND_11 (c) != func2_AND_11 (c)) __builtin_exit (__LINE__); + if (func1_AND_12 (c) != func2_AND_12 (c)) __builtin_exit (__LINE__); + } while (++c); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/pr115830-asl.c b/gcc/testsuite/gcc.target/avr/pr115830-asl.c new file mode 100644 index 00000000000..09a4495caac --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-asl.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT8_TYPE__ uint8_t; +typedef __INT8_TYPE__ int8_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP int8_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 42; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 42; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (ASL_01, <<= 1, != 0) +MK_FUN (ASL_02, <<= 2, != 0) +MK_FUN (ASL_03, <<= 3, != 0) +MK_FUN (ASL_04, <<= 1, == 0) +MK_FUN (ASL_05, <<= 2, == 0) +MK_FUN (ASL_06, <<= 3, == 0) +MK_FUN (ASL_07, <<= 1, >= 0) +MK_FUN (ASL_08, <<= 2, >= 0) +MK_FUN (ASL_09, <<= 3, >= 0) +MK_FUN (ASL_10, <<= 1, <= 0) +MK_FUN (ASL_11, <<= 2, <= 0) +MK_FUN (ASL_12, <<= 3, <= 0) +MK_FUN (ASL_13, <<= 1, > 0) +MK_FUN (ASL_14, <<= 2, > 0) +MK_FUN (ASL_15, <<= 3, > 0) +MK_FUN (ASL_16, <<= 1, < 0) +MK_FUN (ASL_17, <<= 2, < 0) +MK_FUN (ASL_18, <<= 3, < 0) + +int main (void) +{ + uint8_t c = 0; + do { + if (func1_ASL_01 (c) != func2_ASL_01 (c)) __builtin_exit (__LINE__); + if (func1_ASL_02 (c) != func2_ASL_02 (c)) __builtin_exit (__LINE__); + if (func1_ASL_03 (c) != func2_ASL_03 (c)) __builtin_exit (__LINE__); + if (func1_ASL_04 (c) != func2_ASL_04 (c)) __builtin_exit (__LINE__); + if (func1_ASL_05 (c) != func2_ASL_05 (c)) __builtin_exit (__LINE__); + if (func1_ASL_06 (c) != func2_ASL_06 (c)) __builtin_exit (__LINE__); + if (func1_ASL_07 (c) != func2_ASL_07 (c)) __builtin_exit (__LINE__); + if (func1_ASL_08 (c) != func2_ASL_08 (c)) __builtin_exit (__LINE__); + if (func1_ASL_09 (c) != func2_ASL_09 (c)) __builtin_exit (__LINE__); + if (func1_ASL_10 (c) != func2_ASL_10 (c)) __builtin_exit (__LINE__); + if (func1_ASL_11 (c) != func2_ASL_11 (c)) __builtin_exit (__LINE__); + if (func1_ASL_12 (c) != func2_ASL_12 (c)) __builtin_exit (__LINE__); + if (func1_ASL_13 (c) != func2_ASL_13 (c)) __builtin_exit (__LINE__); + if (func1_ASL_14 (c) != func2_ASL_14 (c)) __builtin_exit (__LINE__); + if (func1_ASL_15 (c) != func2_ASL_15 (c)) __builtin_exit (__LINE__); + if (func1_ASL_16 (c) != func2_ASL_16 (c)) __builtin_exit (__LINE__); + if (func1_ASL_17 (c) != func2_ASL_17 (c)) __builtin_exit (__LINE__); + if (func1_ASL_18 (c) != func2_ASL_18 (c)) __builtin_exit (__LINE__); + } while (++c); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/pr115830-asl32.c b/gcc/testsuite/gcc.target/avr/pr115830-asl32.c new file mode 100644 index 00000000000..6e8100f5f58 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-asl32.c @@ -0,0 +1,57 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT32_TYPE__ uint32_t; +typedef __INT32_TYPE__ int32_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP int32_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 0x77665544; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 0x77665544; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (ASL_03, <<= 1, >= 0) +MK_FUN (ASL_06, <<= 1, < 0) + +NI void test_asl (uint32_t c) +{ + if (func1_ASL_03 (c) != func2_ASL_03 (c)) __builtin_exit (__LINE__); + if (func1_ASL_06 (c) != func2_ASL_06 (c)) __builtin_exit (__LINE__); +} + +int main (void) +{ + test_asl (0); + test_asl (0x80000000); + test_asl (0x80000001); + test_asl (0xc0000000); + test_asl (0xc0000001); + test_asl (0); + test_asl (0xff00ff00); + test_asl (0x00ff00ff); + test_asl (0xff00ff00 >> 1); + test_asl (0x00ff00ff >> 1); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/pr115830-asr.c b/gcc/testsuite/gcc.target/avr/pr115830-asr.c new file mode 100644 index 00000000000..1ceafb9a537 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-asr.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT8_TYPE__ uint8_t; +typedef __INT8_TYPE__ int8_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP int8_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 42; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 42; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (ASR_01, >>= 1, != 0) +MK_FUN (ASR_02, >>= 2, != 0) +MK_FUN (ASR_03, >>= 3, != 0) +MK_FUN (ASR_04, >>= 1, == 0) +MK_FUN (ASR_05, >>= 2, == 0) +MK_FUN (ASR_06, >>= 3, == 0) +MK_FUN (ASR_07, >>= 1, >= 0) +MK_FUN (ASR_08, >>= 2, >= 0) +MK_FUN (ASR_09, >>= 3, >= 0) +MK_FUN (ASR_10, >>= 1, <= 0) +MK_FUN (ASR_11, >>= 2, <= 0) +MK_FUN (ASR_12, >>= 3, <= 0) +MK_FUN (ASR_13, >>= 1, > 0) +MK_FUN (ASR_14, >>= 2, > 0) +MK_FUN (ASR_15, >>= 3, > 0) +MK_FUN (ASR_16, >>= 1, < 0) +MK_FUN (ASR_17, >>= 2, < 0) +MK_FUN (ASR_18, >>= 3, < 0) + +int main (void) +{ + uint8_t c = 0; + do { + if (func1_ASR_01 (c) != func2_ASR_01 (c)) __builtin_exit (__LINE__); + if (func1_ASR_02 (c) != func2_ASR_02 (c)) __builtin_exit (__LINE__); + if (func1_ASR_03 (c) != func2_ASR_03 (c)) __builtin_exit (__LINE__); + if (func1_ASR_04 (c) != func2_ASR_04 (c)) __builtin_exit (__LINE__); + if (func1_ASR_05 (c) != func2_ASR_05 (c)) __builtin_exit (__LINE__); + if (func1_ASR_06 (c) != func2_ASR_06 (c)) __builtin_exit (__LINE__); + if (func1_ASR_07 (c) != func2_ASR_07 (c)) __builtin_exit (__LINE__); + if (func1_ASR_08 (c) != func2_ASR_08 (c)) __builtin_exit (__LINE__); + if (func1_ASR_09 (c) != func2_ASR_09 (c)) __builtin_exit (__LINE__); + if (func1_ASR_10 (c) != func2_ASR_10 (c)) __builtin_exit (__LINE__); + if (func1_ASR_11 (c) != func2_ASR_11 (c)) __builtin_exit (__LINE__); + if (func1_ASR_12 (c) != func2_ASR_12 (c)) __builtin_exit (__LINE__); + if (func1_ASR_13 (c) != func2_ASR_13 (c)) __builtin_exit (__LINE__); + if (func1_ASR_14 (c) != func2_ASR_14 (c)) __builtin_exit (__LINE__); + if (func1_ASR_15 (c) != func2_ASR_15 (c)) __builtin_exit (__LINE__); + if (func1_ASR_16 (c) != func2_ASR_16 (c)) __builtin_exit (__LINE__); + if (func1_ASR_17 (c) != func2_ASR_17 (c)) __builtin_exit (__LINE__); + if (func1_ASR_18 (c) != func2_ASR_18 (c)) __builtin_exit (__LINE__); + } while (++c); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/pr115830-ior.c b/gcc/testsuite/gcc.target/avr/pr115830-ior.c new file mode 100644 index 00000000000..51451b4f32f --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-ior.c @@ -0,0 +1,67 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT8_TYPE__ uint8_t; +typedef __INT8_TYPE__ int8_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP int8_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 42; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 42; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (IOR_01, &= 0x8, != 0) +MK_FUN (IOR_02, &= 0x8, == 0) +MK_FUN (IOR_03, &= 0x8, >= 0) +MK_FUN (IOR_04, &= 0x8, <= 0) +MK_FUN (IOR_05, &= 0x8, > 0) +MK_FUN (IOR_06, &= 0x8, < 0) +MK_FUN (IOR_07, &= 0x7f, != 0) +MK_FUN (IOR_08, &= 0x7f, == 0) +MK_FUN (IOR_09, &= 0x7f, >= 0) +MK_FUN (IOR_10, &= 0x7f, <= 0) +MK_FUN (IOR_11, &= 0x7f, > 0) +MK_FUN (IOR_12, &= 0x7f, < 0) + + +int main (void) +{ + uint8_t c = 0; + do { + if (func1_IOR_01 (c) != func2_IOR_01 (c)) __builtin_exit (__LINE__); + if (func1_IOR_02 (c) != func2_IOR_02 (c)) __builtin_exit (__LINE__); + if (func1_IOR_03 (c) != func2_IOR_03 (c)) __builtin_exit (__LINE__); + if (func1_IOR_04 (c) != func2_IOR_04 (c)) __builtin_exit (__LINE__); + if (func1_IOR_05 (c) != func2_IOR_05 (c)) __builtin_exit (__LINE__); + if (func1_IOR_06 (c) != func2_IOR_06 (c)) __builtin_exit (__LINE__); + if (func1_IOR_07 (c) != func2_IOR_07 (c)) __builtin_exit (__LINE__); + if (func1_IOR_08 (c) != func2_IOR_08 (c)) __builtin_exit (__LINE__); + if (func1_IOR_09 (c) != func2_IOR_09 (c)) __builtin_exit (__LINE__); + if (func1_IOR_10 (c) != func2_IOR_10 (c)) __builtin_exit (__LINE__); + if (func1_IOR_11 (c) != func2_IOR_11 (c)) __builtin_exit (__LINE__); + if (func1_IOR_12 (c) != func2_IOR_12 (c)) __builtin_exit (__LINE__); + } while (++c); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/pr115830-lsr.c b/gcc/testsuite/gcc.target/avr/pr115830-lsr.c new file mode 100644 index 00000000000..1e027154c73 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/pr115830-lsr.c @@ -0,0 +1,60 @@ +/* { dg-do run } */ +/* { dg-additional-options { -std=c99 -fwrapv -Os } } */ + +typedef __UINT8_TYPE__ uint8_t; +typedef __INT8_TYPE__ int8_t; + +#define AI static inline __attribute__((always_inline)) +#define NI __attribute__((noinline,noclone,no_icf)) + +#define TYP uint8_t + +TYP volatile v; + +#define MK_FUN(ID, OP, TST) \ +NI TYP func1_##ID (TYP c) \ +{ \ + v = 42; \ + c OP; \ + if (c TST) \ + v = c; \ + return v; \ +} \ + \ +NI TYP func2_##ID (TYP c) \ +{ \ + TYP v = 42; \ + c OP; \ + __asm ("" : "+r" (c)); \ + if (c TST) \ + v = c; \ + return v; \ +} + +MK_FUN (LSR_01, >>= 1, != 0) +MK_FUN (LSR_02, >>= 2, != 0) +MK_FUN (LSR_03, >>= 3, != 0) +MK_FUN (LSR_04, >>= 1, == 0) +MK_FUN (LSR_05, >>= 2, == 0) +MK_FUN (LSR_06, >>= 3, == 0) +MK_FUN (LSR_13, >>= 1, > 0) +MK_FUN (LSR_14, >>= 2, > 0) +MK_FUN (LSR_15, >>= 3, > 0) + +int main (void) +{ + uint8_t c = 0; + do { + if (func1_LSR_01 (c) != func2_LSR_01 (c)) __builtin_exit (__LINE__); + if (func1_LSR_02 (c) != func2_LSR_02 (c)) __builtin_exit (__LINE__); + if (func1_LSR_03 (c) != func2_LSR_03 (c)) __builtin_exit (__LINE__); + if (func1_LSR_04 (c) != func2_LSR_04 (c)) __builtin_exit (__LINE__); + if (func1_LSR_05 (c) != func2_LSR_05 (c)) __builtin_exit (__LINE__); + if (func1_LSR_06 (c) != func2_LSR_06 (c)) __builtin_exit (__LINE__); + if (func1_LSR_13 (c) != func2_LSR_13 (c)) __builtin_exit (__LINE__); + if (func1_LSR_14 (c) != func2_LSR_14 (c)) __builtin_exit (__LINE__); + if (func1_LSR_15 (c) != func2_LSR_15 (c)) __builtin_exit (__LINE__); + } while (++c); + + return 0; +}