1 ;; Machine description for GNU compiler,
2 ;; for Atmel AVR micro controllers.
3 ;; Copyright (C) 1998 - 2011
4 ;; Free Software Foundation, Inc.
5 ;; Contributed by Georg Lay (avr@gjlay.de)
7 ;; This file is part of GCC.
9 ;; GCC is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; GCC is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GCC; see the file COPYING3. If not see
21 ;; <http://www.gnu.org/licenses/>.
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25 ;; The purpose of this file is to provide a light-weight DImode
26 ;; implementation for AVR. The trouble with DImode is that tree -> RTL
27 ;; lowering leads to really unpleasant code for operations that don't
28 ;; work byte-wise like NEG, PLUS, MINUS, etc. Defining optabs entries for
29 ;; them won't help because the optab machinery assumes these operations
30 ;; are cheap and does not check if a libgcc implementation is available.
32 ;; The DImode insns are all straight forward -- except movdi. The approach
33 ;; of this implementation is to provide DImode insns without the burden of
36 ;; The caveat is that if there are insns for some mode, there must also be a
37 ;; respective move insn that describes reloads. Therefore, this
38 ;; implementation uses an accumulator-based model with two hard-coded,
39 ;; accumulator-like registers
44 ;; so that no DImode insn contains pseudos or needs reloading.
50 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
52 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
54 (define_expand "adddi3"
55 [(parallel [(match_operand:DI 0 "general_operand" "")
56 (match_operand:DI 1 "general_operand" "")
57 (match_operand:DI 2 "general_operand" "")])]
60 rtx acc_a = gen_rtx_REG (DImode, ACC_A);
62 emit_move_insn (acc_a, operands[1]);
64 if (s8_operand (operands[2], VOIDmode))
66 emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
67 emit_insn (gen_adddi3_const8_insn ());
69 else if (CONST_INT_P (operands[2])
70 || CONST_DOUBLE_P (operands[2]))
72 emit_insn (gen_adddi3_const_insn (operands[2]));
76 emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
77 emit_insn (gen_adddi3_insn ());
80 emit_move_insn (operands[0], acc_a);
84 (define_insn "adddi3_insn"
86 (plus:DI (reg:DI ACC_A)
90 [(set_attr "adjust_len" "call")
91 (set_attr "cc" "clobber")])
93 (define_insn "adddi3_const8_insn"
95 (plus:DI (reg:DI ACC_A)
96 (sign_extend:DI (reg:QI REG_X))))]
99 [(set_attr "adjust_len" "call")
100 (set_attr "cc" "clobber")])
102 (define_insn "adddi3_const_insn"
104 (plus:DI (reg:DI ACC_A)
105 (match_operand:DI 0 "const_double_operand" "n")))]
107 && !s8_operand (operands[0], VOIDmode)"
109 return avr_out_plus64 (operands[0], NULL);
111 [(set_attr "adjust_len" "plus64")
112 (set_attr "cc" "clobber")])
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
117 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
119 (define_expand "subdi3"
120 [(parallel [(match_operand:DI 0 "general_operand" "")
121 (match_operand:DI 1 "general_operand" "")
122 (match_operand:DI 2 "general_operand" "")])]
125 rtx acc_a = gen_rtx_REG (DImode, ACC_A);
127 emit_move_insn (acc_a, operands[1]);
128 emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
129 emit_insn (gen_subdi3_insn ());
130 emit_move_insn (operands[0], acc_a);
134 (define_insn "subdi3_insn"
136 (minus:DI (reg:DI ACC_A)
140 [(set_attr "adjust_len" "call")
141 (set_attr "cc" "set_czn")])
144 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
146 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
148 (define_expand "negdi2"
149 [(parallel [(match_operand:DI 0 "general_operand" "")
150 (match_operand:DI 1 "general_operand" "")])]
153 rtx acc_a = gen_rtx_REG (DImode, ACC_A);
155 emit_move_insn (acc_a, operands[1]);
156 emit_insn (gen_negdi2_insn ());
157 emit_move_insn (operands[0], acc_a);
161 (define_insn "negdi2_insn"
163 (neg:DI (reg:DI ACC_A)))]
166 [(set_attr "adjust_len" "call")
167 (set_attr "cc" "clobber")])
170 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
174 (define_expand "conditional_jump"
177 (match_operator 0 "ordered_comparison_operator" [(cc0)
179 (label_ref (match_operand 1 "" ""))
183 (define_expand "cbranchdi4"
184 [(parallel [(match_operand:DI 1 "register_operand" "")
185 (match_operand:DI 2 "nonmemory_operand" "")
186 (match_operator 0 "ordered_comparison_operator" [(cc0)
188 (label_ref (match_operand 3 "" ""))])]
191 rtx acc_a = gen_rtx_REG (DImode, ACC_A);
193 emit_move_insn (acc_a, operands[1]);
195 if (s8_operand (operands[2], VOIDmode))
197 emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
198 emit_insn (gen_compare_const8_di2 ());
200 else if (CONST_INT_P (operands[2])
201 || CONST_DOUBLE_P (operands[2]))
203 emit_insn (gen_compare_const_di2 (operands[2]));
207 emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
208 emit_insn (gen_compare_di2 ());
211 emit_jump_insn (gen_conditional_jump (operands[0], operands[3]));
215 (define_insn "compare_di2"
217 (compare (reg:DI ACC_A)
221 [(set_attr "adjust_len" "call")
222 (set_attr "cc" "compare")])
224 (define_insn "compare_const8_di2"
226 (compare (reg:DI ACC_A)
227 (sign_extend:DI (reg:QI REG_X))))]
230 [(set_attr "adjust_len" "call")
231 (set_attr "cc" "compare")])
233 (define_insn "compare_const_di2"
235 (compare (reg:DI ACC_A)
236 (match_operand:DI 0 "const_double_operand" "n")))
237 (clobber (match_scratch:QI 1 "=&d"))]
239 && !s8_operand (operands[0], VOIDmode)"
241 return avr_out_compare64 (insn, operands, NULL);
243 [(set_attr "adjust_len" "compare64")
244 (set_attr "cc" "compare")])
247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
249 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
251 (define_code_iterator di_shifts
252 [ashift ashiftrt lshiftrt rotate])
254 ;; Shift functions from libgcc are called without defining these insns,
255 ;; but with them we can describe their reduced register footprint.
261 (define_expand "<code_stdname>di3"
262 [(parallel [(match_operand:DI 0 "general_operand" "")
263 (di_shifts:DI (match_operand:DI 1 "general_operand" "")
264 (match_operand:QI 2 "general_operand" ""))])]
267 rtx acc_a = gen_rtx_REG (DImode, ACC_A);
269 emit_move_insn (acc_a, operands[1]);
270 emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]);
271 emit_insn (gen_<code_stdname>di3_insn ());
272 emit_move_insn (operands[0], acc_a);
276 (define_insn "<code_stdname>di3_insn"
278 (di_shifts:DI (reg:DI ACC_A)
281 "%~call __<code_stdname>di3"
282 [(set_attr "adjust_len" "call")
283 (set_attr "cc" "clobber")])