Index: gcc/config/avr/predicates.md =================================================================== --- gcc/config/avr/predicates.md (revision 190299) +++ gcc/config/avr/predicates.md (working copy) @@ -74,7 +74,7 @@ (define_predicate "nox_general_operand" ;; Return 1 if OP is the zero constant for MODE. (define_predicate "const0_operand" - (and (match_code "const_int,const_double") + (and (match_code "const_int,const_fixed,const_double") (match_test "op == CONST0_RTX (mode)"))) ;; Return 1 if OP is the one constant integer for MODE. @@ -248,3 +248,21 @@ (define_predicate "s16_operand" (define_predicate "o16_operand" (and (match_code "const_int") (match_test "IN_RANGE (INTVAL (op), -(1<<16), -1)"))) + +;; Const int, fixed, or double operand +(define_predicate "const_operand" + (ior (match_code "const_fixed") + (match_code "const_double") + (match_operand 0 "const_int_operand"))) + +;; Const int, const fixed, or const double operand +(define_predicate "nonmemory_or_const_operand" + (ior (match_code "const_fixed") + (match_code "const_double") + (match_operand 0 "nonmemory_operand"))) + +;; Immediate, const fixed, or const double operand +(define_predicate "const_or_immediate_operand" + (ior (match_code "const_fixed") + (match_code "const_double") + (match_operand 0 "immediate_operand"))) Index: gcc/config/avr/avr-fixed.md =================================================================== --- gcc/config/avr/avr-fixed.md (revision 0) +++ gcc/config/avr/avr-fixed.md (revision 0) @@ -0,0 +1,334 @@ +;; This file contains instructions that support fixed-point operations +;; for Atmel AVR micro controllers. +;; Copyright (C) 2012 +;; Free Software Foundation, Inc. +;; Contributed by Sean D'Epagnier (sean@depagnier.com) + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +(define_mode_iterator ALL1Q [(QQ "") (UQQ "")]) +(define_mode_iterator ALL2Q [(HQ "") (UHQ "")]) +(define_mode_iterator ALL2A [(HA "") (UHA "")]) +(define_mode_iterator ALL2QA [(HQ "") (UHQ "") + (HA "") (UHA "")]) +(define_mode_iterator ALL4A [(SA "") (USA "")]) + +;;; Conversions + +(define_mode_iterator FIXED_A + [(QQ "") (UQQ "") + (HQ "") (UHQ "") (HA "") (UHA "") + (SQ "") (USQ "") (SA "") (USA "") + (DQ "") (UDQ "") (DA "") (UDA "") + (TA "") (UTA "") + (QI "") (HI "") (SI "") (DI "")]) + +;; Same so that be can build cross products + +(define_mode_iterator FIXED_B + [(QQ "") (UQQ "") + (HQ "") (UHQ "") (HA "") (UHA "") + (SQ "") (USQ "") (SA "") (USA "") + (DQ "") (UDQ "") (DA "") (UDA "") + (TA "") (UTA "") + (QI "") (HI "") (SI "") (DI "")]) + +(define_insn "fract2" + [(set (match_operand:FIXED_A 0 "register_operand" "=r") + (fract_convert:FIXED_A + (match_operand:FIXED_B 1 "register_operand" "r")))] + "mode != mode" + { + return avr_out_fract (insn, operands, true, NULL); + } + [(set_attr "cc" "clobber") + (set_attr "adjust_len" "sfract")]) + +(define_insn "fractuns2" + [(set (match_operand:FIXED_A 0 "register_operand" "=r") + (unsigned_fract_convert:FIXED_A + (match_operand:FIXED_B 1 "register_operand" "r")))] + "mode != mode" + { + return avr_out_fract (insn, operands, false, NULL); + } + [(set_attr "cc" "clobber") + (set_attr "adjust_len" "ufract")]) + +;****************************************************************************** +; mul + +(define_insn "mulqq3" + [(set (match_operand:QQ 0 "register_operand" "=r") + (mult:QQ (match_operand:QQ 1 "register_operand" "a") + (match_operand:QQ 2 "register_operand" "a")))] + "AVR_HAVE_MUL" + "fmuls %1,%2\;mov %0,r1\;clr __zero_reg__" + [(set_attr "length" "3") + (set_attr "cc" "clobber")]) + +(define_insn "muluqq3" + [(set (match_operand:UQQ 0 "register_operand" "=r") + (mult:UQQ (match_operand:UQQ 1 "register_operand" "r") + (match_operand:UQQ 2 "register_operand" "r")))] + "AVR_HAVE_MUL" + "mul %1,%2\;mov %0,r1\;clr __zero_reg__" + [(set_attr "length" "3") + (set_attr "cc" "clobber")]) + +;; (reg:ALL2Q 20) not clobbered on the enhanced core. +;; Use registers from 16-23 so we can use FMULS. +;; All call-used registers clobbered otherwise - Normal library call. + +;; "mulhq3" "muluhq3" +(define_expand "mul3" + [(set (reg:ALL2Q 22) + (match_operand:ALL2Q 1 "register_operand" "")) + (set (reg:ALL2Q 20) + (match_operand:ALL2Q 2 "register_operand" "")) + (parallel [(set (reg:ALL2Q 18) + (mult:ALL2Q (reg:ALL2Q 22) + (reg:ALL2Q 20))) + (clobber (reg:ALL2Q 22))]) + (set (match_operand:ALL2Q 0 "register_operand" "") + (reg:ALL2Q 18))] + "AVR_HAVE_MUL") + +;; "*mulhq3_enh_call" "*muluhq3_enh_call" +(define_insn "*mul3_enh_call" + [(set (reg:ALL2Q 18) + (mult:ALL2Q (reg:ALL2Q 22) + (reg:ALL2Q 20))) + (clobber (reg:ALL2Q 22))] + "AVR_HAVE_MUL" + "%~call __mul3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +; Special calls for with and without mul. +;; "mulha3" "muluha3" +(define_expand "mul3" + [(set (reg:ALL2A 22) + (match_operand:ALL2A 1 "register_operand" "")) + (set (reg:ALL2A 20) + (match_operand:ALL2A 2 "register_operand" "")) + (parallel [(set (reg:ALL2A 18) + (mult:ALL2A (reg:ALL2A 22) + (reg:ALL2A 20))) + (clobber (reg:ALL2A 22))]) + (set (match_operand:ALL2A 0 "register_operand" "") + (reg:ALL2A 18))] + "" + { + if (!AVR_HAVE_MUL) + { + emit_insn (gen_mul3_call (operands[0], operands[1], operands[2])); + DONE; + } + }) + +;; "*mulha3_enh" "*muluhq3_enh" +(define_insn "*mul3_enh" + [(set (reg:ALL2A 18) + (mult:ALL2A (reg:ALL2A 22) + (reg:ALL2A 20))) + (clobber (reg:ALL2A 22))] + "AVR_HAVE_MUL" + "%~call __mul3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; Without MUL. Clobbers both inputs, needs a separate output register. + +;; "mulha3_call" "muluhq3_call" +(define_expand "mul3_call" + [(set (reg:ALL2A 24) + (match_operand:ALL2A 1 "register_operand" "")) + (set (reg:ALL2A 22) + (match_operand:ALL2A 2 "register_operand" "")) + (parallel [(set (reg:ALL2A 18) + (mult:ALL2A (reg:ALL2A 22) + (reg:ALL2A 24))) + (clobber (reg:ALL2A 22)) + (clobber (reg:ALL2A 24))]) + (set (match_operand:ALL2A 0 "register_operand" "") + (reg:ALL2A 18))] + "!AVR_HAVE_MUL") + +;; "*mulha3_call" "*muluha3_call" +(define_insn "*mul3_call" + [(set (reg:ALL2A 18) + (mult:ALL2A (reg:ALL2A 22) + (reg:ALL2A 24))) + (clobber (reg:ALL2A 22)) + (clobber (reg:ALL2A 24))] + "!AVR_HAVE_MUL" + "%~call __mul3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; On the enhanced core, don't clobber either input and use a separate output. +;; R15 is needed as a zero register since R1 aka. __zero_reg__ is used for MUL. + +;; "mulsa3" "mulusa3" +(define_expand "mul3" + [(set (reg:ALL4A 16) + (match_operand:ALL4A 1 "register_operand" "")) + (set (reg:ALL4A 20) + (match_operand:ALL4A 2 "register_operand" "")) + (parallel [(set (reg:ALL4A 24) + (mult:ALL4A (reg:ALL4A 16) + (reg:ALL4A 20))) + (clobber (reg:QI 15))]) + (set (match_operand:ALL4A 0 "register_operand" "") + (reg:ALL4A 24))] + "" + { + if (!AVR_HAVE_MUL) + { + emit_insn (gen_mul3_call (operands[0], operands[1], operands[2])); + DONE; + } + }) + +;; "*mulsa3_enh" "*mulusa3_enh" +(define_insn "*mul3_enh" + [(set (reg:ALL4A 24) + (mult:ALL4A (reg:ALL4A 16) + (reg:ALL4A 20))) + (clobber (reg:QI 15))] + "AVR_HAVE_MUL" + "%~call __mul3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; Without MUL. Clobbers both inputs, needs a separate output, +;; needs two more scratch registers. + +;; "mulsa3_call" "mulusa3_call" +(define_expand "mul3_call" + [(set (reg:ALL4A 18) + (match_operand:ALL4A 1 "register_operand" "")) + (set (reg:ALL4A 24) + (match_operand:ALL4A 2 "register_operand" "")) + (parallel [(set (reg:ALL4A 14) + (mult:ALL4A (reg:ALL4A 18) + (reg:ALL4A 24))) + (clobber (reg:ALL4A 18)) + (clobber (reg:ALL4A 24)) + (clobber (reg:HI 22))]) + (set (match_operand:ALL4A 0 "register_operand" "") + (reg:ALL4A 14))] + "!AVR_HAVE_MUL") + +;; "*mulsa3_call" "*mulusa3_call" +(define_insn "*mul3_call" + [(set (reg:ALL4A 14) + (mult:ALL4A (reg:ALL4A 18) + (reg:ALL4A 24))) + (clobber (reg:ALL4A 18)) + (clobber (reg:ALL4A 24)) + (clobber (reg:HI 22))] + "!AVR_HAVE_MUL" + "%~call __mul3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +; / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / +; div + +;; Expand signed and unsigned in one shot +(define_code_iterator usdiv [udiv div]) + +;; "divqq3" "udivuqq3" +(define_expand "3" + [(set (reg:ALL1Q 25) + (match_operand:ALL1Q 1 "register_operand" "")) + (set (reg:ALL1Q 22) + (match_operand:ALL1Q 2 "register_operand" "")) + (parallel [(set (reg:ALL1Q 24) + (usdiv:ALL1Q (reg:ALL1Q 25) + (reg:ALL1Q 22))) + (clobber (reg:ALL1Q 25))]) + (set (match_operand:ALL1Q 0 "register_operand" "") + (reg:ALL1Q 24))]) + +;; "*divqq3_call" "*udivuqq3_call" +(define_insn "*3_call" + [(set (reg:ALL1Q 24) + (usdiv:ALL1Q (reg:ALL1Q 25) + (reg:ALL1Q 22))) + (clobber (reg:ALL1Q 25))] + "" + "%~call __3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; "divhq3" "udivuhq3" "divha3" "udivuha3" +(define_expand "3" + [(set (reg:ALL2QA 26) + (match_operand:ALL2QA 1 "register_operand" "")) + (set (reg:ALL2QA 22) + (match_operand:ALL2QA 2 "register_operand" "")) + (parallel [(set (reg:ALL2QA 24) + (usdiv:ALL2QA (reg:ALL2QA 26) + (reg:ALL2QA 22))) + (clobber (reg:ALL2QA 26)) + (clobber (reg:QI 21))]) + (set (match_operand:ALL2QA 0 "register_operand" "") + (reg:ALL2QA 24))]) + +;; "*divhq3_call" "*udivuhq3_call" +;; "*divha3_call" "*udivuha3_call" +(define_insn "*3_call" + [(set (reg:ALL2QA 24) + (usdiv:ALL2QA (reg:ALL2QA 26) + (reg:ALL2QA 22))) + (clobber (reg:ALL2QA 26)) + (clobber (reg:QI 21))] + "" + "%~call __3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; Note the first parameter gets passed in already offset by 2 bytes + +;; "divsa3" "udivusa3" +(define_expand "3" + [(set (reg:ALL4A 24) + (match_operand:ALL4A 1 "register_operand" "")) + (set (reg:ALL4A 18) + (match_operand:ALL4A 2 "register_operand" "")) + (parallel [(set (reg:ALL4A 22) + (usdiv:ALL4A (reg:ALL4A 24) + (reg:ALL4A 18))) + (clobber (reg:HI 26)) + (clobber (reg:HI 30))]) + (set (match_operand:ALL4A 0 "register_operand" "") + (reg:ALL4A 22))]) + +;; "*divsa3_call" "*udivusa3_call" +(define_insn "*3_call" + [(set (reg:ALL4A 22) + (usdiv:ALL4A (reg:ALL4A 24) + (reg:ALL4A 18))) + (clobber (reg:HI 26)) + (clobber (reg:HI 30))] + "" + "%~call __3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) Index: gcc/config/avr/avr-dimode.md =================================================================== --- gcc/config/avr/avr-dimode.md (revision 190299) +++ gcc/config/avr/avr-dimode.md (working copy) @@ -47,44 +47,58 @@ (define_constants [(ACC_A 18) (ACC_B 10)]) +;; Supported modes that are 8 bytes wide +(define_mode_iterator ALL8 [(DI "") + (DQ "") (UDQ "") + (DA "") (UDA "") + (TA "") (UTA "")]) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Addition ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define_expand "adddi3" - [(parallel [(match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" "") - (match_operand:DI 2 "general_operand" "")])] +;; "adddi3" +;; "adddq3" "addudq3" +;; "addda3" "adduda3" +;; "addta3" "adduta3" +(define_expand "add3" + [(parallel [(match_operand:ALL8 0 "general_operand" "") + (match_operand:ALL8 1 "general_operand" "") + (match_operand:ALL8 2 "general_operand" "")])] "avr_have_dimode" { - rtx acc_a = gen_rtx_REG (DImode, ACC_A); + rtx acc_a = gen_rtx_REG (mode, ACC_A); emit_move_insn (acc_a, operands[1]); - if (s8_operand (operands[2], VOIDmode)) + if (DImode == mode + && s8_operand (operands[2], VOIDmode)) { emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]); emit_insn (gen_adddi3_const8_insn ()); } - else if (CONST_INT_P (operands[2]) - || CONST_DOUBLE_P (operands[2])) + else if (const_operand (operands[2], GET_MODE (operands[2]))) { - emit_insn (gen_adddi3_const_insn (operands[2])); + emit_insn (gen_add3_const_insn (operands[2])); } else { - emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]); - emit_insn (gen_adddi3_insn ()); + emit_move_insn (gen_rtx_REG (mode, ACC_B), operands[2]); + emit_insn (gen_add3_insn ()); } emit_move_insn (operands[0], acc_a); DONE; }) -(define_insn "adddi3_insn" - [(set (reg:DI ACC_A) - (plus:DI (reg:DI ACC_A) - (reg:DI ACC_B)))] +;; "adddi3_insn" +;; "adddq3_insn" "addudq3_insn" +;; "addda3_insn" "adduda3_insn" +;; "addta3_insn" "adduta3_insn" +(define_insn "add3_insn" + [(set (reg:ALL8 ACC_A) + (plus:ALL8 (reg:ALL8 ACC_A) + (reg:ALL8 ACC_B)))] "avr_have_dimode" "%~call __adddi3" [(set_attr "adjust_len" "call") @@ -99,10 +113,14 @@ (define_insn "adddi3_const8_insn" [(set_attr "adjust_len" "call") (set_attr "cc" "clobber")]) -(define_insn "adddi3_const_insn" - [(set (reg:DI ACC_A) - (plus:DI (reg:DI ACC_A) - (match_operand:DI 0 "const_double_operand" "n")))] +;; "adddi3_const_insn" +;; "adddq3_const_insn" "addudq3_const_insn" +;; "addda3_const_insn" "adduda3_const_insn" +;; "addta3_const_insn" "adduta3_const_insn" +(define_insn "add3_const_insn" + [(set (reg:ALL8 ACC_A) + (plus:ALL8 (reg:ALL8 ACC_A) + (match_operand:ALL8 0 "const_operand" "n Ynn")))] "avr_have_dimode && !s8_operand (operands[0], VOIDmode)" { @@ -116,30 +134,62 @@ (define_insn "adddi3_const_insn" ;; Subtraction ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define_expand "subdi3" - [(parallel [(match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" "") - (match_operand:DI 2 "general_operand" "")])] +;; "subdi3" +;; "subdq3" "subudq3" +;; "subda3" "subuda3" +;; "subta3" "subuta3" +(define_expand "sub3" + [(parallel [(match_operand:ALL8 0 "general_operand" "") + (match_operand:ALL8 1 "general_operand" "") + (match_operand:ALL8 2 "general_operand" "")])] "avr_have_dimode" { - rtx acc_a = gen_rtx_REG (DImode, ACC_A); + rtx acc_a = gen_rtx_REG (mode, ACC_A); emit_move_insn (acc_a, operands[1]); - emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]); - emit_insn (gen_subdi3_insn ()); + + if (const_operand (operands[2], GET_MODE (operands[2]))) + { + emit_insn (gen_sub3_const_insn (operands[2])); + } + else + { + emit_move_insn (gen_rtx_REG (mode, ACC_B), operands[2]); + emit_insn (gen_sub3_insn ()); + } + emit_move_insn (operands[0], acc_a); DONE; }) -(define_insn "subdi3_insn" - [(set (reg:DI ACC_A) - (minus:DI (reg:DI ACC_A) - (reg:DI ACC_B)))] +;; "subdi3_insn" +;; "subdq3_insn" "subudq3_insn" +;; "subda3_insn" "subuda3_insn" +;; "subta3_insn" "subuta3_insn" +(define_insn "sub3_insn" + [(set (reg:ALL8 ACC_A) + (minus:ALL8 (reg:ALL8 ACC_A) + (reg:ALL8 ACC_B)))] "avr_have_dimode" "%~call __subdi3" [(set_attr "adjust_len" "call") (set_attr "cc" "set_czn")]) +;; "subdi3_const_insn" +;; "subdq3_const_insn" "subudq3_const_insn" +;; "subda3_const_insn" "subuda3_const_insn" +;; "subta3_const_insn" "subuta3_const_insn" +(define_insn "sub3_const_insn" + [(set (reg:ALL8 ACC_A) + (minus:ALL8 (reg:ALL8 ACC_A) + (match_operand:ALL8 0 "const_operand" "n Ynn")))] + "avr_have_dimode" + { + return avr_out_minus64 (operands[0], NULL); + } + [(set_attr "adjust_len" "minus64") + (set_attr "cc" "clobber")]) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Negation @@ -180,15 +230,19 @@ (define_expand "conditional_jump" (pc)))] "avr_have_dimode") -(define_expand "cbranchdi4" - [(parallel [(match_operand:DI 1 "register_operand" "") - (match_operand:DI 2 "nonmemory_operand" "") +;; "cbranchdi4" +;; "cbranchdq4" "cbranchudq4" +;; "cbranchda4" "cbranchuda4" +;; "cbranchta4" "cbranchuta4" +(define_expand "cbranch4" + [(parallel [(match_operand:ALL8 1 "register_operand" "") + (match_operand:ALL8 2 "nonmemory_operand" "") (match_operator 0 "ordered_comparison_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" ""))])] "avr_have_dimode" { - rtx acc_a = gen_rtx_REG (DImode, ACC_A); + rtx acc_a = gen_rtx_REG (mode, ACC_A); emit_move_insn (acc_a, operands[1]); @@ -197,25 +251,28 @@ (define_expand "cbranchdi4" emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]); emit_insn (gen_compare_const8_di2 ()); } - else if (CONST_INT_P (operands[2]) - || CONST_DOUBLE_P (operands[2])) + else if (const_operand (operands[2], GET_MODE (operands[2]))) { - emit_insn (gen_compare_const_di2 (operands[2])); + emit_insn (gen_compare_const_2 (operands[2])); } else { - emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]); - emit_insn (gen_compare_di2 ()); + emit_move_insn (gen_rtx_REG (mode, ACC_B), operands[2]); + emit_insn (gen_compare_2 ()); } emit_jump_insn (gen_conditional_jump (operands[0], operands[3])); DONE; }) -(define_insn "compare_di2" +;; "compare_qi2" +;; "compare_qq2" "compare_udq2" +;; "compare_da2" "compare_uda2" +;; "compare_ta2" "compare_uta2" +(define_insn "compare_2" [(set (cc0) - (compare (reg:DI ACC_A) - (reg:DI ACC_B)))] + (compare (reg:ALL8 ACC_A) + (reg:ALL8 ACC_B)))] "avr_have_dimode" "%~call __cmpdi2" [(set_attr "adjust_len" "call") @@ -230,10 +287,14 @@ (define_insn "compare_const8_di2" [(set_attr "adjust_len" "call") (set_attr "cc" "compare")]) -(define_insn "compare_const_di2" +;; "compare_const_qi2" +;; "compare_const_qq2" "compare_const_udq2" +;; "compare_const_da2" "compare_const_uda2" +;; "compare_const_ta2" "compare_const_uta2" +(define_insn "compare_const_2" [(set (cc0) - (compare (reg:DI ACC_A) - (match_operand:DI 0 "const_double_operand" "n"))) + (compare (reg:ALL8 ACC_A) + (match_operand:ALL8 0 "const_operand" "n Ynn"))) (clobber (match_scratch:QI 1 "=&d"))] "avr_have_dimode && !s8_operand (operands[0], VOIDmode)" @@ -258,25 +319,41 @@ (define_code_iterator di_shifts ;; "ashrdi3" ;; "lshrdi3" ;; "rotldi3" -(define_expand "di3" - [(parallel [(match_operand:DI 0 "general_operand" "") - (di_shifts:DI (match_operand:DI 1 "general_operand" "") - (match_operand:QI 2 "general_operand" ""))])] +;; "ashldq3" "ashrdq3" "lshrdq3" "rotldq3" +;; "ashlda3" "ashrda3" "lshrda3" "rotlda3" +;; "ashlta3" "ashrta3" "lshrta3" "rotlta3" +;; "ashludq3" "ashrudq3" "lshrudq3" "rotludq3" +;; "ashluda3" "ashruda3" "lshruda3" "rotluda3" +;; "ashluta3" "ashruta3" "lshruta3" "rotluta3" +(define_expand "3" + [(parallel [(match_operand:ALL8 0 "general_operand" "") + (di_shifts:ALL8 (match_operand:ALL8 1 "general_operand" "") + (match_operand:QI 2 "general_operand" ""))])] "avr_have_dimode" { - rtx acc_a = gen_rtx_REG (DImode, ACC_A); + rtx acc_a = gen_rtx_REG (mode, ACC_A); emit_move_insn (acc_a, operands[1]); emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]); - emit_insn (gen_di3_insn ()); + emit_insn (gen_3_insn ()); emit_move_insn (operands[0], acc_a); DONE; }) -(define_insn "di3_insn" - [(set (reg:DI ACC_A) - (di_shifts:DI (reg:DI ACC_A) - (reg:QI 16)))] +;; "ashldi3_insn" +;; "ashrdi3_insn" +;; "lshrdi3_insn" +;; "rotldi3_insn" +;; "ashldq3_insn" "ashrdq3_insn" "lshrdq3_insn" "rotldq3_insn" +;; "ashlda3_insn" "ashrda3_insn" "lshrda3_insn" "rotlda3_insn" +;; "ashlta3_insn" "ashrta3_insn" "lshrta3_insn" "rotlta3_insn" +;; "ashludq3_insn" "ashrudq3_insn" "lshrudq3_insn" "rotludq3_insn" +;; "ashluda3_insn" "ashruda3_insn" "lshruda3_insn" "rotluda3_insn" +;; "ashluta3_insn" "ashruta3_insn" "lshruta3_insn" "rotluta3_insn" +(define_insn "3_insn" + [(set (reg:ALL8 ACC_A) + (di_shifts:ALL8 (reg:ALL8 ACC_A) + (reg:QI 16)))] "avr_have_dimode" "%~call __di3" [(set_attr "adjust_len" "call") Index: gcc/config/avr/avr.md =================================================================== --- gcc/config/avr/avr.md (revision 190299) +++ gcc/config/avr/avr.md (working copy) @@ -88,10 +88,10 @@ (define_c_enum "unspecv" (include "predicates.md") (include "constraints.md") - + ;; Condition code settings. (define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber, - out_plus, out_plus_noclobber,ldi" + out_plus, out_plus_noclobber,ldi,minus" (const_string "none")) (define_attr "type" "branch,branch1,arith,xcall" @@ -139,8 +139,10 @@ (define_attr "length" "" (define_attr "adjust_len" "out_bitop, out_plus, out_plus_noclobber, plus64, addto_sp, + minus, minus64, tsthi, tstpsi, tstsi, compare, compare64, call, mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32, + ufract, sfract, xload, movmem, load_lpm, ashlqi, ashrqi, lshrqi, ashlhi, ashrhi, lshrhi, @@ -225,8 +227,20 @@ (define_mode_iterator QISI [(QI "") (HI (define_mode_iterator QIDI [(QI "") (HI "") (PSI "") (SI "") (DI "")]) (define_mode_iterator HISI [(HI "") (PSI "") (SI "")]) +(define_mode_iterator ALL1 [(QI "") (QQ "") (UQQ "")]) +(define_mode_iterator ALL2 [(HI "") (HQ "") (UHQ "") (HA "") (UHA "")]) +(define_mode_iterator ALL4 [(SI "") (SQ "") (USQ "") (SA "") (USA "")]) + ;; All supported move-modes -(define_mode_iterator MOVMODE [(QI "") (HI "") (SI "") (SF "") (PSI "")]) +(define_mode_iterator MOVMODE [(QI "") (HI "") (SI "") (SF "") (PSI "") + (QQ "") (UQQ "") + (HQ "") (UHQ "") (HA "") (UHA "") + (SQ "") (USQ "") (SA "") (USA "")]) + +;; Supported ordered modes that are 2, 3, 4 bytes wide +(define_mode_iterator ORDERED234 [(HI "") (SI "") (PSI "") + (HQ "") (UHQ "") (HA "") (UHA "") + (SQ "") (USQ "") (SA "") (USA "")]) ;; Define code iterators ;; Define two incarnations so that we can build the cross product. @@ -317,9 +331,11 @@ (define_expand "nonlocal_goto" DONE; }) -(define_insn "pushqi1" - [(set (mem:QI (post_dec:HI (reg:HI REG_SP))) - (match_operand:QI 0 "reg_or_0_operand" "r,L"))] +;; "pushqi1" +;; "pushqq1" "pushuqq1" +(define_insn "push1" + [(set (mem:ALL1 (post_dec:HI (reg:HI REG_SP))) + (match_operand:ALL1 0 "reg_or_0_operand" "r,Y00"))] "" "@ push %0 @@ -334,7 +350,9 @@ (define_mode_iterator MPUSH (PSI "") (SI "") (CSI "") (DI "") (CDI "") - (SF "") (SC "")]) + (SF "") (SC "") + (HQ "") (UHQ "") (HA "") (UHA "") + (SQ "") (USQ "") (SA "") (USA "")]) (define_expand "push1" [(match_operand:MPUSH 0 "" "")] @@ -422,12 +440,14 @@ (define_insn "load__clobber" (set_attr "cc" "clobber")]) -(define_insn_and_split "xload8_A" - [(set (match_operand:QI 0 "register_operand" "=r") - (match_operand:QI 1 "memory_operand" "m")) +;; "xload8qi_A" +;; "xload8qq_A" "xload8uqq_A" +(define_insn_and_split "xload8_A" + [(set (match_operand:ALL1 0 "register_operand" "=r") + (match_operand:ALL1 1 "memory_operand" "m")) (clobber (reg:HI REG_Z))] "can_create_pseudo_p() - && !avr_xload_libgcc_p (QImode) + && !avr_xload_libgcc_p (mode) && avr_mem_memx_p (operands[1]) && REG_P (XEXP (operands[1], 0))" { gcc_unreachable(); } @@ -441,16 +461,16 @@ (define_insn_and_split "xload8_A" emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0)); emit_move_insn (hi8, simplify_gen_subreg (QImode, addr, PSImode, 2)); - insn = emit_insn (gen_xload_8 (operands[0], hi8)); + insn = emit_insn (gen_xload_8 (operands[0], hi8)); set_mem_addr_space (SET_SRC (single_set (insn)), MEM_ADDR_SPACE (operands[1])); DONE; }) -;; "xloadqi_A" -;; "xloadhi_A" +;; "xloadqi_A" "xloadqq_A" "xloaduqq_A" +;; "xloadhi_A" "xloadhq_A" "xloaduhq_A" "xloadha_A" "xloaduha_A" +;; "xloadsi_A" "xloadsq_A" "xloadusq_A" "xloadsa_A" "xloadusa_A" ;; "xloadpsi_A" -;; "xloadsi_A" ;; "xloadsf_A" (define_insn_and_split "xload_A" [(set (match_operand:MOVMODE 0 "register_operand" "=r") @@ -488,11 +508,13 @@ (define_insn_and_split "xload_A" ;; Move value from address space memx to a register ;; These insns must be prior to respective generic move insn. -(define_insn "xload_8" - [(set (match_operand:QI 0 "register_operand" "=&r,r") - (mem:QI (lo_sum:PSI (match_operand:QI 1 "register_operand" "r,r") - (reg:HI REG_Z))))] - "!avr_xload_libgcc_p (QImode)" +;; "xloadqi_8" +;; "xloadqq_8" "xloaduqq_8" +(define_insn "xload_8" + [(set (match_operand:ALL1 0 "register_operand" "=&r,r") + (mem:ALL1 (lo_sum:PSI (match_operand:QI 1 "register_operand" "r,r") + (reg:HI REG_Z))))] + "!avr_xload_libgcc_p (mode)" { return avr_out_xload (insn, operands, NULL); } @@ -504,11 +526,11 @@ (define_insn "xload_8" ;; R21:Z : 24-bit source address ;; R22 : 1-4 byte output -;; "xload_qi_libgcc" -;; "xload_hi_libgcc" -;; "xload_psi_libgcc" -;; "xload_si_libgcc" +;; "xload_qi_libgcc" "xload_qq_libgcc" "xload_uqq_libgcc" +;; "xload_hi_libgcc" "xload_hq_libgcc" "xload_uhq_libgcc" "xload_ha_libgcc" "xload_uha_libgcc" +;; "xload_si_libgcc" "xload_sq_libgcc" "xload_usq_libgcc" "xload_sa_libgcc" "xload_usa_libgcc" ;; "xload_sf_libgcc" +;; "xload_psi_libgcc" (define_insn "xload__libgcc" [(set (reg:MOVMODE 22) (mem:MOVMODE (lo_sum:PSI (reg:QI 21) @@ -528,9 +550,9 @@ (define_insn "xload__libgcc" ;; General move expanders -;; "movqi" -;; "movhi" -;; "movsi" +;; "movqi" "movqq" "movuqq" +;; "movhi" "movhq" "movuhq" "movha" "movuha" +;; "movsi" "movsq" "movusq" "movsa" "movusa" ;; "movsf" ;; "movpsi" (define_expand "mov" @@ -546,8 +568,7 @@ (define_expand "mov" /* One of the operands has to be in a register. */ if (!register_operand (dest, mode) - && !(register_operand (src, mode) - || src == CONST0_RTX (mode))) + && !reg_or_0_operand (src, mode)) { operands[1] = src = copy_to_mode_reg (mode, src); } @@ -560,7 +581,9 @@ (define_expand "mov" src = replace_equiv_address (src, copy_to_mode_reg (PSImode, addr)); if (!avr_xload_libgcc_p (mode)) - emit_insn (gen_xload8_A (dest, src)); + /* ; No here because gen_xload8_A only iterates over ALL1. + ; insn-emit does not depend on the mode, it' all about operands. */ + emit_insn (gen_xload8qi_A (dest, src)); else emit_insn (gen_xload_A (dest, src)); @@ -627,12 +650,13 @@ (define_expand "mov" ;; are call-saved registers, and most of LD_REGS are call-used registers, ;; so this may still be a win for registers live across function calls. -(define_insn "movqi_insn" - [(set (match_operand:QI 0 "nonimmediate_operand" "=r ,d,Qm,r ,q,r,*r") - (match_operand:QI 1 "nox_general_operand" "rL,i,rL,Qm,r,q,i"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode) - || const0_rtx == operands[1]" +;; "movqi_insn" +;; "movqq_insn" "movuqq_insn" +(define_insn "mov_insn" + [(set (match_operand:ALL1 0 "nonimmediate_operand" "=r ,d ,Qm ,r ,q,r,*r") + (match_operand:ALL1 1 "nox_general_operand" "r Y00,n Ynn,r Y00,Qm,r,q,i"))] + "register_operand (operands[0], mode) + || reg_or_0_operand (operands[1], mode)" { return output_movqi (insn, operands, NULL); } @@ -643,9 +667,11 @@ (define_insn "movqi_insn" ;; This is used in peephole2 to optimize loading immediate constants ;; if a scratch register from LD_REGS happens to be available. -(define_insn "*reload_inqi" - [(set (match_operand:QI 0 "register_operand" "=l") - (match_operand:QI 1 "immediate_operand" "i")) +;; "*reload_inqi" +;; "*reload_inqq" "*reload_inuqq" +(define_insn "*reload_in" + [(set (match_operand:ALL1 0 "register_operand" "=l") + (match_operand:ALL1 1 "const_operand" "i")) (clobber (match_operand:QI 2 "register_operand" "=&d"))] "reload_completed" "ldi %2,lo8(%1) @@ -655,14 +681,15 @@ (define_insn "*reload_inqi" (define_peephole2 [(match_scratch:QI 2 "d") - (set (match_operand:QI 0 "l_register_operand" "") - (match_operand:QI 1 "immediate_operand" ""))] - "(operands[1] != const0_rtx - && operands[1] != const1_rtx - && operands[1] != constm1_rtx)" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (match_dup 2))])] - "") + (set (match_operand:ALL1 0 "l_register_operand" "") + (match_operand:ALL1 1 "const_operand" ""))] + ; No need for a clobber reg for 0x0, 0x01 or 0xff + "!satisfies_constraint_Y00 (operands[1]) + && !satisfies_constraint_Y01 (operands[1]) + && !satisfies_constraint_Ym1 (operands[1])" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (clobber (match_dup 2))])]) ;;============================================================================ ;; move word (16 bit) @@ -693,18 +720,20 @@ (define_insn "movhi_sp_r" (define_peephole2 [(match_scratch:QI 2 "d") - (set (match_operand:HI 0 "l_register_operand" "") - (match_operand:HI 1 "immediate_operand" ""))] - "(operands[1] != const0_rtx - && operands[1] != constm1_rtx)" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (match_dup 2))])] - "") + (set (match_operand:ALL2 0 "l_register_operand" "") + (match_operand:ALL2 1 "const_or_immediate_operand" ""))] + "operands[1] != CONST0_RTX (mode)" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (clobber (match_dup 2))])]) ;; '*' because it is not used in rtl generation, only in above peephole -(define_insn "*reload_inhi" - [(set (match_operand:HI 0 "register_operand" "=r") - (match_operand:HI 1 "immediate_operand" "i")) +;; "*reload_inhi" +;; "*reload_inhq" "*reload_inuhq" +;; "*reload_inha" "*reload_inuha" +(define_insn "*reload_in" + [(set (match_operand:ALL2 0 "l_register_operand" "=l") + (match_operand:ALL2 1 "immediate_operand" "i")) (clobber (match_operand:QI 2 "register_operand" "=&d"))] "reload_completed" { @@ -712,14 +741,16 @@ (define_insn "*reload_inhi" } [(set_attr "length" "4") (set_attr "adjust_len" "reload_in16") - (set_attr "cc" "none")]) + (set_attr "cc" "clobber")]) -(define_insn "*movhi" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m ,d,*r,q,r") - (match_operand:HI 1 "nox_general_operand" "r,L,m,rL,i,i ,r,q"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode) - || const0_rtx == operands[1]" +;; "*movhi" +;; "*movhq" "*movuhq" +;; "*movha" "*movuha" +(define_insn "*mov" + [(set (match_operand:ALL2 0 "nonimmediate_operand" "=r,r ,r,m ,d,*r,q,r") + (match_operand:ALL2 1 "nox_general_operand" "r,Y00,m,r Y00,i,i ,r,q"))] + "register_operand (operands[0], mode) + || reg_or_0_operand (operands[1], mode)" { return output_movhi (insn, operands, NULL); } @@ -728,28 +759,30 @@ (define_insn "*movhi" (set_attr "cc" "none,none,clobber,clobber,none,clobber,none,none")]) (define_peephole2 ; movw - [(set (match_operand:QI 0 "even_register_operand" "") - (match_operand:QI 1 "even_register_operand" "")) - (set (match_operand:QI 2 "odd_register_operand" "") - (match_operand:QI 3 "odd_register_operand" ""))] + [(set (match_operand:ALL1 0 "even_register_operand" "") + (match_operand:ALL1 1 "even_register_operand" "")) + (set (match_operand:ALL1 2 "odd_register_operand" "") + (match_operand:ALL1 3 "odd_register_operand" ""))] "(AVR_HAVE_MOVW && REGNO (operands[0]) == REGNO (operands[2]) - 1 && REGNO (operands[1]) == REGNO (operands[3]) - 1)" - [(set (match_dup 4) (match_dup 5))] + [(set (match_dup 4) + (match_dup 5))] { operands[4] = gen_rtx_REG (HImode, REGNO (operands[0])); operands[5] = gen_rtx_REG (HImode, REGNO (operands[1])); }) (define_peephole2 ; movw_r - [(set (match_operand:QI 0 "odd_register_operand" "") - (match_operand:QI 1 "odd_register_operand" "")) - (set (match_operand:QI 2 "even_register_operand" "") - (match_operand:QI 3 "even_register_operand" ""))] + [(set (match_operand:ALL1 0 "odd_register_operand" "") + (match_operand:ALL1 1 "odd_register_operand" "")) + (set (match_operand:ALL1 2 "even_register_operand" "") + (match_operand:ALL1 3 "even_register_operand" ""))] "(AVR_HAVE_MOVW && REGNO (operands[2]) == REGNO (operands[0]) - 1 && REGNO (operands[3]) == REGNO (operands[1]) - 1)" - [(set (match_dup 4) (match_dup 5))] + [(set (match_dup 4) + (match_dup 5))] { operands[4] = gen_rtx_REG (HImode, REGNO (operands[2])); operands[5] = gen_rtx_REG (HImode, REGNO (operands[3])); @@ -801,19 +834,21 @@ (define_insn "*movpsi" (define_peephole2 ; *reload_insi [(match_scratch:QI 2 "d") - (set (match_operand:SI 0 "l_register_operand" "") - (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:ALL4 0 "l_register_operand" "") + (match_operand:ALL4 1 "immediate_operand" "")) (match_dup 2)] - "(operands[1] != const0_rtx - && operands[1] != constm1_rtx)" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (match_dup 2))])] - "") + "operands[1] != CONST0_RTX (mode)" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (clobber (match_dup 2))])]) ;; '*' because it is not used in rtl generation. +;; "*reload_insi" +;; "*reload_insq" "*reload_inusq" +;; "*reload_insa" "*reload_inusa" (define_insn "*reload_insi" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operand:SI 1 "const_int_operand" "n")) + [(set (match_operand:ALL4 0 "register_operand" "=r") + (match_operand:ALL4 1 "immediate_operand" "n Ynn")) (clobber (match_operand:QI 2 "register_operand" "=&d"))] "reload_completed" { @@ -824,12 +859,14 @@ (define_insn "*reload_insi" (set_attr "cc" "clobber")]) -(define_insn "*movsi" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r") - (match_operand:SI 1 "nox_general_operand" "r,L,Qm,rL,i ,i"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode) - || const0_rtx == operands[1]" +;; "*movsi" +;; "*movsq" "*movusq" +;; "*movsa" "*movusa" +(define_insn "*mov" + [(set (match_operand:ALL4 0 "nonimmediate_operand" "=r,r ,r ,Qm ,!d,r") + (match_operand:ALL4 1 "nox_general_operand" "r,Y00,Qm,r Y00,i ,i"))] + "register_operand (operands[0], mode) + || reg_or_0_operand (operands[1], mode)" { return output_movsisf (insn, operands, NULL); } @@ -844,8 +881,7 @@ (define_insn "*movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r") (match_operand:SF 1 "nox_general_operand" "r,G,Qm,rG,F ,F"))] "register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode) - || operands[1] == CONST0_RTX (SFmode)" + || reg_or_0_operand (operands[1], SFmode)" { return output_movsisf (insn, operands, NULL); } @@ -861,8 +897,7 @@ (define_peephole2 ; *reload_insf "operands[1] != CONST0_RTX (SFmode)" [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (match_dup 2))])] - "") + (clobber (match_dup 2))])]) ;; '*' because it is not used in rtl generation. (define_insn "*reload_insf" @@ -1015,9 +1050,10 @@ (define_expand "strlenhi" (set (match_dup 4) (plus:HI (match_dup 4) (const_int -1))) - (set (match_operand:HI 0 "register_operand" "") - (minus:HI (match_dup 4) - (match_dup 5)))] + (parallel [(set (match_operand:HI 0 "register_operand" "") + (minus:HI (match_dup 4) + (match_dup 5))) + (clobber (scratch:QI))])] "" { rtx addr; @@ -1043,10 +1079,12 @@ (define_insn "*strlenhi" ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; add bytes -(define_insn "addqi3" - [(set (match_operand:QI 0 "register_operand" "=r,d,r,r,r,r") - (plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,0") - (match_operand:QI 2 "nonmemory_operand" "r,i,P,N,K,Cm2")))] +;; "addqi3" +;; "addqq3" "adduqq3" +(define_insn "add3" + [(set (match_operand:ALL1 0 "register_operand" "=r,d ,r ,r ,r ,r") + (plus:ALL1 (match_operand:ALL1 1 "register_operand" "%0,0 ,0 ,0 ,0 ,0") + (match_operand:ALL1 2 "nonmemory_operand" "r,n Ynn,Y01,Ym1,Y02,Ym2")))] "" "@ add %0,%2 @@ -1058,11 +1096,13 @@ (define_insn "addqi3" [(set_attr "length" "1,1,1,1,2,2") (set_attr "cc" "set_czn,set_czn,set_zn,set_zn,set_zn,set_zn")]) - -(define_expand "addhi3" - [(set (match_operand:HI 0 "register_operand" "") - (plus:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "nonmemory_operand" "")))] +;; "addhi3" +;; "addhq3" "adduhq3" +;; "addha3" "adduha3" +(define_expand "add3" + [(set (match_operand:ALL2 0 "register_operand" "") + (plus:ALL2 (match_operand:ALL2 1 "register_operand" "") + (match_operand:ALL2 2 "nonmemory_or_const_operand" "")))] "" { if (CONST_INT_P (operands[2])) @@ -1079,6 +1119,12 @@ (define_expand "addhi3" DONE; } } + + if (CONST_FIXED == GET_CODE (operands[2])) + { + emit_insn (gen_add3_clobber (operands[0], operands[1], operands[2])); + DONE; + } }) @@ -1124,24 +1170,22 @@ (define_insn "*addhi3_sp" [(set_attr "length" "6") (set_attr "adjust_len" "addto_sp")]) -(define_insn "*addhi3" - [(set (match_operand:HI 0 "register_operand" "=r,d,!w,d") - (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0 ,0") - (match_operand:HI 2 "nonmemory_operand" "r,s,IJ,n")))] +;; "*addhi3" +;; "*addhq3" "*adduhq3" +;; "*addha3" "*adduha3" +(define_insn "*add3" + [(set (match_operand:ALL2 0 "register_operand" "=r,d,!w ,d") + (plus:ALL2 (match_operand:ALL2 1 "register_operand" "%0,0,0 ,0") + (match_operand:ALL2 2 "nonmemory_or_const_operand" "r,s,IJ YIJ,n Ynn")))] "" { - static const char * const asm_code[] = - { - "add %A0,%A2\;adc %B0,%B2", - "subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))", - "", - "" - }; - - if (*asm_code[which_alternative]) - return asm_code[which_alternative]; - - return avr_out_plus_noclobber (operands, NULL, NULL); + if (REG_P (operands[2])) + return "add %A0,%A2\;adc %B0,%B2"; + else if (CONST_INT_P (operands[2]) + || CONST_FIXED == GET_CODE (operands[2])) + return avr_out_plus_noclobber (operands, NULL, NULL); + else + return "subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))"; } [(set_attr "length" "2,2,2,2") (set_attr "adjust_len" "*,*,out_plus_noclobber,out_plus_noclobber") @@ -1152,41 +1196,44 @@ (define_insn "*addhi3" ;; itself because that insn is special to reload. (define_peephole2 ; addhi3_clobber - [(set (match_operand:HI 0 "d_register_operand" "") - (match_operand:HI 1 "const_int_operand" "")) - (set (match_operand:HI 2 "l_register_operand" "") - (plus:HI (match_dup 2) - (match_dup 0)))] + [(set (match_operand:ALL2 0 "d_register_operand" "") + (match_operand:ALL2 1 "const_operand" "")) + (set (match_operand:ALL2 2 "l_register_operand" "") + (plus:ALL2 (match_dup 2) + (match_dup 0)))] "peep2_reg_dead_p (2, operands[0])" [(parallel [(set (match_dup 2) - (plus:HI (match_dup 2) - (match_dup 1))) + (plus:ALL2 (match_dup 2) + (match_dup 1))) (clobber (match_dup 3))])] { - operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0); + operands[3] = simplify_gen_subreg (QImode, operands[0], mode, 0); }) ;; Same, but with reload to NO_LD_REGS ;; Combine *reload_inhi with *addhi3 (define_peephole2 ; addhi3_clobber - [(parallel [(set (match_operand:HI 0 "l_register_operand" "") - (match_operand:HI 1 "const_int_operand" "")) + [(parallel [(set (match_operand:ALL2 0 "l_register_operand" "") + (match_operand:ALL2 1 "const_operand" "")) (clobber (match_operand:QI 2 "d_register_operand" ""))]) - (set (match_operand:HI 3 "l_register_operand" "") - (plus:HI (match_dup 3) - (match_dup 0)))] + (set (match_operand:ALL2 3 "l_register_operand" "") + (plus:ALL2 (match_dup 3) + (match_dup 0)))] "peep2_reg_dead_p (2, operands[0])" [(parallel [(set (match_dup 3) - (plus:HI (match_dup 3) - (match_dup 1))) + (plus:ALL2 (match_dup 3) + (match_dup 1))) (clobber (match_dup 2))])]) -(define_insn "addhi3_clobber" - [(set (match_operand:HI 0 "register_operand" "=!w,d,r") - (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0") - (match_operand:HI 2 "const_int_operand" "IJ,n,n"))) - (clobber (match_scratch:QI 3 "=X,X,&d"))] +;; "addhi3_clobber" +;; "addhq3_clobber" "adduhq3_clobber" +;; "addha3_clobber" "adduha3_clobber" +(define_insn "add3_clobber" + [(set (match_operand:ALL2 0 "register_operand" "=!w ,d ,r") + (plus:ALL2 (match_operand:ALL2 1 "register_operand" "%0 ,0 ,0") + (match_operand:ALL2 2 "const_operand" "IJ YIJ,n Ynn,n Ynn"))) + (clobber (match_scratch:QI 3 "=X ,X ,&d"))] "" { gcc_assert (REGNO (operands[0]) == REGNO (operands[1])); @@ -1198,29 +1245,24 @@ (define_insn "addhi3_clobber" (set_attr "cc" "out_plus")]) -(define_insn "addsi3" - [(set (match_operand:SI 0 "register_operand" "=r,d ,d,r") - (plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0,0") - (match_operand:SI 2 "nonmemory_operand" "r,s ,n,n"))) - (clobber (match_scratch:QI 3 "=X,X ,X,&d"))] +;; "addsi3" +;; "addsq3" "addusq3" +;; "addsa3" "addusa3" +(define_insn "add3" + [(set (match_operand:ALL4 0 "register_operand" "=r,d ,r") + (plus:ALL4 (match_operand:ALL4 1 "register_operand" "%0,0 ,0") + (match_operand:ALL4 2 "nonmemory_operand" "r,i ,n Ynn"))) + (clobber (match_scratch:QI 3 "=X,X ,&d"))] "" { - static const char * const asm_code[] = - { - "add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2", - "subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))", - "", - "" - }; - - if (*asm_code[which_alternative]) - return asm_code[which_alternative]; + if (REG_P (operands[2])) + return "add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2"; return avr_out_plus (operands, NULL, NULL); } - [(set_attr "length" "4,4,4,8") - (set_attr "adjust_len" "*,*,out_plus,out_plus") - (set_attr "cc" "set_n,set_czn,out_plus,out_plus")]) + [(set_attr "length" "4,4,8") + (set_attr "adjust_len" "*,out_plus,out_plus") + (set_attr "cc" "set_n,out_plus,out_plus")]) (define_insn "*addpsi3_zero_extend.qi" [(set (match_operand:PSI 0 "register_operand" "=r") @@ -1329,27 +1371,38 @@ (define_insn "*subpsi3_sign_extend.hi" ;----------------------------------------------------------------------------- ; sub bytes -(define_insn "subqi3" - [(set (match_operand:QI 0 "register_operand" "=r,d") - (minus:QI (match_operand:QI 1 "register_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "r,i")))] + +;; "subqi3" +;; "subqq3" "subuqq3" +(define_insn "sub3" + [(set (match_operand:ALL1 0 "register_operand" "=r,d ,r ,r ,r ,r") + (minus:ALL1 (match_operand:ALL1 1 "register_operand" "0,0 ,0 ,0 ,0 ,0") + (match_operand:ALL1 2 "nonmemory_or_const_operand" "r,n Ynn,Y01,Ym1,Y02,Ym2")))] "" "@ sub %0,%2 - subi %0,lo8(%2)" - [(set_attr "length" "1,1") - (set_attr "cc" "set_czn,set_czn")]) + subi %0,lo8(%2) + dec %0 + inc %0 + dec %0\;dec %0 + inc %0\;inc %0" + [(set_attr "length" "1,1,1,1,2,2") + (set_attr "cc" "set_czn,set_czn,set_zn,set_zn,set_zn,set_zn")]) -(define_insn "subhi3" - [(set (match_operand:HI 0 "register_operand" "=r,d") - (minus:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "nonmemory_operand" "r,i")))] +;; "subhi3" +;; "subhq3" "subuhq3" +;; "subha3" "subuha3" +(define_insn "sub3" + [(set (match_operand:ALL2 0 "register_operand" "=r,d ,*r") + (minus:ALL2 (match_operand:ALL2 1 "register_operand" "0,0 ,0") + (match_operand:ALL2 2 "nonmemory_or_const_operand" "r,i Ynn,Ynn"))) + (clobber (match_scratch:QI 3 "=X,X ,&d"))] "" - "@ - sub %A0,%A2\;sbc %B0,%B2 - subi %A0,lo8(%2)\;sbci %B0,hi8(%2)" - [(set_attr "length" "2,2") - (set_attr "cc" "set_czn,set_czn")]) + { + return avr_out_minus (operands, NULL, NULL); + } + [(set_attr "adjust_len" "minus") + (set_attr "cc" "minus")]) (define_insn "*subhi3_zero_extend1" [(set (match_operand:HI 0 "register_operand" "=r") @@ -1373,13 +1426,23 @@ (define_insn "*subhi3.sign_extend2" [(set_attr "length" "5") (set_attr "cc" "clobber")]) -(define_insn "subsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "register_operand" "r")))] +;; "subsi3" +;; "subsq3" "subusq3" +;; "subsa3" "subusa3" +(define_insn "sub3" + [(set (match_operand:ALL4 0 "register_operand" "=r,d ,r") + (minus:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,0") + (match_operand:ALL4 2 "nonmemory_or_const_operand" "r,n Ynn,Ynn"))) + (clobber (match_scratch:QI 3 "=X,X ,&d"))] "" - "sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2" + { + if (REG_P (operands[2])) + return "sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2"; + + return avr_out_minus (operands, NULL, NULL); + } [(set_attr "length" "4") + (set_attr "adjust_len" "*,minus,minus") (set_attr "cc" "set_czn")]) (define_insn "*subsi3_zero_extend" @@ -3303,44 +3366,58 @@ (define_insn_and_split "*rotb" ;;<< << << << << << << << << << << << << << << << << << << << << << << << << << ;; arithmetic shift left -(define_expand "ashlqi3" - [(set (match_operand:QI 0 "register_operand" "") - (ashift:QI (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "nop_general_operand" "")))]) +;; "ashlqi3" +;; "ashlqq3" "ashluqq3" +(define_expand "ashl3" + [(set (match_operand:ALL1 0 "register_operand" "") + (ashift:ALL1 (match_operand:ALL1 1 "register_operand" "") + (match_operand:QI 2 "nop_general_operand" "")))]) (define_split ; ashlqi3_const4 - [(set (match_operand:QI 0 "d_register_operand" "") - (ashift:QI (match_dup 0) - (const_int 4)))] + [(set (match_operand:ALL1 0 "d_register_operand" "") + (ashift:ALL1 (match_dup 0) + (const_int 4)))] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (and:QI (match_dup 0) (const_int -16)))] - "") + [(set (match_dup 1) + (rotate:QI (match_dup 1) + (const_int 4))) + (set (match_dup 1) + (and:QI (match_dup 1) + (const_int -16)))] + { + operands[1] = avr_to_int_mode (operands[0]); + }) (define_split ; ashlqi3_const5 - [(set (match_operand:QI 0 "d_register_operand" "") - (ashift:QI (match_dup 0) - (const_int 5)))] + [(set (match_operand:ALL1 0 "d_register_operand" "") + (ashift:ALL1 (match_dup 0) + (const_int 5)))] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1))) - (set (match_dup 0) (and:QI (match_dup 0) (const_int -32)))] - "") + [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4))) + (set (match_dup 1) (ashift:QI (match_dup 1) (const_int 1))) + (set (match_dup 1) (and:QI (match_dup 1) (const_int -32)))] + { + operands[1] = avr_to_int_mode (operands[0]); + }) (define_split ; ashlqi3_const6 - [(set (match_operand:QI 0 "d_register_operand" "") - (ashift:QI (match_dup 0) - (const_int 6)))] + [(set (match_operand:ALL1 0 "d_register_operand" "") + (ashift:ALL1 (match_dup 0) + (const_int 6)))] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2))) - (set (match_dup 0) (and:QI (match_dup 0) (const_int -64)))] - "") + [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4))) + (set (match_dup 1) (ashift:QI (match_dup 1) (const_int 2))) + (set (match_dup 1) (and:QI (match_dup 1) (const_int -64)))] + { + operands[1] = avr_to_int_mode (operands[0]); + }) -(define_insn "*ashlqi3" - [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r") - (ashift:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0 ,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))] +;; "*ashlqi3" +;; "*ashlqq3" "*ashluqq3" +(define_insn "*ashl3" + [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,!d,r,r") + (ashift:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))] "" { return ashlqi3_out (insn, operands, NULL); @@ -3349,10 +3426,10 @@ (define_insn "*ashlqi3" (set_attr "adjust_len" "ashlqi") (set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")]) -(define_insn "ashlhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r") - (ashift:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] +(define_insn "ashl3" + [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r") + (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] "" { return ashlhi3_out (insn, operands, NULL); @@ -3377,8 +3454,7 @@ (define_insn_and_split "*ashl "" [(set (match_dup 0) (ashift:QI (match_dup 1) - (match_dup 2)))] - "") + (match_dup 2)))]) ;; ??? Combiner does not recognize that it could split the following insn; ;; presumably because he has no register handy? @@ -3443,10 +3519,13 @@ (define_peephole2 }) -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") - (ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] +;; "ashlsi3" +;; "ashlsq3" "ashlusq3" +;; "ashlsa3" "ashlusa3" +(define_insn "ashl3" + [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r") + (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] "" { return ashlsi3_out (insn, operands, NULL); @@ -3458,55 +3537,65 @@ (define_insn "ashlsi3" ;; Optimize if a scratch register from LD_REGS happens to be available. (define_peephole2 ; ashlqi3_l_const4 - [(set (match_operand:QI 0 "l_register_operand" "") - (ashift:QI (match_dup 0) - (const_int 4))) + [(set (match_operand:ALL1 0 "l_register_operand" "") + (ashift:ALL1 (match_dup 0) + (const_int 4))) (match_scratch:QI 1 "d")] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) + [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4))) (set (match_dup 1) (const_int -16)) - (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] - "") + (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))] + { + operands[2] = avr_to_int_mode (operands[0]); + }) (define_peephole2 ; ashlqi3_l_const5 - [(set (match_operand:QI 0 "l_register_operand" "") - (ashift:QI (match_dup 0) - (const_int 5))) + [(set (match_operand:ALL1 0 "l_register_operand" "") + (ashift:ALL1 (match_dup 0) + (const_int 5))) (match_scratch:QI 1 "d")] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1))) + [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4))) + (set (match_dup 2) (ashift:QI (match_dup 2) (const_int 1))) (set (match_dup 1) (const_int -32)) - (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] - "") + (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))] + { + operands[2] = avr_to_int_mode (operands[0]); + }) (define_peephole2 ; ashlqi3_l_const6 - [(set (match_operand:QI 0 "l_register_operand" "") - (ashift:QI (match_dup 0) - (const_int 6))) + [(set (match_operand:ALL1 0 "l_register_operand" "") + (ashift:ALL1 (match_dup 0) + (const_int 6))) (match_scratch:QI 1 "d")] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2))) + [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4))) + (set (match_dup 2) (ashift:QI (match_dup 2) (const_int 2))) (set (match_dup 1) (const_int -64)) - (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] - "") + (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))] + { + operands[2] = avr_to_int_mode (operands[0]); + }) (define_peephole2 [(match_scratch:QI 3 "d") - (set (match_operand:HI 0 "register_operand" "") - (ashift:HI (match_operand:HI 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" "")))] + (set (match_operand:ALL2 0 "register_operand" "") + (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] "" - [(parallel [(set (match_dup 0) (ashift:HI (match_dup 1) (match_dup 2))) - (clobber (match_dup 3))])] - "") - -(define_insn "*ashlhi3_const" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r") - (ashift:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0") - (match_operand:QI 2 "const_int_operand" "L,P,O,K,n"))) - (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))] + [(parallel [(set (match_dup 0) + (ashift:ALL2 (match_dup 1) + (match_dup 2))) + (clobber (match_dup 3))])]) + +;; "*ashlhi3_const" +;; "*ashlhq3_const" "*ashluhq3_const" +;; "*ashlha3_const" "*ashluha3_const" +(define_insn "*ashl3_const" + [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r") + (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0") + (match_operand:QI 2 "const_int_operand" "L,P,O,K,n"))) + (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))] "reload_completed" { return ashlhi3_out (insn, operands, NULL); @@ -3517,19 +3606,24 @@ (define_insn "*ashlhi3_const" (define_peephole2 [(match_scratch:QI 3 "d") - (set (match_operand:SI 0 "register_operand" "") - (ashift:SI (match_operand:SI 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" "")))] + (set (match_operand:ALL4 0 "register_operand" "") + (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] "" - [(parallel [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2))) + [(parallel [(set (match_dup 0) + (ashift:ALL4 (match_dup 1) + (match_dup 2))) (clobber (match_dup 3))])] "") -(define_insn "*ashlsi3_const" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") - (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r,0") - (match_operand:QI 2 "const_int_operand" "L,P,O,n"))) - (clobber (match_scratch:QI 3 "=X,X,X,&d"))] +;; "*ashlsi3_const" +;; "*ashlsq3_const" "*ashlusq3_const" +;; "*ashlsa3_const" "*ashlusa3_const" +(define_insn "*ashl3_const" + [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r") + (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0") + (match_operand:QI 2 "const_int_operand" "L,P,O,n"))) + (clobber (match_scratch:QI 3 "=X,X,X,&d"))] "reload_completed" { return ashlsi3_out (insn, operands, NULL); @@ -3580,10 +3674,12 @@ (define_insn "*ashlpsi3" ;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ;; arithmetic shift right -(define_insn "ashrqi3" - [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r ,r ,r") - (ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0 ,0 ,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,K,C03 C04 C05,C06 C07,Qm")))] +;; "ashrqi3" +;; "ashrqq3" "ashruqq3" +(define_insn "ashr3" + [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,r ,r ,r") + (ashiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0 ,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,K,C03 C04 C05,C06 C07,Qm")))] "" { return ashrqi3_out (insn, operands, NULL); @@ -3592,10 +3688,13 @@ (define_insn "ashrqi3" (set_attr "adjust_len" "ashrqi") (set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,clobber,clobber")]) -(define_insn "ashrhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] +;; "ashrhi3" +;; "ashrhq3" "ashruhq3" +;; "ashrha3" "ashruha3" +(define_insn "ashr3" + [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r") + (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] "" { return ashrhi3_out (insn, operands, NULL); @@ -3616,10 +3715,13 @@ (define_insn "ashrpsi3" [(set_attr "adjust_len" "ashrpsi") (set_attr "cc" "clobber")]) -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] +;; "ashrsi3" +;; "ashrsq3" "ashrusq3" +;; "ashrsa3" "ashrusa3" +(define_insn "ashr3" + [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r") + (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] "" { return ashrsi3_out (insn, operands, NULL); @@ -3632,19 +3734,23 @@ (define_insn "ashrsi3" (define_peephole2 [(match_scratch:QI 3 "d") - (set (match_operand:HI 0 "register_operand" "") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" "")))] + (set (match_operand:ALL2 0 "register_operand" "") + (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] "" - [(parallel [(set (match_dup 0) (ashiftrt:HI (match_dup 1) (match_dup 2))) - (clobber (match_dup 3))])] - "") - -(define_insn "*ashrhi3_const" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0") - (match_operand:QI 2 "const_int_operand" "L,P,O,K,n"))) - (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))] + [(parallel [(set (match_dup 0) + (ashiftrt:ALL2 (match_dup 1) + (match_dup 2))) + (clobber (match_dup 3))])]) + +;; "*ashrhi3_const" +;; "*ashrhq3_const" "*ashruhq3_const" +;; "*ashrha3_const" "*ashruha3_const" +(define_insn "*ashr3_const" + [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r") + (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0") + (match_operand:QI 2 "const_int_operand" "L,P,O,K,n"))) + (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))] "reload_completed" { return ashrhi3_out (insn, operands, NULL); @@ -3655,19 +3761,23 @@ (define_insn "*ashrhi3_const" (define_peephole2 [(match_scratch:QI 3 "d") - (set (match_operand:SI 0 "register_operand" "") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" "")))] + (set (match_operand:ALL4 0 "register_operand" "") + (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] "" - [(parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 1) (match_dup 2))) - (clobber (match_dup 3))])] - "") - -(define_insn "*ashrsi3_const" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0") - (match_operand:QI 2 "const_int_operand" "L,P,O,n"))) - (clobber (match_scratch:QI 3 "=X,X,X,&d"))] + [(parallel [(set (match_dup 0) + (ashiftrt:ALL4 (match_dup 1) + (match_dup 2))) + (clobber (match_dup 3))])]) + +;; "*ashrsi3_const" +;; "*ashrsq3_const" "*ashrusq3_const" +;; "*ashrsa3_const" "*ashrusa3_const" +(define_insn "*ashr3_const" + [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r") + (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0") + (match_operand:QI 2 "const_int_operand" "L,P,O,n"))) + (clobber (match_scratch:QI 3 "=X,X,X,&d"))] "reload_completed" { return ashrsi3_out (insn, operands, NULL); @@ -3679,44 +3789,59 @@ (define_insn "*ashrsi3_const" ;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ;; logical shift right -(define_expand "lshrqi3" - [(set (match_operand:QI 0 "register_operand" "") - (lshiftrt:QI (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "nop_general_operand" "")))]) +;; "lshrqi3" +;; "lshrqq3 "lshruqq3" +(define_expand "lshr3" + [(set (match_operand:ALL1 0 "register_operand" "") + (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "") + (match_operand:QI 2 "nop_general_operand" "")))]) (define_split ; lshrqi3_const4 - [(set (match_operand:QI 0 "d_register_operand" "") - (lshiftrt:QI (match_dup 0) - (const_int 4)))] + [(set (match_operand:ALL1 0 "d_register_operand" "") + (lshiftrt:ALL1 (match_dup 0) + (const_int 4)))] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (and:QI (match_dup 0) (const_int 15)))] - "") + [(set (match_dup 1) + (rotate:QI (match_dup 1) + (const_int 4))) + (set (match_dup 1) + (and:QI (match_dup 1) + (const_int 15)))] + { + operands[1] = avr_to_int_mode (operands[0]); + }) (define_split ; lshrqi3_const5 - [(set (match_operand:QI 0 "d_register_operand" "") - (lshiftrt:QI (match_dup 0) - (const_int 5)))] - "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1))) - (set (match_dup 0) (and:QI (match_dup 0) (const_int 7)))] - "") + [(set (match_operand:ALL1 0 "d_register_operand" "") + (lshiftrt:ALL1 (match_dup 0) + (const_int 5)))] + "" + [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4))) + (set (match_dup 1) (lshiftrt:QI (match_dup 1) (const_int 1))) + (set (match_dup 1) (and:QI (match_dup 1) (const_int 7)))] + { + operands[1] = avr_to_int_mode (operands[0]); + }) (define_split ; lshrqi3_const6 [(set (match_operand:QI 0 "d_register_operand" "") (lshiftrt:QI (match_dup 0) (const_int 6)))] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2))) - (set (match_dup 0) (and:QI (match_dup 0) (const_int 3)))] - "") + [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4))) + (set (match_dup 1) (lshiftrt:QI (match_dup 1) (const_int 2))) + (set (match_dup 1) (and:QI (match_dup 1) (const_int 3)))] + { + operands[1] = avr_to_int_mode (operands[0]); + }) -(define_insn "*lshrqi3" - [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r") - (lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0 ,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))] +;; "*lshrqi3" +;; "*lshrqq3" +;; "*lshruqq3" +(define_insn "*lshr3" + [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,!d,r,r") + (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))] "" { return lshrqi3_out (insn, operands, NULL); @@ -3725,10 +3850,13 @@ (define_insn "*lshrqi3" (set_attr "adjust_len" "lshrqi") (set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")]) -(define_insn "lshrhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r") - (lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] +;; "lshrhi3" +;; "lshrhq3" "lshruhq3" +;; "lshrha3" "lshruha3" +(define_insn "lshr3" + [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r") + (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] "" { return lshrhi3_out (insn, operands, NULL); @@ -3749,10 +3877,13 @@ (define_insn "lshrpsi3" [(set_attr "adjust_len" "lshrpsi") (set_attr "cc" "clobber")]) -(define_insn "lshrsi3" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0") - (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] +;; "lshrsi3" +;; "lshrsq3" "lshrusq3" +;; "lshrsa3" "lshrusa3" +(define_insn "lshr3" + [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r") + (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0") + (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))] "" { return lshrsi3_out (insn, operands, NULL); @@ -3764,55 +3895,65 @@ (define_insn "lshrsi3" ;; Optimize if a scratch register from LD_REGS happens to be available. (define_peephole2 ; lshrqi3_l_const4 - [(set (match_operand:QI 0 "l_register_operand" "") - (lshiftrt:QI (match_dup 0) - (const_int 4))) + [(set (match_operand:ALL1 0 "l_register_operand" "") + (lshiftrt:ALL1 (match_dup 0) + (const_int 4))) (match_scratch:QI 1 "d")] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) + [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4))) (set (match_dup 1) (const_int 15)) - (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] - "") + (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))] + { + operands[2] = avr_to_int_mode (operands[0]); + }) (define_peephole2 ; lshrqi3_l_const5 - [(set (match_operand:QI 0 "l_register_operand" "") - (lshiftrt:QI (match_dup 0) - (const_int 5))) + [(set (match_operand:ALL1 0 "l_register_operand" "") + (lshiftrt:ALL1 (match_dup 0) + (const_int 5))) (match_scratch:QI 1 "d")] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1))) + [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4))) + (set (match_dup 2) (lshiftrt:QI (match_dup 2) (const_int 1))) (set (match_dup 1) (const_int 7)) - (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] - "") + (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))] + { + operands[2] = avr_to_int_mode (operands[0]); + }) (define_peephole2 ; lshrqi3_l_const6 - [(set (match_operand:QI 0 "l_register_operand" "") - (lshiftrt:QI (match_dup 0) - (const_int 6))) + [(set (match_operand:ALL1 0 "l_register_operand" "") + (lshiftrt:ALL1 (match_dup 0) + (const_int 6))) (match_scratch:QI 1 "d")] "" - [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4))) - (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2))) + [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4))) + (set (match_dup 2) (lshiftrt:QI (match_dup 2) (const_int 2))) (set (match_dup 1) (const_int 3)) - (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] - "") + (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))] + { + operands[2] = avr_to_int_mode (operands[0]); + }) (define_peephole2 [(match_scratch:QI 3 "d") - (set (match_operand:HI 0 "register_operand" "") - (lshiftrt:HI (match_operand:HI 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" "")))] + (set (match_operand:ALL2 0 "register_operand" "") + (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] "" - [(parallel [(set (match_dup 0) (lshiftrt:HI (match_dup 1) (match_dup 2))) - (clobber (match_dup 3))])] - "") - -(define_insn "*lshrhi3_const" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r") - (lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0") - (match_operand:QI 2 "const_int_operand" "L,P,O,K,n"))) - (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))] + [(parallel [(set (match_dup 0) + (lshiftrt:ALL2 (match_dup 1) + (match_dup 2))) + (clobber (match_dup 3))])]) + +;; "*lshrhi3_const" +;; "*lshrhq3_const" "*lshruhq3_const" +;; "*lshrha3_const" "*lshruha3_const" +(define_insn "*lshr3_const" + [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r") + (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0") + (match_operand:QI 2 "const_int_operand" "L,P,O,K,n"))) + (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))] "reload_completed" { return lshrhi3_out (insn, operands, NULL); @@ -3823,19 +3964,23 @@ (define_insn "*lshrhi3_const" (define_peephole2 [(match_scratch:QI 3 "d") - (set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" "")))] + (set (match_operand:ALL4 0 "register_operand" "") + (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] "" - [(parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 1) (match_dup 2))) - (clobber (match_dup 3))])] - "") - -(define_insn "*lshrsi3_const" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0") - (match_operand:QI 2 "const_int_operand" "L,P,O,n"))) - (clobber (match_scratch:QI 3 "=X,X,X,&d"))] + [(parallel [(set (match_dup 0) + (lshiftrt:ALL4 (match_dup 1) + (match_dup 2))) + (clobber (match_dup 3))])]) + +;; "*lshrsi3_const" +;; "*lshrsq3_const" "*lshrusq3_const" +;; "*lshrsa3_const" "*lshrusa3_const" +(define_insn "*lshr3_const" + [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r") + (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0") + (match_operand:QI 2 "const_int_operand" "L,P,O,n"))) + (clobber (match_scratch:QI 3 "=X,X,X,&d"))] "reload_completed" { return lshrsi3_out (insn, operands, NULL); @@ -4278,24 +4423,29 @@ (define_insn "*negated_tstsi" [(set_attr "cc" "compare") (set_attr "length" "4")]) -(define_insn "*reversed_tstsi" +;; "*reversed_tstsi" +;; "*reversed_tstsq" "*reversed_tstusq" +;; "*reversed_tstsa" "*reversed_tstusa" +(define_insn "*reversed_tst" [(set (cc0) - (compare (const_int 0) - (match_operand:SI 0 "register_operand" "r"))) - (clobber (match_scratch:QI 1 "=X"))] - "" - "cp __zero_reg__,%A0 - cpc __zero_reg__,%B0 - cpc __zero_reg__,%C0 - cpc __zero_reg__,%D0" + (compare (match_operand:ALL4 0 "const0_operand" "Y00") + (match_operand:ALL4 1 "register_operand" "r"))) + (clobber (match_scratch:QI 2 "=X"))] + "" + "cp __zero_reg__,%A1 + cpc __zero_reg__,%B1 + cpc __zero_reg__,%C1 + cpc __zero_reg__,%D1" [(set_attr "cc" "compare") (set_attr "length" "4")]) -(define_insn "*cmpqi" +;; "*cmpqi" +;; "*cmpqq" "*cmpuqq" +(define_insn "*cmp" [(set (cc0) - (compare (match_operand:QI 0 "register_operand" "r,r,d") - (match_operand:QI 1 "nonmemory_operand" "L,r,i")))] + (compare (match_operand:ALL1 0 "register_operand" "r ,r,d") + (match_operand:ALL1 1 "nonmemory_operand" "Y00,r,i")))] "" "@ tst %0 @@ -4313,11 +4463,14 @@ (define_insn "*cmpqi_sign_extend" [(set_attr "cc" "compare") (set_attr "length" "1")]) -(define_insn "*cmphi" +;; "*cmphi" +;; "*cmphq" "*cmpuhq" +;; "*cmpha" "*cmpuha" +(define_insn "*cmp" [(set (cc0) - (compare (match_operand:HI 0 "register_operand" "!w,r,r,d ,r ,d,r") - (match_operand:HI 1 "nonmemory_operand" "L ,L,r,s ,s ,M,n"))) - (clobber (match_scratch:QI 2 "=X ,X,X,&d,&d ,X,&d"))] + (compare (match_operand:ALL2 0 "register_operand" "!w ,r ,r,d ,r ,d,r") + (match_operand:ALL2 1 "nonmemory_operand" "Y00,Y00,r,s ,s ,M,n Ynn"))) + (clobber (match_scratch:QI 2 "=X ,X ,X,&d,&d ,X,&d"))] "" { switch (which_alternative) @@ -4330,11 +4483,15 @@ (define_insn "*cmphi" return "cp %A0,%A1\;cpc %B0,%B1"; case 3: + if (mode != HImode) + break; return reg_unused_after (insn, operands[0]) ? "subi %A0,lo8(%1)\;sbci %B0,hi8(%1)" : "ldi %2,hi8(%1)\;cpi %A0,lo8(%1)\;cpc %B0,%2"; case 4: + if (mode != HImode) + break; return "ldi %2,lo8(%1)\;cp %A0,%2\;ldi %2,hi8(%1)\;cpc %B0,%2"; } @@ -4374,11 +4531,14 @@ (define_insn "*cmppsi" (set_attr "length" "3,3,5,6,3,7") (set_attr "adjust_len" "tstpsi,*,*,*,compare,compare")]) -(define_insn "*cmpsi" +;; "*cmpsi" +;; "*cmpsq" "*cmpusq" +;; "*cmpsa" "*cmpusa" +(define_insn "*cmp" [(set (cc0) - (compare (match_operand:SI 0 "register_operand" "r,r ,d,r ,r") - (match_operand:SI 1 "nonmemory_operand" "L,r ,M,M ,n"))) - (clobber (match_scratch:QI 2 "=X,X ,X,&d,&d"))] + (compare (match_operand:ALL4 0 "register_operand" "r ,r ,d,r ,r") + (match_operand:ALL4 1 "nonmemory_operand" "Y00,r ,M,M ,n Ynn"))) + (clobber (match_scratch:QI 2 "=X ,X ,X,&d,&d"))] "" { if (0 == which_alternative) @@ -4398,55 +4558,33 @@ (define_insn "*cmpsi" ;; ---------------------------------------------------------------------- ;; Conditional jump instructions -(define_expand "cbranchsi4" - [(parallel [(set (cc0) - (compare (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" ""))) - (clobber (match_scratch:QI 4 ""))]) +;; "cbranchqi4" +;; "cbranchqq4" "cbranchuqq4" +(define_expand "cbranch4" + [(set (cc0) + (compare (match_operand:ALL1 1 "register_operand" "") + (match_operand:ALL1 2 "nonmemory_operand" ""))) (set (pc) (if_then_else - (match_operator 0 "ordered_comparison_operator" [(cc0) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "") - -(define_expand "cbranchpsi4" - [(parallel [(set (cc0) - (compare (match_operand:PSI 1 "register_operand" "") - (match_operand:PSI 2 "nonmemory_operand" ""))) - (clobber (match_scratch:QI 4 ""))]) - (set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" [(cc0) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "") + (match_operator 0 "ordered_comparison_operator" [(cc0) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))]) -(define_expand "cbranchhi4" +;; "cbranchhi4" "cbranchhq4" "cbranchuhq4" "cbranchha4" "cbranchuha4" +;; "cbranchsi4" "cbranchsq4" "cbranchusq4" "cbranchsa4" "cbranchusa4" +;; "cbranchpsi4" +(define_expand "cbranch4" [(parallel [(set (cc0) - (compare (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "nonmemory_operand" ""))) + (compare (match_operand:ORDERED234 1 "register_operand" "") + (match_operand:ORDERED234 2 "nonmemory_operand" ""))) (clobber (match_scratch:QI 4 ""))]) (set (pc) (if_then_else - (match_operator 0 "ordered_comparison_operator" [(cc0) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "") - -(define_expand "cbranchqi4" - [(set (cc0) - (compare (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (set (pc) - (if_then_else - (match_operator 0 "ordered_comparison_operator" [(cc0) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "") + (match_operator 0 "ordered_comparison_operator" [(cc0) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))]) ;; Test a single bit in a QI/HI/SImode register. @@ -4477,7 +4615,7 @@ (define_insn "*sbrx_branch" (const_int 4)))) (set_attr "cc" "clobber")]) -;; Same test based on Bitwise AND RTL. Keep this incase gcc changes patterns. +;; Same test based on bitwise AND. Keep this in case gcc changes patterns. ;; or for old peepholes. ;; Fixme - bitwise Mask will not work for DImode @@ -4492,12 +4630,12 @@ (define_insn "*sbrx_and_branch" (label_ref (match_operand 3 "" "")) (pc)))] "" -{ + { HOST_WIDE_INT bitnumber; bitnumber = exact_log2 (GET_MODE_MASK (mode) & INTVAL (operands[2])); operands[2] = GEN_INT (bitnumber); return avr_out_sbxx_branch (insn, operands); -} + } [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046)) (le (minus (pc) (match_dup 3)) (const_int 2046))) @@ -4837,9 +4975,10 @@ (define_insn "*tablejump" (define_expand "casesi" - [(set (match_dup 6) - (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0) - (match_operand:HI 1 "register_operand" ""))) + [(parallel [(set (match_dup 6) + (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0) + (match_operand:HI 1 "register_operand" ""))) + (clobber (scratch:QI))]) (parallel [(set (cc0) (compare (match_dup 6) (match_operand:HI 2 "register_operand" ""))) @@ -5201,8 +5340,8 @@ (define_peephole ; "*dec-and-branchqi!=- (define_peephole ; "*cpse.eq" [(set (cc0) - (compare (match_operand:QI 1 "register_operand" "r,r") - (match_operand:QI 2 "reg_or_0_operand" "r,L"))) + (compare (match_operand:ALL1 1 "register_operand" "r,r") + (match_operand:ALL1 2 "reg_or_0_operand" "r,Y00"))) (set (pc) (if_then_else (eq (cc0) (const_int 0)) @@ -5236,8 +5375,8 @@ (define_peephole ; "*cpse.eq" (define_peephole ; "*cpse.ne" [(set (cc0) - (compare (match_operand:QI 1 "register_operand" "") - (match_operand:QI 2 "reg_or_0_operand" ""))) + (compare (match_operand:ALL1 1 "register_operand" "") + (match_operand:ALL1 2 "reg_or_0_operand" ""))) (set (pc) (if_then_else (ne (cc0) (const_int 0)) @@ -5246,7 +5385,7 @@ (define_peephole ; "*cpse.ne" "!AVR_HAVE_JMP_CALL || !avr_current_device->errata_skip" { - if (operands[2] == const0_rtx) + if (operands[2] == CONST0_RTX (mode)) operands[2] = zero_reg_rtx; return 3 == avr_jump_mode (operands[0], insn) @@ -6265,4 +6404,8 @@ (define_insn_and_split "*extzv.qihi2" }) +;; Fixed-point instructions +(include "avr-fixed.md") + +;; Operations on 64-bit registers (include "avr-dimode.md") Index: gcc/config/avr/avr-modes.def =================================================================== --- gcc/config/avr/avr-modes.def (revision 190299) +++ gcc/config/avr/avr-modes.def (working copy) @@ -1 +1,27 @@ FRACTIONAL_INT_MODE (PSI, 24, 3); + +/* On 8 bit machines it requires fewer instructions for fixed point + routines if the decimal place is on a byte boundary which is not + the default for signed accum types. */ + +ADJUST_IBIT (HA, 7); +ADJUST_FBIT (HA, 8); + +ADJUST_IBIT (SA, 15); +ADJUST_FBIT (SA, 16); + +ADJUST_IBIT (DA, 31); +ADJUST_FBIT (DA, 32); + +/* Make TA and UTA 64 bits wide. + 128 bit wide modes would be insane on a 8-bit machine. */ + +ADJUST_BYTESIZE (TA, 8); +ADJUST_ALIGNMENT (TA, 1); +ADJUST_IBIT (TA, 15); +ADJUST_FBIT (TA, 48); + +ADJUST_BYTESIZE (UTA, 8); +ADJUST_ALIGNMENT (UTA, 1); +ADJUST_IBIT (UTA, 16); +ADJUST_FBIT (UTA, 48); Index: gcc/config/avr/avr-protos.h =================================================================== --- gcc/config/avr/avr-protos.h (revision 190299) +++ gcc/config/avr/avr-protos.h (working copy) @@ -79,6 +79,9 @@ extern const char* avr_load_lpm (rtx, rt extern bool avr_rotate_bytes (rtx operands[]); +extern const char* avr_out_fract (rtx, rtx[], bool, int*); +extern rtx avr_to_int_mode (rtx); + extern void expand_prologue (void); extern void expand_epilogue (bool); extern bool avr_emit_movmemhi (rtx*); @@ -92,6 +95,8 @@ extern const char* avr_out_plus (rtx*, i extern const char* avr_out_plus_noclobber (rtx*, int*, int*); extern const char* avr_out_plus64 (rtx, int*); extern const char* avr_out_addto_sp (rtx*, int*); +extern const char* avr_out_minus (rtx*, int*, int*); +extern const char* avr_out_minus64 (rtx, int*); extern const char* avr_out_xload (rtx, rtx*, int*); extern const char* avr_out_movmem (rtx, rtx*, int*); extern const char* avr_out_insert_bits (rtx*, int*); Index: gcc/config/avr/constraints.md =================================================================== --- gcc/config/avr/constraints.md (revision 190299) +++ gcc/config/avr/constraints.md (working copy) @@ -192,3 +192,47 @@ (define_constraint "C0f" "32-bit integer constant where no nibble equals 0xf." (and (match_code "const_int") (match_test "!avr_has_nibble_0xf (op)"))) + +;; CONST_FIXED is no element of 'n' so cook our own. +;; "i" or "s" would match but because the insn uses iterators that cover +;; INT_MODE, "i" or "s" is not always possible. + +(define_constraint "Ynn" + "Fixed-point constant known at compile time." + (match_code "const_fixed")) + +(define_constraint "Y00" + "Fixed-point or integer constant with bit representation 0x0" + (and (match_code "const_fixed,const_int") + (match_test "op == CONST0_RTX (GET_MODE (op))"))) + +(define_constraint "Y01" + "Fixed-point or integer constant with bit representation 0x1" + (ior (and (match_code "const_fixed") + (match_test "1 == INTVAL (avr_to_int_mode (op))")) + (match_test "satisfies_constraint_P (op)"))) + +(define_constraint "Ym1" + "Fixed-point or integer constant with bit representation -0x1" + (ior (and (match_code "const_fixed") + (match_test "-1 == INTVAL (avr_to_int_mode (op))")) + (match_test "satisfies_constraint_N (op)"))) + +(define_constraint "Y02" + "Fixed-point or integer constant with bit representation 0x2" + (ior (and (match_code "const_fixed") + (match_test "2 == INTVAL (avr_to_int_mode (op))")) + (match_test "satisfies_constraint_K (op)"))) + +(define_constraint "Ym2" + "Fixed-point or integer constant with bit representation -0x2" + (ior (and (match_code "const_fixed") + (match_test "-2 == INTVAL (avr_to_int_mode (op))")) + (match_test "satisfies_constraint_Cm2 (op)"))) + +;; Similar to "IJ" used with ADIW/SBIW, but for CONST_FIXED. + +(define_constraint "YIJ" + "Fixed-point constant from @minus{}0x003f to 0x003f." + (and (match_code "const_fixed") + (match_test "IN_RANGE (INTVAL (avr_to_int_mode (op)), -63, 63)"))) Index: gcc/config/avr/avr.c =================================================================== --- gcc/config/avr/avr.c (revision 190299) +++ gcc/config/avr/avr.c (working copy) @@ -49,6 +49,10 @@ #include "params.h" #include "df.h" +#ifndef CONST_FIXED_P +#define CONST_FIXED_P(X) (CONST_FIXED == GET_CODE (X)) +#endif + /* Maximal allowed offset for an address in the LD command */ #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE)) @@ -264,6 +268,23 @@ avr_popcount_each_byte (rtx xval, int n_ return true; } + +/* Access some RTX as INT_MODE. If X is a CONST_FIXED we can get + the bit representation of X by "casting" it to CONST_INT. */ + +rtx +avr_to_int_mode (rtx x) +{ + enum machine_mode mode = GET_MODE (x); + + return VOIDmode == mode + ? x + : simplify_gen_subreg (int_mode_for_mode (mode), x, mode, 0); +} + + +/* Implement `TARGET_OPTION_OVERRIDE'. */ + static void avr_option_override (void) { @@ -389,9 +410,14 @@ avr_regno_reg_class (int r) } +/* Implement `TARGET_SCALAR_MODE_SUPPORTED_P'. */ + static bool avr_scalar_mode_supported_p (enum machine_mode mode) { + if (ALL_FIXED_POINT_MODE_P (mode)) + return true; + if (PSImode == mode) return true; @@ -715,6 +741,8 @@ avr_initial_elimination_offset (int from } } + +/* Implement `TARGET_BUILTIN_SETJMP_FRAME_VALUE'. */ /* Actual start of frame is virtual_stack_vars_rtx this is offset from frame pointer by +STARTING_FRAME_OFFSET. Using saved frame = virtual_stack_vars_rtx - STARTING_FRAME_OFFSET @@ -723,10 +751,13 @@ avr_initial_elimination_offset (int from static rtx avr_builtin_setjmp_frame_value (void) { - return gen_rtx_MINUS (Pmode, virtual_stack_vars_rtx, - gen_int_mode (STARTING_FRAME_OFFSET, Pmode)); + rtx xval = gen_reg_rtx (Pmode); + emit_insn (gen_subhi3 (xval, virtual_stack_vars_rtx, + gen_int_mode (STARTING_FRAME_OFFSET, Pmode))); + return xval; } + /* Return contents of MEM at frame pointer + stack size + 1 (+2 if 3 byte PC). This is return address of function. */ rtx @@ -2081,6 +2112,14 @@ avr_print_operand (FILE *file, rtx x, in /* Use normal symbol for direct address no linker trampoline needed */ output_addr_const (file, x); } + else if (GET_CODE (x) == CONST_FIXED) + { + HOST_WIDE_INT ival = INTVAL (avr_to_int_mode (x)); + if (code != 0) + output_operand_lossage ("Unsupported code '%c'for fixed-point:", + code); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival); + } else if (GET_CODE (x) == CONST_DOUBLE) { long val; @@ -2116,6 +2155,7 @@ notice_update_cc (rtx body ATTRIBUTE_UNU case CC_OUT_PLUS: case CC_OUT_PLUS_NOCLOBBER: + case CC_MINUS: case CC_LDI: { rtx *op = recog_data.operand; @@ -2139,6 +2179,11 @@ notice_update_cc (rtx body ATTRIBUTE_UNU cc = (enum attr_cc) icc; break; + case CC_MINUS: + avr_out_minus (op, &len_dummy, &icc); + cc = (enum attr_cc) icc; + break; + case CC_LDI: cc = (op[1] == CONST0_RTX (GET_MODE (op[0])) @@ -2779,9 +2824,11 @@ output_movqi (rtx insn, rtx operands[], if (real_l) *real_l = 1; - if (register_operand (dest, QImode)) + gcc_assert (1 == GET_MODE_SIZE (GET_MODE (dest))); + + if (REG_P (dest)) { - if (register_operand (src, QImode)) /* mov r,r */ + if (REG_P (src)) /* mov r,r */ { if (test_hard_reg_class (STACK_REG, dest)) return "out %0,%1"; @@ -2803,7 +2850,7 @@ output_movqi (rtx insn, rtx operands[], rtx xop[2]; xop[0] = dest; - xop[1] = src == const0_rtx ? zero_reg_rtx : src; + xop[1] = src == CONST0_RTX (GET_MODE (dest)) ? zero_reg_rtx : src; return out_movqi_mr_r (insn, xop, real_l); } @@ -2825,6 +2872,8 @@ output_movhi (rtx insn, rtx xop[], int * return avr_out_lpm (insn, xop, plen); } + gcc_assert (2 == GET_MODE_SIZE (GET_MODE (dest))); + if (REG_P (dest)) { if (REG_P (src)) /* mov r,r */ @@ -2843,7 +2892,6 @@ output_movhi (rtx insn, rtx xop[], int * return TARGET_NO_INTERRUPTS ? avr_asm_len ("out __SP_H__,%B1" CR_TAB "out __SP_L__,%A1", xop, plen, -2) - : avr_asm_len ("in __tmp_reg__,__SREG__" CR_TAB "cli" CR_TAB "out __SP_H__,%B1" CR_TAB @@ -2880,7 +2928,7 @@ output_movhi (rtx insn, rtx xop[], int * rtx xop[2]; xop[0] = dest; - xop[1] = src == const0_rtx ? zero_reg_rtx : src; + xop[1] = src == CONST0_RTX (GET_MODE (dest)) ? zero_reg_rtx : src; return out_movhi_mr_r (insn, xop, plen); } @@ -3403,9 +3451,10 @@ output_movsisf (rtx insn, rtx operands[] if (!l) l = &dummy; - if (register_operand (dest, VOIDmode)) + gcc_assert (4 == GET_MODE_SIZE (GET_MODE (dest))); + if (REG_P (dest)) { - if (register_operand (src, VOIDmode)) /* mov r,r */ + if (REG_P (src)) /* mov r,r */ { if (true_regnum (dest) > true_regnum (src)) { @@ -3440,10 +3489,10 @@ output_movsisf (rtx insn, rtx operands[] { return output_reload_insisf (operands, NULL_RTX, real_l); } - else if (GET_CODE (src) == MEM) + else if (MEM_P (src)) return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */ } - else if (GET_CODE (dest) == MEM) + else if (MEM_P (dest)) { const char *templ; @@ -4126,14 +4175,25 @@ avr_out_compare (rtx insn, rtx *xop, int rtx xval = xop[1]; /* MODE of the comparison. */ - enum machine_mode mode = GET_MODE (xreg); + enum machine_mode mode; /* Number of bytes to operate on. */ - int i, n_bytes = GET_MODE_SIZE (mode); + int i, n_bytes = GET_MODE_SIZE (GET_MODE (xreg)); /* Value (0..0xff) held in clobber register xop[2] or -1 if unknown. */ int clobber_val = -1; + /* Map fixed mode operands to integer operands with the same binary + representation. They are easier to handle in the remainder. */ + + if (CONST_FIXED == GET_CODE (xval)) + { + xreg = avr_to_int_mode (xop[0]); + xval = avr_to_int_mode (xop[1]); + } + + mode = GET_MODE (xreg); + gcc_assert (REG_P (xreg)); gcc_assert ((CONST_INT_P (xval) && n_bytes <= 4) || (const_double_operand (xval, VOIDmode) && n_bytes == 8)); @@ -5884,6 +5944,9 @@ avr_out_plus_1 (rtx *xop, int *plen, enu /* MODE of the operation. */ enum machine_mode mode = GET_MODE (xop[0]); + /* INT_MODE of the same size. */ + enum machine_mode imode = int_mode_for_mode (mode); + /* Number of bytes to operate on. */ int i, n_bytes = GET_MODE_SIZE (mode); @@ -5908,8 +5971,11 @@ avr_out_plus_1 (rtx *xop, int *plen, enu *pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER; + if (CONST_FIXED_P (xval)) + xval = avr_to_int_mode (xval); + if (MINUS == code) - xval = simplify_unary_operation (NEG, mode, xval, mode); + xval = simplify_unary_operation (NEG, imode, xval, imode); op[2] = xop[3]; @@ -5920,7 +5986,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enu { /* We operate byte-wise on the destination. */ rtx reg8 = simplify_gen_subreg (QImode, xop[0], mode, i); - rtx xval8 = simplify_gen_subreg (QImode, xval, mode, i); + rtx xval8 = simplify_gen_subreg (QImode, xval, imode, i); /* 8-bit value to operate with this byte. */ unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode); @@ -5941,7 +6007,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enu && i + 2 <= n_bytes && test_hard_reg_class (ADDW_REGS, reg8)) { - rtx xval16 = simplify_gen_subreg (HImode, xval, mode, i); + rtx xval16 = simplify_gen_subreg (HImode, xval, imode, i); unsigned int val16 = UINTVAL (xval16) & GET_MODE_MASK (HImode); /* Registers R24, X, Y, Z can use ADIW/SBIW with constants < 64 @@ -6085,6 +6151,41 @@ avr_out_plus_noclobber (rtx *xop, int *p } +/* Output subtraction of register XOP[0] and compile time constant XOP[2]: + + XOP[0] = XOP[0] - XOP[2] + + This is basically the same as `avr_out_plus' except that we subtract. + It's needed because (minus x const) is not mapped to (plus x -const) + for the fixed point modes. */ + +const char* +avr_out_minus (rtx *xop, int *plen, int *pcc) +{ + rtx op[4]; + + if (pcc) + *pcc = (int) CC_SET_CZN; + + if (REG_P (xop[2])) + return avr_asm_len ("sub %A0,%A2" CR_TAB + "sbc %B0,%B2", xop, plen, -2); + + if (!CONST_INT_P (xop[2]) + && !CONST_FIXED_P (xop[2])) + return avr_asm_len ("subi %A0,lo8(%2)" CR_TAB + "sbci %B0,hi8(%2)", xop, plen, -2); + + op[0] = avr_to_int_mode (xop[0]); + op[1] = avr_to_int_mode (xop[1]); + op[2] = gen_int_mode (-INTVAL (avr_to_int_mode (xop[2])), + GET_MODE (op[0])); + op[3] = xop[3]; + + return avr_out_plus (op, plen, pcc); +} + + /* Prepare operands of adddi3_const_insn to be used with avr_out_plus_1. */ const char* @@ -6103,6 +6204,19 @@ avr_out_plus64 (rtx addend, int *plen) return ""; } + +/* Prepare operands of subdi3_const_insn to be used with avr_out_plus64. */ + +const char* +avr_out_minus64 (rtx subtrahend, int *plen) +{ + rtx xneg = avr_to_int_mode (subtrahend); + xneg = simplify_unary_operation (NEG, DImode, xneg, DImode); + + return avr_out_plus64 (xneg, plen); +} + + /* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile time constant XOP[2]: @@ -6442,6 +6556,319 @@ avr_rotate_bytes (rtx operands[]) return true; } + +/* Outputs instructions needed for fixed point type conversion. + This includes converting between any fixed point type, as well + as converting to any integer type. Conversion between integer + types is not supported. + + The number of instructions generated depends on the types + being converted and the registers assigned to them. + + The number of instructions required to complete the conversion + is least if the registers for source and destination are overlapping + and are aligned at the decimal place as actual movement of data is + completely avoided. In some cases, the conversion may already be + complete without any instructions needed. + + When converting to signed types from signed types, sign extension + is implemented. + + Converting signed fractional types requires a bit shift if converting + to or from any unsigned fractional type because the decimal place is + shifted by 1 bit. When the destination is a signed fractional, the sign + is stored in either the carry or T bit. */ + +const char* +avr_out_fract (rtx insn, rtx operands[], bool intsigned, int *plen) +{ + int i; + bool sbit[2]; + /* ilen: Length of integral part (in bytes) + flen: Length of fractional part (in bytes) + tlen: Length of operand (in bytes) + blen: Length of operand (in bits) */ + int ilen[2], flen[2], tlen[2], blen[2]; + int rdest, rsource, offset; + int start, end, dir; + bool sign_in_T = false, sign_in_Carry = false; + int clrword = -1, lastclr = 0, clr = 0; + rtx xop[6]; + + const int dest = 0; + const int src = 1; + + xop[dest] = operands[dest]; + xop[src] = operands[src]; + + if (plen) + *plen = 0; + + /* Determine format (integer and fractional parts) + of types needing conversion. */ + + for (i = 0; i < 2; i++) + { + enum machine_mode mode = GET_MODE (xop[i]); + + tlen[i] = GET_MODE_SIZE (mode); + blen[i] = GET_MODE_BITSIZE (mode); + + if (SCALAR_INT_MODE_P (mode)) + { + sbit[i] = intsigned; + ilen[i] = GET_MODE_SIZE (mode); + flen[i] = 0; + } + else if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) + { + sbit[i] = SIGNED_SCALAR_FIXED_POINT_MODE_P (mode); + ilen[i] = (GET_MODE_IBIT (mode) + 1) / 8; + flen[i] = (GET_MODE_FBIT (mode) + 1) / 8; + } + else + fatal_insn ("unsupported fixed-point conversion", insn); + } + + rdest = REGNO (xop[dest]); + rsource = REGNO (xop[src]); + offset = flen[src] - flen[dest]; + + /* For bit index */ + + xop[2] = GEN_INT (blen[dest] - 1); + xop[3] = GEN_INT (blen[src] - 1); + + /* Store the sign bit if the destination is a signed fract and the source + has a sign in the integer part. */ + + if (sbit[dest] && ilen[dest] == 0 && sbit[src] && ilen[src] > 0) + { + /* Position of MSB in the source operand. */ + + xop[4] = GEN_INT (blen[1] - 1); + + /* To avoid using BST and BLD if the source and destination registers + overlap or the source is unused after, we can use LSL to store the + sign bit in carry since we don't need the integral part of the source. + Restoring the sign from carry saves one BLD instruction below. */ + + if (reg_unused_after (insn, xop[src]) + || (rdest < rsource + tlen[src] + && rdest + tlen[dest] > rsource)) + { + avr_asm_len ("lsl %T1%t4", xop, plen, 1); + sign_in_Carry = true; + } + else + { + avr_asm_len ("bst %T1%T4", xop, plen, 1); + sign_in_T = true; + } + } + + /* Pick the correct direction to shift bytes. */ + + if (rdest < rsource + offset) + { + dir = 1; + start = 0; + end = tlen[dest]; + } + else + { + dir = -1; + start = tlen[dest] - 1; + end = -1; + } + + /* Perform conversion by moving registers into place, clearing + destination registers that do not overlap with any source. */ + + for (i = start; i != end; i += dir) + { + int destloc = rdest + i; + int sourceloc = rsource + i + offset; + + /* Source register location is outside range of source register, + so clear this byte in the dest. */ + + if (sourceloc < rsource + || sourceloc >= rsource + tlen[src]) + { + if (AVR_HAVE_MOVW + && i + dir != end + && (sourceloc + dir < rsource + || sourceloc + dir >= rsource + tlen[src]) + && ((dir == 1 && !(destloc % 2) && !(sourceloc % 2)) + || (dir == -1 && (destloc % 2) && (sourceloc % 2))) + && clrword != -1) + { + /* Use already cleared word to clear two bytes at a time. */ + + int even_i = i & ~1; + int even_clrword = clrword & ~1; + + xop[4] = GEN_INT (8 * even_i); + xop[5] = GEN_INT (8 * even_clrword); + avr_asm_len ("movw %T0%t4,%T0%t5", xop, plen, 1); + i += dir; + } + else + { + /* Do not clear the register if it is going to get + sign extended with a MOV later. */ + + if (sbit[dest] && sbit[src] + && i != tlen[dest] - 1 + && i >= flen[dest]) + continue; + + xop[4] = GEN_INT (8 * i); + avr_asm_len ("clr %T0%t4", xop, plen, 1); + + /* If the last byte was cleared too, we have a cleared + word we can MOVW to clear two bytes at a time. */ + + if (lastclr) + clrword = i; + + clr = 1; + } + } + else if (destloc == sourceloc) + { + /* Source byte is already in destination: Nothing needed. */ + + continue; + } + else + { + /* Registers do not line up and source register location + is within range: Perform move, shifting with MOV or MOVW. */ + + if (AVR_HAVE_MOVW + && i + dir != end + && sourceloc + dir >= rsource + && sourceloc + dir < rsource + tlen[src] + && ((dir == 1 && !(destloc % 2) && !(sourceloc % 2)) + || (dir == -1 && (destloc % 2) && (sourceloc % 2)))) + { + int even_i = i & ~1; + int even_i_plus_offset = (i + offset) & ~1; + + xop[4] = GEN_INT (8 * even_i); + xop[5] = GEN_INT (8 * even_i_plus_offset); + avr_asm_len ("movw %T0%t4,%T1%t5", xop, plen, 1); + i += dir; + } + else + { + xop[4] = GEN_INT (8 * i); + xop[5] = GEN_INT (8 * (i + offset)); + avr_asm_len ("mov %T0%t4,%T1%t5", xop, plen, 1); + } + } + + lastclr = clr; + clr = 0; + } + + /* Perform sign extension if source and dest are both signed, + and there are more integer parts in dest than in source. */ + + if (sbit[dest] && sbit[src] && ilen[dest] > ilen[src]) + { + xop[4] = GEN_INT (blen[src] - 1 - 8 * offset); + avr_asm_len ("sbrc %T0%T4", xop, plen, 1); + + /* Register was previously cleared, so can become 0xff and extended. */ + + avr_asm_len ("com %T0%t2", xop, plen, 1); + + /* Sign extend additional bytes by MOV and MOVW. */ + + start = tlen[dest] - 2; + end = flen[dest] + ilen[src] - 1; + + for (i = start; i != end; i--) + { + if (AVR_HAVE_MOVW && i != start && i-1 != end) + { + i--; + xop[4] = GEN_INT (8 * i); + xop[5] = GEN_INT (8 * (tlen[dest] - 2)); + avr_asm_len ("movw %T0%t4,%T0%t5", xop, plen, 1); + } + else + { + xop[4] = GEN_INT (8 * i); + xop[5] = GEN_INT (8 * (tlen[dest] - 1)); + avr_asm_len ("mov %T0%t4,%T0%t5", xop, plen, 1); + } + } + } + + /* If destination is a signed fract, and the source was not, a shift + by 1 bit is needed. Also restore sign from carry or T. */ + + if (sbit[dest] && !ilen[dest] && (!sbit[src] || ilen[src])) + { + /* We have flen[src] non-zero fractional bytes to shift. + Because of the right shift, handle one byte more so that the + LSB won't be lost. */ + + int nonzero = flen[src] + 1; + + /* If the LSB is in the T flag and there are no fractional + bits, the high byte is zero and no shift needed. */ + + if (flen[src] == 0 && sign_in_T) + nonzero = 0; + + start = flen[dest] - 1; + end = start - nonzero; + + for (i = start; i > end && i >= 0; i--) + { + xop[4] = GEN_INT (8 * i); + if (i == start && !sign_in_Carry) + avr_asm_len ("lsr %T0%t4", xop, plen, 1); + else + avr_asm_len ("ror %T0%t4", xop, plen, 1); + } + + if (sign_in_T) + { + xop[4] = GEN_INT (blen[dest] - 1); + avr_asm_len ("bld %T0%T4", xop, plen, 1); + } + } + else if (sbit[src] && !ilen[src] && (!sbit[dest] || ilen[dest])) + { + /* If source was a signed fract and dest was not, shift 1 bit + other way. */ + + start = flen[dest] - flen[src]; + + if (start < 0) + start = 0; + + for (i = start; i < flen[dest]; i++) + { + xop[4] = GEN_INT (8 * i); + + if (i == start) + avr_asm_len ("lsl %T0%t4", xop, plen, 1); + else + avr_asm_len ("rol %T0%t4", xop, plen, 1); + } + } + + return ""; +} + + /* Modifies the length assigned to instruction INSN LEN is the initially computed length of the insn. */ @@ -6489,6 +6916,8 @@ adjust_insn_length (rtx insn, int len) case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len, NULL); break; case ADJUST_LEN_PLUS64: avr_out_plus64 (op[0], &len); break; + case ADJUST_LEN_MINUS: avr_out_minus (op, &len, NULL); break; + case ADJUST_LEN_MINUS64: avr_out_minus64 (op[0], &len); break; case ADJUST_LEN_OUT_PLUS_NOCLOBBER: avr_out_plus_noclobber (op, &len, NULL); break; @@ -6502,6 +6931,9 @@ adjust_insn_length (rtx insn, int len) case ADJUST_LEN_XLOAD: avr_out_xload (insn, op, &len); break; case ADJUST_LEN_LOAD_LPM: avr_load_lpm (insn, op, &len); break; + case ADJUST_LEN_SFRACT: avr_out_fract (insn, op, true, &len); break; + case ADJUST_LEN_UFRACT: avr_out_fract (insn, op, false, &len); break; + case ADJUST_LEN_TSTHI: avr_out_tsthi (insn, op, &len); break; case ADJUST_LEN_TSTPSI: avr_out_tstpsi (insn, op, &len); break; case ADJUST_LEN_TSTSI: avr_out_tstsi (insn, op, &len); break; @@ -6683,6 +7115,20 @@ avr_assemble_integer (rtx x, unsigned in return true; } + else if (CONST_FIXED_P (x)) + { + unsigned n; + + /* varasm fails to handle big fixed modes that don't fit in hwi. */ + + for (n = 0; n < size; n++) + { + rtx xn = simplify_gen_subreg (QImode, x, GET_MODE (x), n); + default_assemble_integer (xn, 1, aligned_p); + } + + return true; + } return default_assemble_integer (x, size, aligned_p); } @@ -7489,6 +7935,7 @@ avr_operand_rtx_cost (rtx x, enum machin return 0; case CONST_INT: + case CONST_FIXED: case CONST_DOUBLE: return COSTS_N_INSNS (GET_MODE_SIZE (mode)); @@ -7518,6 +7965,7 @@ avr_rtx_costs_1 (rtx x, int codearg, int switch (code) { case CONST_INT: + case CONST_FIXED: case CONST_DOUBLE: case SYMBOL_REF: case CONST: @@ -8788,6 +9236,8 @@ avr_2word_insn_p (rtx insn) return false; case CODE_FOR_movqi_insn: + case CODE_FOR_movuqq_insn: + case CODE_FOR_movqq_insn: { rtx set = single_set (insn); rtx src = SET_SRC (set); @@ -8796,7 +9246,7 @@ avr_2word_insn_p (rtx insn) /* Factor out LDS and STS from movqi_insn. */ if (MEM_P (dest) - && (REG_P (src) || src == const0_rtx)) + && (REG_P (src) || src == CONST0_RTX (GET_MODE (dest)))) { return CONSTANT_ADDRESS_P (XEXP (dest, 0)); } @@ -9021,7 +9471,7 @@ output_reload_in_const (rtx *op, rtx clo if (NULL_RTX == clobber_reg && !test_hard_reg_class (LD_REGS, dest) - && (! (CONST_INT_P (src) || CONST_DOUBLE_P (src)) + && (! (CONST_INT_P (src) || CONST_FIXED_P (src) || CONST_DOUBLE_P (src)) || !avr_popcount_each_byte (src, n_bytes, (1 << 0) | (1 << 1) | (1 << 8)))) { @@ -9048,6 +9498,7 @@ output_reload_in_const (rtx *op, rtx clo ldreg_p = test_hard_reg_class (LD_REGS, xdest[n]); if (!CONST_INT_P (src) + && !CONST_FIXED_P (src) && !CONST_DOUBLE_P (src)) { static const char* const asm_code[][2] = @@ -9239,6 +9690,7 @@ output_reload_insisf (rtx *op, rtx clobb if (AVR_HAVE_MOVW && !test_hard_reg_class (LD_REGS, op[0]) && (CONST_INT_P (op[1]) + || CONST_FIXED_P (op[1]) || CONST_DOUBLE_P (op[1]))) { int len_clr, len_noclr; @@ -10834,6 +11286,9 @@ avr_fold_builtin (tree fndecl, int n_arg #undef TARGET_SCALAR_MODE_SUPPORTED_P #define TARGET_SCALAR_MODE_SUPPORTED_P avr_scalar_mode_supported_p +#undef TARGET_FIXED_POINT_SUPPORTED_P +#define TARGET_FIXED_POINT_SUPPORTED_P hook_bool_void_true + #undef TARGET_ADDR_SPACE_SUBSET_P #define TARGET_ADDR_SPACE_SUBSET_P avr_addr_space_subset_p Index: libgcc/config/avr/avr-lib.h =================================================================== --- libgcc/config/avr/avr-lib.h (revision 190299) +++ libgcc/config/avr/avr-lib.h (working copy) @@ -4,3 +4,79 @@ #define DI SI typedef int QItype __attribute__ ((mode (QI))); #endif + +/* fixed-bit.h does not define functions for TA and UTA because + that part is wrapped in #if MIN_UNITS_PER_WORD > 4. + This would lead to empty functions for TA and UTA. + Thus, supply appropriate defines as if HAVE_[U]TA == 1. + #define HAVE_[U]TA 1 won't work because avr-modes.def + uses ADJUST_BYTESIZE(TA,8) and fixed-bit.h is not generic enough + to arrange for such changes of the mode size. */ + +typedef unsigned _Fract UTAtype __attribute__ ((mode (UTA))); + +#if defined (UTA_MODE) +#define FIXED_SIZE 8 /* in bytes */ +#define INT_C_TYPE UDItype +#define UINT_C_TYPE UDItype +#define HINT_C_TYPE USItype +#define HUINT_C_TYPE USItype +#define MODE_NAME UTA +#define MODE_NAME_S uta +#define MODE_UNSIGNED 1 +#endif + +#if defined (FROM_UTA) +#define FROM_TYPE 4 /* ID for fixed-point */ +#define FROM_MODE_NAME UTA +#define FROM_MODE_NAME_S uta +#define FROM_INT_C_TYPE UDItype +#define FROM_SINT_C_TYPE DItype +#define FROM_UINT_C_TYPE UDItype +#define FROM_MODE_UNSIGNED 1 +#define FROM_FIXED_SIZE 8 /* in bytes */ +#elif defined (TO_UTA) +#define TO_TYPE 4 /* ID for fixed-point */ +#define TO_MODE_NAME UTA +#define TO_MODE_NAME_S uta +#define TO_INT_C_TYPE UDItype +#define TO_SINT_C_TYPE DItype +#define TO_UINT_C_TYPE UDItype +#define TO_MODE_UNSIGNED 1 +#define TO_FIXED_SIZE 8 /* in bytes */ +#endif + +/* Same for TAmode */ + +typedef _Fract TAtype __attribute__ ((mode (TA))); + +#if defined (TA_MODE) +#define FIXED_SIZE 8 /* in bytes */ +#define INT_C_TYPE DItype +#define UINT_C_TYPE UDItype +#define HINT_C_TYPE SItype +#define HUINT_C_TYPE USItype +#define MODE_NAME TA +#define MODE_NAME_S ta +#define MODE_UNSIGNED 0 +#endif + +#if defined (FROM_TA) +#define FROM_TYPE 4 /* ID for fixed-point */ +#define FROM_MODE_NAME TA +#define FROM_MODE_NAME_S ta +#define FROM_INT_C_TYPE DItype +#define FROM_SINT_C_TYPE DItype +#define FROM_UINT_C_TYPE UDItype +#define FROM_MODE_UNSIGNED 0 +#define FROM_FIXED_SIZE 8 /* in bytes */ +#elif defined (TO_TA) +#define TO_TYPE 4 /* ID for fixed-point */ +#define TO_MODE_NAME TA +#define TO_MODE_NAME_S ta +#define TO_INT_C_TYPE DItype +#define TO_SINT_C_TYPE DItype +#define TO_UINT_C_TYPE UDItype +#define TO_MODE_UNSIGNED 0 +#define TO_FIXED_SIZE 8 /* in bytes */ +#endif Index: libgcc/config/avr/lib1funcs-fixed.S =================================================================== --- libgcc/config/avr/lib1funcs-fixed.S (revision 0) +++ libgcc/config/avr/lib1funcs-fixed.S (revision 0) @@ -0,0 +1,1019 @@ +/* -*- Mode: Asm -*- */ +;; Copyright (C) 2012 +;; Free Software Foundation, Inc. +;; Contributed by Sean D'Epagnier (sean@depagnier.com) + +;; This file is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by the +;; Free Software Foundation; either version 3, or (at your option) any +;; later version. + +;; In addition to the permissions in the GNU General Public License, the +;; Free Software Foundation gives you unlimited permission to link the +;; compiled version of this file into combinations with other programs, +;; and to distribute those combinations without any restriction coming +;; from the use of this file. (The General Public License restrictions +;; do apply in other respects; for example, they cover modification of +;; the file, and distribution when not linked into a combine +;; executable.) + +;; This file is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Fixed point library routines for AVR +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.section .text.libgcc.fixed, "ax", @progbits + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Conversions to float +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +#if defined (L_fractqqsf) +DEFUN __fractqqsf + clr r25 + sbrc r24, 7 ; if negative + com r25 ; sign extend + mov r23, r24 ; move in place + mov r24, r25 ; sign extend lower byte + lsl r23 + clr r22 + XJMP __fractsasf ; call larger conversion +ENDF __fractqqsf +#endif /* defined (L_fractqqsf) */ + +#if defined (L_fractuqqsf) +DEFUN __fractuqqsf + clr r22 + mov r23, r24 + clr r24 + clr r25 + XJMP __fractsasf ; call larger conversion +ENDF __fractuqqsf +#endif /* defined (L_fractuqqsf) */ + +#if defined (L_fracthqsf) +DEFUN __fracthqsf + wmov 22, 24 ; put fractional part in place + clr r25 + sbrc r23, 7 ; if negative + com r25 ; sign extend + mov r24, r25 ; sign extend lower byte + lsl r22 + rol r23 + XJMP __fractsasf ; call larger conversion +ENDF __fracthqsf +#endif /* defined (L_fracthqsf) */ + +#if defined (L_fractuhqsf) +DEFUN __fractuhqsf + wmov 22, 24 ; put fractional part in place + clr r24 + clr r25 + XJMP __fractsasf ; call larger conversion +ENDF __fractuhqsf +#endif /* defined (L_fractuhqsf) */ + +#if defined (L_fracthasf) +DEFUN __fracthasf + clr r22 + mov r23, r24 ; move into place + mov r24, r25 + clr r25 + sbrc r24, 7 ; if negative + com r25 ; sign extend + XJMP __fractsasf ; call larger conversion +ENDF __fracthasf +#endif /* defined (L_fracthasf) */ + +#if defined (L_fractuhasf) +DEFUN __fractuhasf + clr r22 + mov r23, r24 ; move into place + XJMP __fractsasf ; call larger conversion +ENDF __fractuhasf +#endif /* defined (L_fractuhasf) */ + +#if defined (L_fractsasf) +DEFUN __fractsasf + XCALL __floatsisf + cpse r25, __zero_reg__ ; skip if zero + subi r25, 0x08 ; adjust exponent + ret +ENDF __fractsasf +#endif /* defined (L_fractsasf) */ + +#if defined (L_fractusasf) +DEFUN __fractusasf + XCALL __floatunsisf + cpse r25, __zero_reg__ ; skip if zero + subi r25, 0x08 ; adjust exponent + ret +ENDF __fractusasf +#endif /* defined (L_fractusasf) */ + +#if defined (L_fractsfqq) /* Conversions from float. */ +DEFUN __fractsfqq + subi r25, -11 ; adjust exponent + subi r24, 128 + XJMP __fixsfsi +ENDF __fractsfqq +#endif /* defined (L_fractqq) */ + +#if defined (L_fractsfuqq) +DEFUN __fractsfuqq + subi r25, -12 ; adjust exponent + XJMP __fixsfsi +ENDF __fractsfuqq +#endif /* defined (L_fractuqq) */ + +#if defined (L_fractsfhq) +DEFUN __fractsfhq + subi r25, -15 ; adjust exponent + subi r24, 128 + XJMP __fixsfsi +ENDF __fractsfhq +#endif /* defined (L_fractsfhq) */ + +#if defined (L_fractsfuhq) +DEFUN __fractsfuhq + subi r25, -16 ; adjust exponent + XJMP __fixsfsi +ENDF __fractsfuhq +#endif /* defined (L_fractsfuhq) */ + +#if defined (L_fractsfha) +DEFUN __fractsfha +ENDF __fractsfha + +DEFUN __fractsfuha + subi r25, -12 ; adjust exponent + XJMP __fixsfsi +ENDF __fractsfuha +#endif /* defined (L_fractsfha) */ + +#if defined (L_fractsfsa) +DEFUN __fractsfsa +ENDF __fractsfsa + +DEFUN __fractsfusa + subi r25, -8 ; adjust exponent + XJMP __fixsfsi +ENDF __fractsfsa +#endif /* defined (L_fractsfsa) */ + +/* For multiplication the functions here are called directly from + avr-fixed.md patterns, instead of using the standard libcall mechanisms. + This can make better code because GCC knows exactly which + of the call-used registers (not all of them) are clobbered. */ + +#undef r_arg1L +#undef r_arg1H +#undef r_arg2L +#undef r_arg2H +#undef r_resL +#undef r_resH + +/* mulqq and muluqq open coded on the enhanced core */ +#if !defined (__AVR_HAVE_MUL__) +/******************************************************* + Fractional Multiplication 8 x 8 +*******************************************************/ +#define r_arg2 r22 /* multiplicand */ +#define r_arg1 r24 /* multiplier */ +#define r_res __tmp_reg__ /* result */ + +#if defined (L_mulqq3) +DEFUN __mulqq3 + mov r_res, r_arg1 + eor r_res, r_arg2 + bst r_res, 7 + lsl r_arg1 + lsl r_arg2 + brcc 0f + neg r_arg2 +0: + XCALL __muluqq3 + lsr r_arg1 + brtc 1f + neg r_arg1 +1: + ret + +ENDF __mulqq3 +#endif /* defined (L_mulqq3) */ + +#if defined (L_muluqq3) +DEFUN __muluqq3 + clr r_res ; clear result +__muluqq3_loop: + lsr r_arg2 ; shift multiplicand + sbrc r_arg1,7 + add r_res,r_arg2 + breq 1f ; while multiplicand != 0 + lsl r_arg1 + brne __muluqq3_loop ; exit if multiplier = 0 +1: + mov r_arg1,r_res ; result to return register + ret +#undef r_arg2 +#undef r_arg1 +#undef r_res + +ENDF __muluqq3 +#endif /* defined (L_muluqq3) */ +#endif /* !defined (__AVR_HAVE_MUL__) */ + +/******************************************************* + Fractional Multiplication 16 x 16 +*******************************************************/ + +#if defined (__AVR_HAVE_MUL__) +#define r_arg1L r22 /* multiplier Low */ +#define r_arg1H r23 /* multiplier High */ +#define r_arg2L r20 /* multiplicand Low */ +#define r_arg2H r21 /* multiplicand High */ +#define r_resL r18 /* result Low */ +#define r_resH r19 /* result High */ + +#if defined (L_mulhq3) +DEFUN __mulhq3 + fmuls r_arg1H, r_arg2H + movw r_resL, r0 + fmulsu r_arg2H, r_arg1L + clr r_arg1L + sbc r_resH, r_arg1L + add r_resL, r1 + adc r_resH, r_arg1L + fmulsu r_arg1H, r_arg2L + sbc r_resH, r_arg1L + add r_resL, r1 + adc r_resH, r_arg1L + clr __zero_reg__ + ret +ENDF __mulhq3 +#endif /* defined (L_mulhq3) */ + +#if defined (L_muluhq3) +DEFUN __muluhq3 + mul r_arg1H, r_arg2H + movw r_resL, r0 + mul r_arg1H, r_arg2L + add r_resL, r1 + clr __zero_reg__ + adc r_resH, __zero_reg__ + mul r_arg1L, r_arg2H + add r_resL, r1 + clr __zero_reg__ + adc r_resH, __zero_reg__ + ret +ENDF __muluhq3 + +#endif /* defined (L_muluhq3) */ + +#undef r_arg1L +#undef r_arg1H +#undef r_arg2L +#undef r_arg2H +#undef r_resL +#undef r_resH + +#else /* defined (__AVR_HAVE_MUL__) */ + +#define r_arg1L 24 /* multiplier Low */ +#define r_arg1H 25 /* multiplier High */ +#define r_arg2L 22 /* multiplicand Low */ +#define r_arg2H 23 /* multiplicand High */ +#define r_resL 0 /* __tmp_reg__ result Low */ +#define r_resH 1 /* __zero_reg__ result High */ + +#if defined (L_mulhq3) +DEFUN __mulhq3 + mov r_resL, r_arg1H + eor r_resL, r_arg2H + bst r_resL, 7 + lsl r_arg1L + rol r_arg1H + lsl r_arg2L + rol r_arg2H + brcc 0f + neg2 r_arg2L +0: + XCALL __muluhq3 + lsr r_arg1H + ror r_arg1L + brtc mulhq3_exit + neg2 r_arg1L +mulhq3_exit: + ret +ENDF __mulhq3 +#endif /* defined (L_mulhq3) */ + +#if defined (L_muluhq3) +DEFUN __muluhq3 + clr r_resL ; clear result +__muluhq3_loop: + lsr r_arg2H ; shift multiplicand + ror r_arg2L + sbrs r_arg1H,7 + rjmp 0f + add r_resL,r_arg2L ; result + multiplicand + adc r_resH,r_arg2H +0: + lsl r_arg1L ; shift multiplier + rol r_arg1H + brne __muluhq3_loop + cpi r_arg1L, 0 + brne __muluhq3_loop ; exit multiplier = 0 + wmov r_arg1L,r_resL ; result to return register + clr __zero_reg__ ; zero the zero reg + ret +ENDF __muluhq3 +#endif /* defined (L_muluhq3) */ + +#undef r_arg1L +#undef r_arg1H +#undef r_arg2L +#undef r_arg2H +#undef r_resL +#undef r_resH + +#endif /* defined (__AVR_HAVE_MUL__) */ + +/******************************************************* + Fixed Multiplication 8.8 x 8.8 +*******************************************************/ + +#if defined (__AVR_HAVE_MUL__) +#define r_arg1L r22 /* multiplier Low */ +#define r_arg1H r23 /* multiplier High */ +#define r_arg2L r20 /* multiplicand Low */ +#define r_arg2H r21 /* multiplicand High */ +#define r_resL r18 /* result Low */ +#define r_resH r19 /* result High */ + +#if defined (L_mulha3) +DEFUN __mulha3 + mul r_arg1L, r_arg2L + mov r_resL, r1 + muls r_arg1H, r_arg2H + mov r_resH, r0 + mulsu r_arg1H, r_arg2L + add r_resL, r0 + adc r_resH, r1 + mulsu r_arg2H, r_arg1L + add r_resL, r0 + adc r_resH, r1 + clr __zero_reg__ + ret +ENDF __mulha3 +#endif /* defined (L_mulha3) */ + +#if defined (L_muluha3) +DEFUN __muluha3 + mul r_arg1L, r_arg2L + mov r_resL, r1 + mul r_arg1H, r_arg2H + mov r_resH, r0 + mul r_arg1H, r_arg2L + add r_resL, r0 + adc r_resH, r1 + mul r_arg1L, r_arg2H + add r_resL, r0 + adc r_resH, r1 + clr __zero_reg__ + ret +ENDF __muluha3 +#endif /* defined (L_muluha3) */ + +#undef r_arg1L +#undef r_arg1H +#undef r_arg2L +#undef r_arg2H +#undef r_resL +#undef r_resH + +#else /* defined (__AVR_HAVE_MUL__) */ + +#define r_arg1L 24 /* multiplier Low */ +#define r_arg1H 25 /* multiplier High */ +#define r_arg2L 22 /* multiplicand Low */ +#define r_arg2H 23 /* multiplicand High */ +#define r_resL 18 /* result Low */ +#define r_resH 19 /* result High */ +#define r_scratchL 0 /* scratch Low */ +#define r_scratchH 1 + +#if defined (L_mulha3) +DEFUN __mulha3 + mov r_resL, r_arg1H + eor r_resL, r_arg2H + bst r_resL, 7 + sbrs r_arg1H, 7 + rjmp 1f + neg2 r_arg1L +1: + sbrs r_arg2H, 7 + rjmp 2f + neg2 r_arg2L +2: + XCALL __muluha3 + brtc __mulha3_exit + neg2 r_resL +__mulha3_exit: + ret +ENDF __mulha3 +#endif /* defined (L_mulha3) */ + +#if defined (L_muluha3) +DEFUN __muluha3 + clr r_resL ; clear result + clr r_resH + wmov 0, r_arg1L ; save multiplicand +__muluha3_loop1: + sbrs r_arg2H,0 + rjmp 0f + add r_resL,r_arg1L ; result + multiplicand + adc r_resH,r_arg1H +0: + lsl r_arg1L ; shift multiplicand + rol r_arg1H + sbiw r_arg1L,0 + breq __muluha3_loop1_done ; exit multiplicand = 0 + lsr r_arg2H + brne __muluha3_loop1 ; exit multiplier = 0 +__muluha3_loop1_done: + wmov r_arg1L, r_scratchL ; restore multiplicand +__muluha3_loop2: + lsr r_arg1H ; shift multiplicand + ror r_arg1L + sbiw r_arg1L,0 + breq __muluha3_exit ; exit if multiplicand = 0 + sbrs r_arg2L,7 + rjmp 0f + add r_resL,r_arg1L ; result + multiplicand + adc r_resH,r_arg1H +0: + lsl r_arg2L + brne __muluha3_loop2 ; exit if multiplier = 0 +__muluha3_exit: + clr __zero_reg__ ; got clobbered + ret +ENDF __muluha3 +#endif /* defined (L_muluha3) */ + +#undef r_arg1L +#undef r_arg1H +#undef r_arg2L +#undef r_arg2H +#undef r_resL +#undef r_resH +#undef r_scratchL +#undef r_scratchH + +#endif /* defined (__AVR_HAVE_MUL__) */ + + +/******************************************************* + Fixed Multiplication 16.16 x 16.16 +*******************************************************/ + +#if defined (__AVR_HAVE_MUL__) +/* uses nonstandard registers because mulus only works from 16-23 */ +#define r_clr r15 + +#define r_arg1L r16 /* multiplier Low */ +#define r_arg1H r17 +#define r_arg1HL r18 +#define r_arg1HH r19 /* multiplier High */ + +#define r_arg2L r20 /* multiplicand Low */ +#define r_arg2H r21 +#define r_arg2HL r22 +#define r_arg2HH r23 /* multiplicand High */ + +#define r_resL r24 /* result Low */ +#define r_resH r25 +#define r_resHL r26 +#define r_resHH r27 /* result High */ + +#if defined (L_mulsa3) +DEFUN __mulsa3 + clr r_clr + clr r_resH + clr r_resHL + clr r_resHH + mul r_arg1H, r_arg2L + mov r_resL, r1 + mul r_arg1L, r_arg2H + add r_resL, r1 + adc r_resH, r_clr + mul r_arg1L, r_arg2HL + add r_resL, r0 + adc r_resH, r1 + adc r_resHL, r_clr + mul r_arg1H, r_arg2H + add r_resL, r0 + adc r_resH, r1 + adc r_resHL, r_clr + mul r_arg1HL, r_arg2L + add r_resL, r0 + adc r_resH, r1 + adc r_resHL, r_clr + mulsu r_arg2HH, r_arg1L + sbc r_resHH, r_clr + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mul r_arg1H, r_arg2HL + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mul r_arg1HL, r_arg2H + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mulsu r_arg1HH, r_arg2L + sbc r_resHH, r_clr + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mulsu r_arg2HH, r_arg1H + add r_resHL, r0 + adc r_resHH, r1 + mul r_arg1HL, r_arg2HL + add r_resHL, r0 + adc r_resHH, r1 + mulsu r_arg1HH, r_arg2H + add r_resHL, r0 + adc r_resHH, r1 + mulsu r_arg2HH, r_arg1HL + add r_resHH, r0 + mulsu r_arg1HH, r_arg2HL + add r_resHH, r0 + clr __zero_reg__ + ret +ENDF __mulsa3 +#endif /* L_mulsa3 */ + +#if defined (L_mulusa3) +DEFUN __mulusa3 + clr r_clr + clr r_resH + clr r_resHL + clr r_resHH + mul r_arg1H, r_arg2L + mov r_resL, r1 + mul r_arg1L, r_arg2H + add r_resL, r1 + adc r_resH, r_clr + mul r_arg1L, r_arg2HL + add r_resL, r0 + adc r_resH, r1 + adc r_resHL, r_clr + mul r_arg1H, r_arg2H + add r_resL, r0 + adc r_resH, r1 + adc r_resHL, r_clr + mul r_arg1HL, r_arg2L + add r_resL, r0 + adc r_resH, r1 + adc r_resHL, r_clr + mul r_arg1L, r_arg2HH + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mul r_arg1H, r_arg2HL + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mul r_arg1HL, r_arg2H + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mul r_arg1HH, r_arg2L + add r_resH, r0 + adc r_resHL, r1 + adc r_resHH, r_clr + mul r_arg1H, r_arg2HH + add r_resHL, r0 + adc r_resHH, r1 + mul r_arg1HL, r_arg2HL + add r_resHL, r0 + adc r_resHH, r1 + mul r_arg1HH, r_arg2H + add r_resHL, r0 + adc r_resHH, r1 + mul r_arg1HL, r_arg2HH + add r_resHH, r0 + mul r_arg1HH, r_arg2HL + add r_resHH, r0 + clr __zero_reg__ + ret +ENDF __mulusa3 +#endif /* L_mulusa3 */ + +#undef r_arg1L +#undef r_arg1H +#undef r_arg1HL +#undef r_arg1HH + +#undef r_arg2L +#undef r_arg2H +#undef r_arg2HL +#undef r_arg2HH + +#undef r_resL +#undef r_resH +#undef r_resHL +#undef r_resHH +#undef r_clr + +#else /* defined (__AVR_HAVE_MUL__) */ + +#define r_arg1L 18 /* multiplier Low */ +#define r_arg1H 19 +#define r_arg1HL 20 +#define r_arg1HH 21 /* multiplier High */ + +;; These registers needed for SBIW */ +#define r_arg2L 24 /* multiplicand Low */ +#define r_arg2H 25 +#define r_arg2HL 26 +#define r_arg2HH 27 /* multiplicand High */ + +#define r_resL 14 /* result Low */ +#define r_resH 15 +#define r_resHL 16 +#define r_resHH 17 /* result High */ + +#define r_scratchL 0 /* scratch Low */ +#define r_scratchH 1 +#define r_scratchHL 22 +#define r_scratchHH 23 /* scratch High */ + +#if defined (L_mulsa3) +DEFUN __mulsa3 + mov r_resL, r_arg1HH + eor r_resL, r_arg2HH + bst r_resL, 7 + sbrs r_arg1HH, 7 + rjmp 1f + neg4 r_arg1L +1: + sbrs r_arg2HH, 7 + rjmp 2f + neg4 r_arg2L +2: + XCALL __mulusa3 + brtc __mulsa3_exit + neg4 r_resL +__mulsa3_exit: + ret +ENDF __mulsa3 +#endif /* defined (L_mulsa3) */ + +#if defined (L_mulusa3) +DEFUN __mulusa3 + clr r_resL ; clear result + clr r_resH + wmov r_resHL, r_resL + wmov r_scratchL, r_arg1L ; save multiplicand + wmov r_scratchHL, r_arg1HL +__mulusa3_loop1: + sbrs r_arg2HL,0 + rjmp 0f + add r_resL,r_arg1L ; result + multiplicand + adc r_resH,r_arg1H + adc r_resHL,r_arg1HL + adc r_resHH,r_arg1HH +0: + lsl r_arg1L ; shift multiplicand + rol r_arg1H + rol r_arg1HL + rol r_arg1HH + lsr r_arg2HH + ror r_arg2HL + sbiw r_arg2HL,0 + brne __mulusa3_loop1 ; exit multiplier = 0 + wmov r_arg1L, r_scratchL ; restore multiplicand + wmov r_arg1HL, r_scratchHL +__mulusa3_loop2: + lsr r_arg1HH ; shift multiplicand + ror r_arg1HL + ror r_arg1H + ror r_arg1L + sbrs r_arg2H,7 + rjmp 1f + add r_resL,r_arg1L ; result + multiplicand + adc r_resH,r_arg1H + adc r_resHL,r_arg1HL + adc r_resHH,r_arg1HH +1: + lsl r_arg2L + rol r_arg2H + sbiw r_arg2L,0 + brne __mulusa3_loop2 ; exit if multiplier = 0 + clr __zero_reg__ ; got clobbered + ret +ENDF __mulusa3 +#endif /* defined (L_mulusa3) */ + +#undef r_scratchL +#undef r_scratchH +#undef r_scratchHL +#undef r_scratchHH + +#undef r_arg1L +#undef r_arg1H +#undef r_arg1HL +#undef r_arg1HH + +#undef r_arg2L +#undef r_arg2H +#undef r_arg2HL +#undef r_arg2HH + +#undef r_resL +#undef r_resH +#undef r_resHL +#undef r_resHH + +#endif /* defined (__AVR_HAVE_MUL__) */ + +/******************************************************* + Fractional Division 8 / 8 +*******************************************************/ + +#define r_divd r25 /* dividend */ +#define r_quo r24 /* quotient */ +#define r_div r22 /* divisor */ + +#if defined (L_divqq3) +DEFUN __divqq3 + mov r0, r_divd + eor r0, r_div + sbrc r_div, 7 + neg r_div + sbrc r_divd, 7 + neg r_divd + cp r_divd, r_div + breq __divqq3_minus1 ; if equal return -1 + XCALL __udivuqq3 + lsr r_quo + sbrc r0, 7 ; negate result if needed + neg r_quo + ret +__divqq3_minus1: + ldi r_quo, 0x80 + ret +ENDF __divqq3 +#endif /* defined (L_divqq3) */ + +#if defined (L_udivuqq3) +DEFUN __udivuqq3 + clr r_quo ; clear quotient + inc __zero_reg__ ; init loop counter, used per shift +__udivuqq3_loop: + lsl r_divd ; shift dividend + brcs 0f ; dividend overflow + cp r_divd,r_div ; compare dividend & divisor + brcc 0f ; dividend >= divisor + rol r_quo ; shift quotient (with CARRY) + rjmp __udivuqq3_cont +0: + sub r_divd,r_div ; restore dividend + lsl r_quo ; shift quotient (without CARRY) +__udivuqq3_cont: + lsl __zero_reg__ ; shift loop-counter bit + brne __udivuqq3_loop + com r_quo ; complement result + ; because C flag was complemented in loop + ret +ENDF __udivuqq3 +#endif /* defined (L_udivuqq3) */ + +#undef r_divd +#undef r_quo +#undef r_div + + +/******************************************************* + Fractional Division 16 / 16 +*******************************************************/ +#define r_divdL 26 /* dividend Low */ +#define r_divdH 27 /* dividend Hig */ +#define r_quoL 24 /* quotient Low */ +#define r_quoH 25 /* quotient High */ +#define r_divL 22 /* divisor */ +#define r_divH 23 /* divisor */ +#define r_cnt 21 + +#if defined (L_divhq3) +DEFUN __divhq3 + mov r0, r_divdH + eor r0, r_divH + sbrs r_divH, 7 + rjmp 1f + neg2 r_divL +1: + sbrs r_divdH, 7 + rjmp 2f + neg2 r_divdL +2: + cp r_divdL, r_divL + cpc r_divdH, r_divH + breq __divhq3_minus1 ; if equal return -1 + XCALL __udivuhq3 + lsr r_quoH + ror r_quoL + brpl 9f + ;; negate result if needed + neg2 r_quoL +9: + ret +__divhq3_minus1: + ldi r_quoH, 0x80 + clr r_quoL + ret +ENDF __divhq3 +#endif /* defined (L_divhq3) */ + +#if defined (L_udivuhq3) +DEFUN __udivuhq3 + sub r_quoH,r_quoH ; clear quotient and carry + ;; FALLTHRU +ENDF __udivuhq3 + +DEFUN __udivuha3_common + clr r_quoL ; clear quotient + ldi r_cnt,16 ; init loop counter +__udivuhq3_loop: + rol r_divdL ; shift dividend (with CARRY) + rol r_divdH + brcs __udivuhq3_ep ; dividend overflow + cp r_divdL,r_divL ; compare dividend & divisor + cpc r_divdH,r_divH + brcc __udivuhq3_ep ; dividend >= divisor + rol r_quoL ; shift quotient (with CARRY) + rjmp __udivuhq3_cont +__udivuhq3_ep: + sub r_divdL,r_divL ; restore dividend + sbc r_divdH,r_divH + lsl r_quoL ; shift quotient (without CARRY) +__udivuhq3_cont: + rol r_quoH ; shift quotient + dec r_cnt ; decrement loop counter + brne __udivuhq3_loop + com r_quoL ; complement result + com r_quoH ; because C flag was complemented in loop + ret +ENDF __udivuha3_common +#endif /* defined (L_udivuhq3) */ + +/******************************************************* + Fixed Division 8.8 / 8.8 +*******************************************************/ +#if defined (L_divha3) +DEFUN __divha3 + mov r0, r_divdH + eor r0, r_divH + sbrs r_divH, 7 + rjmp 1f + neg2 r_divL +1: + sbrs r_divdH, 7 + rjmp 2f + neg2 r_divdL +2: + XCALL __udivuha3 + sbrs r0, 7 ; negate result if needed + ret + neg2 r_quoL + ret +ENDF __divha3 +#endif /* defined (L_divha3) */ + +#if defined (L_udivuha3) +DEFUN __udivuha3 + mov r_quoH, r_divdL + mov r_divdL, r_divdH + clr r_divdH + lsl r_quoH ; shift quotient into carry + XJMP __udivuha3_common ; same as fractional after rearrange +ENDF __udivuha3 +#endif /* defined (L_udivuha3) */ + +#undef r_divdL +#undef r_divdH +#undef r_quoL +#undef r_quoH +#undef r_divL +#undef r_divH +#undef r_cnt + +/******************************************************* + Fixed Division 16.16 / 16.16 +*******************************************************/ + +#define r_arg1L 24 /* arg1 gets passed already in place */ +#define r_arg1H 25 +#define r_arg1HL 26 +#define r_arg1HH 27 +#define r_divdL 26 /* dividend Low */ +#define r_divdH 27 +#define r_divdHL 30 +#define r_divdHH 31 /* dividend High */ +#define r_quoL 22 /* quotient Low */ +#define r_quoH 23 +#define r_quoHL 24 +#define r_quoHH 25 /* quotient High */ +#define r_divL 18 /* divisor Low */ +#define r_divH 19 +#define r_divHL 20 +#define r_divHH 21 /* divisor High */ +#define r_cnt __zero_reg__ /* loop count (0 after the loop!) */ + +#if defined (L_divsa3) +DEFUN __divsa3 + mov r0, r_arg1HH + eor r0, r_divHH + sbrs r_divHH, 7 + rjmp 1f + neg4 r_divL +1: + sbrs r_arg1HH, 7 + rjmp 2f + neg4 r_arg1L +2: + XCALL __udivusa3 + sbrs r0, 7 ; negate result if needed + ret + neg4 r_quoL + ret +ENDF __divsa3 +#endif /* defined (L_divsa3) */ + +#if defined (L_udivusa3) +DEFUN __udivusa3 + ldi r_divdHL, 32 ; init loop counter + mov r_cnt, r_divdHL + clr r_divdHL + clr r_divdHH + wmov r_quoL, r_divdHL + lsl r_quoHL ; shift quotient into carry + rol r_quoHH +__udivusa3_loop: + rol r_divdL ; shift dividend (with CARRY) + rol r_divdH + rol r_divdHL + rol r_divdHH + brcs __udivusa3_ep ; dividend overflow + cp r_divdL,r_divL ; compare dividend & divisor + cpc r_divdH,r_divH + cpc r_divdHL,r_divHL + cpc r_divdHH,r_divHH + brcc __udivusa3_ep ; dividend >= divisor + rol r_quoL ; shift quotient (with CARRY) + rjmp __udivusa3_cont +__udivusa3_ep: + sub r_divdL,r_divL ; restore dividend + sbc r_divdH,r_divH + sbc r_divdHL,r_divHL + sbc r_divdHH,r_divHH + lsl r_quoL ; shift quotient (without CARRY) +__udivusa3_cont: + rol r_quoH ; shift quotient + rol r_quoHL + rol r_quoHH + dec r_cnt ; decrement loop counter + brne __udivusa3_loop + com r_quoL ; complement result + com r_quoH ; because C flag was complemented in loop + com r_quoHL + com r_quoHH + ret +ENDF __udivusa3 +#endif /* defined (L_udivusa3) */ + +#undef r_divdL +#undef r_divdH +#undef r_divdHL +#undef r_divdHH +#undef r_quoL +#undef r_quoH +#undef r_quoHL +#undef r_quoHH +#undef r_divL +#undef r_divH +#undef r_divHL +#undef r_divHH +#undef r_cnt Index: libgcc/config/avr/lib1funcs.S =================================================================== --- libgcc/config/avr/lib1funcs.S (revision 190299) +++ libgcc/config/avr/lib1funcs.S (working copy) @@ -91,6 +91,32 @@ see the files COPYING3 and COPYING.RUNTI .endfunc .endm +;; Negate a 2-byte value held in consecutive registers +.macro neg2 reg + com \reg+1 + neg \reg + sbci \reg+1, -1 +.endm + +;; Negate a 4-byte value held in consecutive registers +.macro neg4 reg + com \reg+3 + com \reg+2 + com \reg+1 +.if \reg >= 16 + neg \reg + sbci \reg+1, -1 + sbci \reg+2, -1 + sbci \reg+3, -1 +.else + com \reg + adc \reg, __zero_reg__ + adc \reg+1, __zero_reg__ + adc \reg+2, __zero_reg__ + adc \reg+3, __zero_reg__ +.endif +.endm + .section .text.libgcc.mul, "ax", @progbits @@ -1247,6 +1273,22 @@ __divmodsi4_exit: ENDF __divmodsi4 #endif /* defined (L_divmodsi4) */ +#undef r_remHH +#undef r_remHL +#undef r_remH +#undef r_remL + +#undef r_arg1HH +#undef r_arg1HL +#undef r_arg1H +#undef r_arg1L + +#undef r_arg2HH +#undef r_arg2HL +#undef r_arg2H +#undef r_arg2L + +#undef r_cnt /******************************************************* Division 64 / 64 @@ -2794,3 +2836,5 @@ ENDF __fmul #undef B1 #undef C0 #undef C1 + +#include "lib1funcs-fixed.S" Index: libgcc/config/avr/t-avr =================================================================== --- libgcc/config/avr/t-avr (revision 190299) +++ libgcc/config/avr/t-avr (working copy) @@ -55,6 +55,24 @@ LIB1ASMFUNCS = \ _cmpdi2 _cmpdi2_s8 \ _fmul _fmuls _fmulsu +# Fixed point routines in avr/lib1funcs-fixed.S +LIB1ASMFUNCS += \ + _fractqqsf _fractuqqsf \ + _fracthqsf _fractuhqsf \ + _fracthasf _fractuhasf \ + _fractsasf _fractusasf \ + _fractsfqq _fractsfuqq \ + _fractsfhq _fractsfuhq \ + _fractsfha _fractsfsa \ + _mulqq3 _muluqq3 \ + _mulhq3 _muluhq3 \ + _mulha3 _muluha3 \ + _mulsa3 _mulusa3 \ + _divqq3 _udivuqq3 \ + _divhq3 _udivuhq3 \ + _divha3 _udivuha3 \ + _divsa3 _udivusa3 + LIB2FUNCS_EXCLUDE = \ _moddi3 _umoddi3 \ _clz