From patchwork Fri Jul 12 11:01:47 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: 1959763 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=i9G28aqM; dkim=pass header.d=gjlay.de header.i=@gjlay.de header.a=ed25519-sha256 header.s=strato-dkim-0003 header.b=PsxnBsc3; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; 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 [IPv6:2620:52:3:1:0:246e:9693:128c]) (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 4WL7wG5qPBz1xqx for ; Fri, 12 Jul 2024 21:02:22 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3FF7B3838A18 for ; Fri, 12 Jul 2024 11:02:20 +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 ADB143858294 for ; Fri, 12 Jul 2024 11:01:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ADB143858294 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 ADB143858294 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=1720782117; cv=pass; b=IGObDGfFmTC/2KT1hems1+832znHiWkYNELyeACVurk/dRDHKGnFMjFx0aAUYFr8Ok1cBjKP+rxpzaxGpshnMPd3LewKaz7Ck7gsvo4smA1ob3+Km5BpYRzAbEYuID9PFfJqVhSqKaYgz3GyuS/m48qKxk7iLfpbqVFD3ukpy9k= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1720782117; c=relaxed/simple; bh=DhphcYI1dijm+WeqnhK3yp0XY3zcTWdffYAvI2OchCk=; h=DKIM-Signature:DKIM-Signature:Message-ID:Date:MIME-Version:From: To:Subject; b=Tj/qyXnqUcrCVNM6jkqaYBQCoXn02DNnhSzwMd+6uB1yI2ZA87csNRN8F9KLzIGI0cSu/8zLYRcDOqfHsLayDsYDarx/e011pGWP7y+krYQJWjJAJq5rcK+1F87vodncaRRgibwv0JNU8Hpm8o2alKCkLW6l5hfdxFKVFBVU2pQ= ARC-Authentication-Results: i=2; server2.sourceware.org ARC-Seal: i=1; a=rsa-sha256; t=1720782108; cv=none; d=strato.com; s=strato-dkim-0002; b=f9Lm/5Fyu0EmuRn4t1vZCPwD96yZ402amjjtUyBP3vpHTladz0EedEgGdWj8YeC/ZF 5pVbJ9qvTlV2nL1uSqkyqIX85+TcXLFeZC2h5Q2bcZqRK1OcHllYKCKt8eEd7XBWAQmd NTIgQCLJU3ZXB+QJE63dvok7oeQxn8OF9MvBnAVUPAboksVorYgu4n+/L2EooCf/eXUh +3wSxwThHlP4MwZcYsv9q67GjfICNKSV9ZmN4t8iyNhXdX8Ev/zDsAvR9JGf/grxwJ8E 7g6Las/4Eh+AC/rHYCcANW109oTARdb8DzoW/wflT/zyu5Ql/GVMNmttwFDJGvX1ZeIE izbw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1720782108; s=strato-dkim-0002; d=strato.com; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=qCBV8/NPeZMpe53zkt3NJVpN5AOMSloaS79cQx7jMps=; b=h/0dVyZlN0NsweY5Jpj7h/B4BoQoam4tiTPvq7BfvrTiR5mC5IUgDg43MQJ1HVOIyc PbkSk81EGJ5PCYzvZP1bcX4/eHJwco6EFdm7/hkDPH5fO8Ba50t6XKm6B65B1c+51uWq T9MRtv7OPnvffjPAQ2tnBEVBlSmNwcG1/C2mEoX9/Z4pdJjhBAD3m68LuyDZorp3fG7M ehT2pDmzIUnJkksimeylRE6+gbmtMYo0DO6WffWP3iZLLVAZpUxkLDnq2DQgBiNx9/So lOvch76e7l0UnZ7BxnydkUHuVd6fT7852H1EwjOwizraIocrugxVl0AhDB2NaXfMoF+5 DaZw== 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=1720782108; s=strato-dkim-0002; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=qCBV8/NPeZMpe53zkt3NJVpN5AOMSloaS79cQx7jMps=; b=i9G28aqMaJTjIHbQSn9dlBxA2tVH7bweu7d/UjrcL4GwwdnDtWfrdVDA+fnElVCggn tj71mlpzs3iKw/1S1ETd+Of1TYxh6py5uVsXRcFQYuSkcpLzSG/q+qsAxzMna6MX9uEN WvIE2bw9ktH8rHuayROeKcYZ3Gwn1r4Mv1rJHN+TXLQZacAVqdpD0s168F6Y3Pnw2UtR h9y9sPG32uEHXuX1rGG0WJhEAolWJ08e2hiKbJc3SszbvbCkTurjT+MVC31B1aVT+Z1t QinudJeYQntOiDVbh8TZLVNTrznl8YOtU1X2YSHR8qNdt2J5Wmt/uf5GUBnCv6LZxLKM hwvw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1720782108; s=strato-dkim-0003; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=qCBV8/NPeZMpe53zkt3NJVpN5AOMSloaS79cQx7jMps=; b=PsxnBsc39NjpXOUgHOamJHQ35g6I8DFLIznenZby49z9TsUKVBdQJDN0kK/6N87b9h TPklYjYzOxBv0+S2usAg== 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 xbc76306CB1m58p (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate) for ; Fri, 12 Jul 2024 13:01:48 +0200 (CEST) Message-ID: <6d869528-3758-4755-9f9a-4d206ae61bdd@gjlay.de> Date: Fri, 12 Jul 2024 13:01:47 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Georg-Johann Lay Content-Language: en-US To: "gcc-patches@gcc.gnu.org" Subject: [patch,avr] Overhaul add and sub insns that extend one operand X-Spam-Status: No, score=-11.0 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 These are insns of the forms (set (regA:M) (plus:M (extend:M (regB:L)) (regA:M))) and (set (regA:M) (minus:M (regA:M) (extend:M (regB:L)))) where "extend" may be a sign-extend or zero-extend, and the integer modes satisfy SImode >= M > L >= QImode. Currently, these are represented as single insns (and splits). This patch rewrites them in terms of mode iterators M and L with SImode >= M > L >= QImode. This gives 3 new insns (and splits) that cover 6 + 6 + 5 = 17 cases, where previously there was support for just 8 cases. The patch handles only the cases that have a plus or a sign-extend. The minus & zero-extend case was already handled in 077f16b2. Ok for trunk? Johann --- AVR: Overhaul add and sub insns that extend one operand. These are insns of the forms (set (regA:M) (plus:M (extend:M (regB:L)) (regA:M))) or (set (regA:M) (minus:M (regA:M) (extend:M (regB:L)))) where "extend" may be a sign-extend or zero-extend, and the integer modes are SImode >= M > L >= QImode. The existing patterns are now represented in terms of insns with mode iterators, and these new insn support all valid combinations of M and L (which previously was not the case). gcc/ * config/avr/avr.cc (avr_out_minus): Assimilate into... (avr_out_plus_ext): ...this new function. (avr_adjust_insn_length) [ADJUST_LEN_PLUS_EXT]: Handle case. (avr_rtx_costs_1) [PLUS, MINUS]: Adjust RTX costs. * config/avr/avr.md (adjust_len) : Add new attribute value. (PSISI): New mode iterator. (*addpsi3_zero_extend.hi_split): Assimilate... (*addpsi3_zero_extend.qi_split): Assimilate... (*addsi3_zero_extend_split): Assimilate... (*addsi3_zero_extend.hi_split): Assimilate... (*add3.zero_extend._split): ...into this new insn-and-split. (*addpsi3_zero_extend.hi): Assimilate... (*addpsi3_zero_extend.qi): Assimilate... (*addsi3_zero_extend): Assimilate... (*addsi3_zero_extend.hi): Assimilate... (*add3.zero_extend.): ...into this new insn. (*addpsi3_sign_extend.hi_split): Assimilate... (*addhi3.sign_extend1_split): Assimilate... (*add3.sign_extend._split): ...into this new insn-and-split. (*addpsi3_sign_extend.hi): Assimilate... (*addhi3.sign_extend1): Assimilate... (*add3.sign_extend.): ...into this new insn. (*subpsi3_sign_extend.hi_split): Assimilate... (*subhi3.sign_extend2_split): Assimilate... (*sub3.sign_extend._split): ...into this new insn-and-split. (*subpsi3_sign_extend.hi): Assimilate... (*subhi3.sign_extend2): Assimilate... (*sub3.sign_extend.): ...into this new insn. (*sub3.zero_extend.): Use avr_out_plus_ext for asm out. * config/avr/avr-protos.h (avr_out_minus): Remove. (avr_out_plus_ext): New proto. gcc/testsuite/ * gcc.target/avr/torture/add-extend.c: New test. * gcc.target/avr/torture/sub-extend.c: New test. diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 6e02161759c..568c33a7bbd 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -95,7 +95,7 @@ extern void avr_output_addr_vec (rtx_insn*, rtx); extern const char *avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]); extern const char* avr_out_bitop (rtx, rtx*, int*); extern const char* avr_out_plus (rtx, rtx*, int* =NULL, bool =true); -extern const char* avr_out_minus (rtx*); +extern const char* avr_out_plus_ext (rtx_insn*, rtx*, int*); extern const char* avr_out_round (rtx_insn *, rtx*, int* =NULL); extern const char* avr_out_addto_sp (rtx*, int*); extern const char* avr_out_xload (rtx_insn *, rtx*, int*); diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 4a7cbd0e7bc..3478c9d461a 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -8843,30 +8843,90 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len) } -/* Output subtraction of integer registers XOP[0] and XOP[2] and return "" +/* Output addition of registers YOP[0] and YOP[1] - XOP[0] = XOP[0] - XOP[2] + YOP[0] += extend (YOP[1]) - where the mode of XOP[0] is in { HI, PSI, SI }, and the mode of - XOP[2] is in { QI, HI, PSI }. When the mode of XOP[0] is larger - than the mode of XOP[2], then the latter is zero-extended on the fly. - The number of instructions will be the mode size of XOP[0]. */ + or subtraction of registers YOP[0] and YOP[2] + + YOP[0] -= extend (YOP[2]) + + where the integer modes satisfy SI >= YOP[0].mode > YOP[1/2].mode >= QI, + and the extension may be sign- or zero-extend. Returns "". + + If PLEN == NULL output the instructions. + If PLEN != NULL set *PLEN to the length of the sequence in words. */ const char * -avr_out_minus (rtx *xop) +avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen) { - int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0])); - int n_bytes2 = GET_MODE_SIZE (GET_MODE (xop[2])); + rtx regs[2]; + + const rtx src = SET_SRC (single_set (insn)); + const RTX_CODE add = GET_CODE (src); + gcc_assert (GET_CODE (src) == PLUS || GET_CODE (src) == MINUS); + + // Use XOP[] in the remainder with XOP[0] = YOP[0] and XOP[1] = YOP[1/2]. + rtx xop[2] = { yop[0], yop[add == PLUS ? 1 : 2] }; + const rtx xreg = XEXP (src, add == PLUS ? 1 : 0); + const rtx xext = XEXP (src, add == PLUS ? 0 : 1); + const RTX_CODE ext = GET_CODE (xext); + + gcc_assert (REG_P (xreg) + && (ext == ZERO_EXTEND || ext == SIGN_EXTEND)); + + const int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0])); + const int n_bytes1 = GET_MODE_SIZE (GET_MODE (xop[1])); + rtx msb1 = all_regs_rtx[n_bytes1 - 1 + REGNO (xop[1])]; + + const char *const s_ADD = add == PLUS ? "add %0,%1" : "sub %0,%1"; + const char *const s_ADC = add == PLUS ? "adc %0,%1" : "sbc %0,%1"; + const char *const s_DEC = add == PLUS + ? "adc %0,__zero_reg__" CR_TAB "sbrc %1,7" CR_TAB "dec %0" + : "sbc %0,__zero_reg__" CR_TAB "sbrc %1,7" CR_TAB "inc %0"; + + // A register that containts 8 copies of $1.msb. + rtx ext_reg = ext == ZERO_EXTEND ? zero_reg_rtx : NULL_RTX; + + if (plen) + *plen = 0; + + if (ext == SIGN_EXTEND + && (n_bytes0 > 1 + n_bytes1 + || reg_overlap_mentioned_p (msb1, xop[0]))) + { + // Sign-extending more than one byte: Set tmp_reg to 0 or -1 + // depending on $1.msb. Same for the pathological case where + // $0 and $1 overlap. + + regs[0] = ext_reg = tmp_reg_rtx; + regs[1] = msb1; + + avr_asm_len ("mov %0,%1" CR_TAB + "lsl %0" CR_TAB + "sbc %0,%0", regs, plen, 3); + } - output_asm_insn ("sub %0,%2", xop); + // Adding the bytes of $1 is just plain additions / subtractions. + // Same for the extended bytes when we have ext_reg. + + avr_asm_len (s_ADD, xop, plen, 1); for (int i = 1; i < n_bytes0; ++i) { - rtx op[2]; - op[0] = all_regs_rtx[i + REGNO (xop[0])]; - op[1] = (i < n_bytes2) ? all_regs_rtx[i + REGNO (xop[2])] : zero_reg_rtx; + regs[0] = all_regs_rtx[i + REGNO (xop[0])]; + regs[1] = i < n_bytes1 ? all_regs_rtx[i + REGNO (xop[1])] : ext_reg; + + if (! regs[1]) + { + // Extending just 1 byte: This is one instruction shorter + // than sign-extending $1.msb to tmp_reg. - output_asm_insn ("sbc %0,%1", op); + regs[1] = msb1; + avr_asm_len (s_DEC, regs, plen, 3); + } + else + avr_asm_len (s_ADC, regs, plen, 1); } return ""; @@ -11010,6 +11070,7 @@ avr_adjust_insn_length (rtx_insn *insn, int len) case ADJUST_LEN_INSV: avr_out_insv (insn, op, &len); break; case ADJUST_LEN_PLUS: avr_out_plus (insn, op, &len); break; + case ADJUST_LEN_PLUS_EXT: avr_out_plus_ext (insn, op, &len); break; case ADJUST_LEN_ADDTO_SP: avr_out_addto_sp (op, &len); break; case ADJUST_LEN_MOV8: output_movqi (insn, op, &len); break; @@ -12647,6 +12708,8 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, return true; } + // *add3.zero_extend. + // *addhi3_zero_extend if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND && REG_P (XEXP (x, 1))) { @@ -12660,6 +12723,16 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, return true; } + // *add3.sign_extend. + if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND + && REG_P (XEXP (x, 1))) + { + int size2 = GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0), 0))); + *total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode) + + (GET_MODE_SIZE (mode) > 1 + size2)); + return true; + } + switch (mode) { case E_QImode: @@ -12754,11 +12827,13 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)); return true; } - // *sub3.sign_extend2 + // *sub3.sign_extend. if (REG_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) == SIGN_EXTEND) { - *total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode)); + int size2 = GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 1), 0))); + *total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode) + + (GET_MODE_SIZE (mode) > 1 + size2)); return true; } diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 8c3e55a91ee..fc2eb061170 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -161,7 +161,7 @@ (define_attr "length" "" ;; Otherwise do special processing depending on the attribute. (define_attr "adjust_len" - "out_bitop, plus, addto_sp, sext, extr, extr_not, + "out_bitop, plus, addto_sp, sext, extr, extr_not, plus_ext, tsthi, tstpsi, tstsi, compare, compare64, call, mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32, ufract, sfract, round, @@ -261,6 +261,7 @@ (define_mode_iterator QISI [QI HI PSI SI]) (define_mode_iterator QIDI [QI HI PSI SI DI]) (define_mode_iterator QIPSI [QI HI PSI]) (define_mode_iterator HISI [HI PSI SI]) +(define_mode_iterator PSISI [PSI SI]) ;; Ordered integral and fixed-point modes of specific sizes. (define_mode_iterator ALL1 [QI QQ UQQ]) @@ -1595,33 +1596,6 @@ (define_insn "*addhi3_zero_extend1" "add %A0,%2\;adc %B0,__zero_reg__" [(set_attr "length" "2")]) -(define_insn_and_split "*addhi3.sign_extend1_split" - [(set (match_operand:HI 0 "register_operand" "=r") - (plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r")) - (match_operand:HI 2 "register_operand" "0")))] - "" - "#" - "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (sign_extend:HI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) - - -(define_insn "*addhi3.sign_extend1" - [(set (match_operand:HI 0 "register_operand" "=r") - (plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r")) - (match_operand:HI 2 "register_operand" "0"))) - (clobber (reg:CC REG_CC))] - "reload_completed" - { - return reg_overlap_mentioned_p (operands[0], operands[1]) - ? "mov __tmp_reg__,%1\;add %A0,%1\;adc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;dec %B0" - : "add %A0,%1\;adc %B0,__zero_reg__\;sbrc %1,7\;dec %B0"; - } - [(set (attr "length") - (symbol_ref ("4 + reg_overlap_mentioned_p (operands[0], operands[1])")))]) - (define_insn_and_split "*addhi3_zero_extend.const_split" [(set (match_operand:HI 0 "register_operand" "=d") (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "0")) @@ -1877,110 +1851,108 @@ (define_insn "*add3" [(set_attr "length" "4") (set_attr "adjust_len" "plus")]) -(define_insn_and_split "*addpsi3_zero_extend.qi_split" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r")) - (match_operand:PSI 2 "register_operand" "0")))] - "" - "#" - "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:PSI (zero_extend:PSI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) - -(define_insn "*addpsi3_zero_extend.qi" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r")) - (match_operand:PSI 2 "register_operand" "0"))) - (clobber (reg:CC REG_CC))] - "reload_completed" - "add %A0,%A1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__" - [(set_attr "length" "3")]) -(define_insn_and_split "*addpsi3_zero_extend.hi_split" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r")) - (match_operand:PSI 2 "register_operand" "0")))] - "" +;; "*addpsi3.zero_extend.qi_split" "*addpsi3.zero_extend.hi_split" +;; "*addsi3.zero_extend.qi_split" "*addsi3.zero_extend.hi_split" +;; "*addsi3.zero_extend.psi_split" +;; The HI case is treated in an own insn as it can more than just "r,r,0". +(define_insn_and_split "*add3.zero_extend._split" + [(set (match_operand:PSISI 0 "register_operand" "=r") + (plus:PSISI (zero_extend:PSISI (match_operand:QIPSI 1 "register_operand" "r")) + (match_operand:PSISI 2 "register_operand" "0")))] + "GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" "#" "&& reload_completed" [(parallel [(set (match_dup 0) - (plus:PSI (zero_extend:PSI (match_dup 1)) - (match_dup 2))) + (plus:PSISI (zero_extend:PSISI (match_dup 1)) + (match_dup 2))) (clobber (reg:CC REG_CC))])]) -(define_insn "*addpsi3_zero_extend.hi" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r")) - (match_operand:PSI 2 "register_operand" "0"))) +;; "*addpsi3.zero_extend.qi" "*addpsi3.zero_extend.hi" +;; "*addsi3.zero_extend.qi" "*addsi3.zero_extend.hi" +;; "*addsi3.zero_extend.psi" +(define_insn "*add3.zero_extend." + [(set (match_operand:PSISI 0 "register_operand" "=r") + (plus:PSISI (zero_extend:PSISI (match_operand:QIPSI 1 "register_operand" "r")) + (match_operand:PSISI 2 "register_operand" "0"))) (clobber (reg:CC REG_CC))] - "reload_completed" - "add %A0,%A1\;adc %B0,%B1\;adc %C0,__zero_reg__" - [(set_attr "length" "3")]) - -(define_insn_and_split "*addpsi3_sign_extend.hi_split" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (sign_extend:PSI (match_operand:HI 1 "register_operand" "r")) - (match_operand:PSI 2 "register_operand" "0")))] - "" - "#" - "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:PSI (sign_extend:PSI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + "reload_completed + && GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" + { + return avr_out_plus_ext (insn, operands, nullptr); + } + [(set_attr "length" "")]) -(define_insn "*addpsi3_sign_extend.hi" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (sign_extend:PSI (match_operand:HI 1 "register_operand" "r")) - (match_operand:PSI 2 "register_operand" "0"))) - (clobber (reg:CC REG_CC))] - "reload_completed" - "add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;sbrc %B1,7\;dec %C0" - [(set_attr "length" "5")]) -(define_insn_and_split "*addsi3_zero_extend_split" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r")) - (match_operand:SI 2 "register_operand" "0")))] - "" +;; "*addhi3.sign_extend.qi_split" +;; "*addpsi3.sign_extend.qi_split" "*addpsi3.sign_extend.hi_split" +;; "*addsi3.sign_extend.qi_split" "*addsi3.sign_extend.hi_split" +;; "*addsi3.sign_extend.psi_split" +(define_insn_and_split "*add3.sign_extend._split" + [(set (match_operand:HISI 0 "register_operand" "=r") + (plus:HISI (sign_extend:HISI (match_operand:QIPSI 1 "register_operand" "r")) + (match_operand:HISI 2 "register_operand" "0")))] + "GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" "#" "&& reload_completed" [(parallel [(set (match_dup 0) - (plus:SI (zero_extend:SI (match_dup 1)) - (match_dup 2))) + (plus:HISI (sign_extend:HISI (match_dup 1)) + (match_dup 2))) (clobber (reg:CC REG_CC))])]) -(define_insn "*addsi3_zero_extend" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r")) - (match_operand:SI 2 "register_operand" "0"))) +;; "*addhi3.sign_extend.qi" +;; "*addpsi3.sign_extend.qi" "*addpsi3.sign_extend.hi" +;; "*addsi3.sign_extend.qi" "*addsi3.sign_extend.hi" +;; "*addsi3.sign_extend.psi" +(define_insn "*add3.sign_extend." + [(set (match_operand:HISI 0 "register_operand" "=r") + (plus:HISI (sign_extend:HISI (match_operand:QIPSI 1 "register_operand" "r")) + (match_operand:HISI 2 "register_operand" "0"))) (clobber (reg:CC REG_CC))] - "reload_completed" - "add %A0,%1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__" - [(set_attr "length" "4")]) - -(define_insn_and_split "*addsi3_zero_extend.hi_split" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (match_operand:SI 2 "register_operand" "0")))] - "" + "reload_completed + && GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" + { + return avr_out_plus_ext (insn, operands, nullptr); + } + [(set (attr "length") + (symbol_ref "3 + ")) + (set_attr "adjust_len" "plus_ext")]) + + +;; "*subhi3.sign_extend.qi_split" +;; "*subpsi3.sign_extend.qi_split" "*subpsi3.sign_extend.hi_split" +;; "*subsi3.sign_extend.qi_split" "*subsi3.sign_extend.hi_split" +;; "*subsi3.sign_extend.psi_split" +(define_insn_and_split "*sub3.sign_extend._split" + [(set (match_operand:HISI 0 "register_operand" "=r") + (minus:HISI (match_operand:HISI 1 "register_operand" "0") + (sign_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))] + "GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" "#" "&& reload_completed" [(parallel [(set (match_dup 0) - (plus:SI (zero_extend:SI (match_dup 1)) - (match_dup 2))) + (minus:HISI (match_dup 1) + (sign_extend:HISI (match_dup 2)))) (clobber (reg:CC REG_CC))])]) -(define_insn "*addsi3_zero_extend.hi" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (match_operand:SI 2 "register_operand" "0"))) +;; "*subhi3.sign_extend.qi" +;; "*subpsi3.sign_extend.qi" "*subpsi3.sign_extend.hi" +;; "*subsi3.sign_extend.qi" "*subsi3.sign_extend.hi" +;; "*subsi3.sign_extend.psi" +(define_insn "*sub3.sign_extend." + [(set (match_operand:HISI 0 "register_operand" "=r") + (minus:HISI (match_operand:HISI 1 "register_operand" "0") + (sign_extend:HISI (match_operand:QIPSI 2 "register_operand" "r")))) (clobber (reg:CC REG_CC))] - "reload_completed" - "add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__" - [(set_attr "length" "4")]) + "reload_completed + && GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" + { + return avr_out_plus_ext (insn, operands, nullptr); + } + [(set (attr "length") + (symbol_ref "3 + ")) + (set_attr "adjust_len" "plus_ext")]) + (define_insn_and_split "addpsi3" [(set (match_operand:PSI 0 "register_operand" "=??r,d ,d,r") @@ -2031,27 +2003,6 @@ (define_insn "*subpsi3" [(set_attr "length" "3")]) -(define_insn_and_split "*subpsi3_sign_extend.hi_split" - [(set (match_operand:PSI 0 "register_operand" "=r") - (minus:PSI (match_operand:PSI 1 "register_operand" "0") - (sign_extend:PSI (match_operand:HI 2 "register_operand" "r"))))] - "" - "#" - "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:PSI (match_dup 1) - (sign_extend:PSI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) - -(define_insn "*subpsi3_sign_extend.hi" - [(set (match_operand:PSI 0 "register_operand" "=r") - (minus:PSI (match_operand:PSI 1 "register_operand" "0") - (sign_extend:PSI (match_operand:HI 2 "register_operand" "r")))) - (clobber (reg:CC REG_CC))] - "reload_completed" - "sub %A0,%A2\;sbc %B0,%B2\;sbc %C0,__zero_reg__\;sbrc %B2,7\;inc %C0" - [(set_attr "length" "5")]) - ;----------------------------------------------------------------------------- ; sub bytes @@ -2114,33 +2065,6 @@ (define_insn "*sub3" [(set_attr "adjust_len" "plus")]) -(define_insn_and_split "*subhi3.sign_extend2_split" - [(set (match_operand:HI 0 "register_operand" "=r") - (minus:HI (match_operand:HI 1 "register_operand" "0") - (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))] - "" - "#" - "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:HI (match_dup 1) - (sign_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) - - -(define_insn "*subhi3.sign_extend2" - [(set (match_operand:HI 0 "register_operand" "=r") - (minus:HI (match_operand:HI 1 "register_operand" "0") - (sign_extend:HI (match_operand:QI 2 "register_operand" "r")))) - (clobber (reg:CC REG_CC))] - "reload_completed" - { - return reg_overlap_mentioned_p (operands[0], operands[2]) - ? "mov __tmp_reg__,%2\;sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;inc %B0" - : "sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc %2,7\;inc %B0"; - } - [(set (attr "length") - (symbol_ref ("4 + reg_overlap_mentioned_p (operands[0], operands[2])")))]) - ;; "subsi3" ;; "subsq3" "subusq3" ;; "subsa3" "subusa3" @@ -2199,7 +2123,7 @@ (define_insn "*sub3.zero_extend." "reload_completed && GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" { - return avr_out_minus (operands); + return avr_out_plus_ext (insn, operands, nullptr); } [(set_attr "length" "")]) diff --git a/gcc/testsuite/gcc.target/avr/torture/add-extend.c b/gcc/testsuite/gcc.target/avr/torture/add-extend.c new file mode 100644 index 00000000000..42445e837e1 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/add-extend.c @@ -0,0 +1,113 @@ +/* { dg-do run } */ + +typedef __UINT8_TYPE__ u8; +typedef __UINT16_TYPE__ u16; +typedef __uint24 u24; +typedef __UINT32_TYPE__ u32; + +typedef __INT8_TYPE__ s8; +typedef __INT16_TYPE__ s16; +typedef __int24 s24; +typedef __INT32_TYPE__ s32; + +#define NI __attribute__((noinline,noclone,no_icf)) + +NI u32 addu_32_8 (u32 a, u8 b) { return a + b; } +NI u32 addu_32_16 (u32 a, u16 b) { return a + b; } +NI u32 addu_32_24 (u32 a, u24 b) { return a + b; } + +NI u24 addu_24_8 (u24 a, u8 b) { return a + b; } +NI u24 addu_24_16 (u24 a, u16 b) { return a + b; } + +NI u16 addu_16_8 (u16 a, u8 b) { return a + b; } + +/************************/ + +NI s32 adds_32_8 (s32 a, s8 b) { return a + b; } +NI s32 adds_32_16 (s32 a, s16 b) { return a + b; } +NI s32 adds_32_24 (s32 a, s24 b) { return a + b; } + +NI s24 adds_24_8 (s24 a, s8 b) { return a + b; } +NI s24 adds_24_16 (s24 a, s16 b) { return a + b; } + +NI s16 adds_16_8 (s16 a, s8 b) { return a + b; } + +/************************/ + +NI u32 addu_32 (u32 a, u32 b) { return a + b; } +NI u24 addu_24 (u24 a, u24 b) { return a + b; } +NI u16 addu_16 (u16 a, u16 b) { return a + b; } + +NI s32 adds_32 (s32 a, s32 b) { return a + b; } +NI s24 adds_24 (s24 a, s24 b) { return a + b; } +NI s16 adds_16 (s16 a, s16 b) { return a + b; } + +/************************/ + +NI u8 next (void *p0, u8 n_bytes) +{ + u8 *p = (u8*) p0; + + u8 n; + for (n = 0; n < n_bytes; ++n) + { + u8 val = *p; + + switch (val) + { + case 0x00: val = 0x01; break; + case 0x01: val = 0xfe; break; + case 0xfe: val = 0xff; break; + case 0xff: val = 0x00; break; + default: ++val; break; + } + *p++ = val; + if (val) + return 1; + } + + return 0; +} + +#define MK_TEST(A, B) \ +NI void test_##A##_##B (void) \ +{ \ + u##A a = 0; \ + do \ + { \ + u##B b = 0; \ + do \ + { \ + if (addu_##A##_##B (a, b) != addu_##A (a, b)) \ + __builtin_exit (11); \ + \ + if (adds_##A##_##B (a, b) != adds_##A ((s##A) a, (s##B) b)) \ + __builtin_exit (13); \ + \ + } while (next (&b, sizeof (b))); \ + } while (next (&a, sizeof (a))); \ +} + +MK_TEST (16, 8) + +MK_TEST (24, 8) +MK_TEST (24, 16) + +MK_TEST (32, 8) +MK_TEST (32, 16) +MK_TEST (32, 24) + + +int main (void) +{ + test_16_8 (); + + test_24_8 (); + test_24_16 (); + + test_32_8 (); + test_32_16 (); + test_32_24 (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/torture/sub-extend.c b/gcc/testsuite/gcc.target/avr/torture/sub-extend.c new file mode 100644 index 00000000000..91b65c07ccf --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/sub-extend.c @@ -0,0 +1,113 @@ +/* { dg-do run } */ + +typedef __UINT8_TYPE__ u8; +typedef __UINT16_TYPE__ u16; +typedef __uint24 u24; +typedef __UINT32_TYPE__ u32; + +typedef __INT8_TYPE__ s8; +typedef __INT16_TYPE__ s16; +typedef __int24 s24; +typedef __INT32_TYPE__ s32; + +#define NI __attribute__((noinline,noclone,no_icf)) + +NI u32 subu_32_8 (u32 a, u8 b) { return a - b; } +NI u32 subu_32_16 (u32 a, u16 b) { return a - b; } +NI u32 subu_32_24 (u32 a, u24 b) { return a - b; } + +NI u24 subu_24_8 (u24 a, u8 b) { return a - b; } +NI u24 subu_24_16 (u24 a, u16 b) { return a - b; } + +NI u16 subu_16_8 (u16 a, u8 b) { return a - b; } + +/************************/ + +NI s32 subs_32_8 (s32 a, s8 b) { return a - b; } +NI s32 subs_32_16 (s32 a, s16 b) { return a - b; } +NI s32 subs_32_24 (s32 a, s24 b) { return a - b; } + +NI s24 subs_24_8 (s24 a, s8 b) { return a - b; } +NI s24 subs_24_16 (s24 a, s16 b) { return a - b; } + +NI s16 subs_16_8 (s16 a, s8 b) { return a - b; } + +/************************/ + +NI u32 subu_32 (u32 a, u32 b) { return a - b; } +NI u24 subu_24 (u24 a, u24 b) { return a - b; } +NI u16 subu_16 (u16 a, u16 b) { return a - b; } + +NI s32 subs_32 (s32 a, s32 b) { return a - b; } +NI s24 subs_24 (s24 a, s24 b) { return a - b; } +NI s16 subs_16 (s16 a, s16 b) { return a - b; } + +/************************/ + +NI u8 next (void *p0, u8 n_bytes) +{ + u8 *p = (u8*) p0; + + u8 n; + for (n = 0; n < n_bytes; ++n) + { + u8 val = *p; + + switch (val) + { + case 0x00: val = 0x01; break; + case 0x01: val = 0xfe; break; + case 0xfe: val = 0xff; break; + case 0xff: val = 0x00; break; + default: ++val; break; + } + *p++ = val; + if (val) + return 1; + } + + return 0; +} + +#define MK_TEST(A, B) \ +NI void test_##A##_##B (void) \ +{ \ + u##A a = 0; \ + do \ + { \ + u##B b = 0; \ + do \ + { \ + if (subu_##A##_##B (a, b) != subu_##A (a, b)) \ + __builtin_exit (11); \ + \ + if (subs_##A##_##B (a, b) != subs_##A ((s##A) a, (s##B) b)) \ + __builtin_exit (13); \ + \ + } while (next (&b, sizeof (b))); \ + } while (next (&a, sizeof (a))); \ +} + +MK_TEST (16, 8) + +MK_TEST (24, 8) +MK_TEST (24, 16) + +MK_TEST (32, 8) +MK_TEST (32, 16) +MK_TEST (32, 24) + + +int main (void) +{ + test_16_8 (); + + test_24_8 (); + test_24_16 (); + + test_32_8 (); + test_32_16 (); + test_32_24 (); + + return 0; +}