OSDN Git Service

* config/rx/rx.md (simple_return): Use the simple_return rtx.
[pf3gnuchains/gcc-fork.git] / gcc / config / avr / avr-dimode.md
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)
6 ;;
7 ;; This file is part of GCC.
8 ;;
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)
12 ;; any later version.
13 ;;
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.
18 ;;
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/>.
22
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24
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.
31 ;;
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
34 ;; introducing movdi.
35 ;; 
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
40 ;;
41 ;;    A[] = reg:DI 18
42 ;;    B[] = reg:DI 10
43 ;;
44 ;; so that no DImode insn contains pseudos or needs reloading.
45
46 (define_constants
47   [(ACC_A       18)
48    (ACC_B       10)])
49
50 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
51 ;; Addition
52 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
53
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" "")])]
58   "avr_have_dimode"
59   {
60     rtx acc_a = gen_rtx_REG (DImode, ACC_A);
61
62     emit_move_insn (acc_a, operands[1]);
63
64     if (s8_operand (operands[2], VOIDmode))
65       {
66         emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
67         emit_insn (gen_adddi3_const8_insn ());
68       }        
69     else if (CONST_INT_P (operands[2])
70              || CONST_DOUBLE_P (operands[2]))
71       {
72         emit_insn (gen_adddi3_const_insn (operands[2]));
73       }
74     else
75       {
76         emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
77         emit_insn (gen_adddi3_insn ());
78       }
79
80     emit_move_insn (operands[0], acc_a);
81     DONE;
82   })
83
84 (define_insn "adddi3_insn"
85   [(set (reg:DI ACC_A)
86         (plus:DI (reg:DI ACC_A)
87                  (reg:DI ACC_B)))]
88   "avr_have_dimode"
89   "%~call __adddi3"
90   [(set_attr "adjust_len" "call")
91    (set_attr "cc" "clobber")])
92
93 (define_insn "adddi3_const8_insn"
94   [(set (reg:DI ACC_A)
95         (plus:DI (reg:DI ACC_A)
96                  (sign_extend:DI (reg:QI REG_X))))]
97   "avr_have_dimode"
98   "%~call __adddi3_s8"
99   [(set_attr "adjust_len" "call")
100    (set_attr "cc" "clobber")])
101
102 (define_insn "adddi3_const_insn"
103   [(set (reg:DI ACC_A)
104         (plus:DI (reg:DI ACC_A)
105                  (match_operand:DI 0 "const_double_operand" "n")))]
106   "avr_have_dimode
107    && !s8_operand (operands[0], VOIDmode)"
108   {
109     return avr_out_plus64 (operands[0], NULL);
110   }
111   [(set_attr "adjust_len" "plus64")
112    (set_attr "cc" "clobber")])
113
114
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
116 ;; Subtraction
117 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118
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" "")])]
123   "avr_have_dimode"
124   {
125     rtx acc_a = gen_rtx_REG (DImode, ACC_A);
126
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);
131     DONE;
132   })
133
134 (define_insn "subdi3_insn"
135   [(set (reg:DI ACC_A)
136         (minus:DI (reg:DI ACC_A)
137                   (reg:DI ACC_B)))]
138   "avr_have_dimode"
139   "%~call __subdi3"
140   [(set_attr "adjust_len" "call")
141    (set_attr "cc" "set_czn")])
142
143
144 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
145 ;; Negation
146 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
147
148 (define_expand "negdi2"
149   [(parallel [(match_operand:DI 0 "general_operand" "")
150               (match_operand:DI 1 "general_operand" "")])]
151   "avr_have_dimode"
152   {
153     rtx acc_a = gen_rtx_REG (DImode, ACC_A);
154
155     emit_move_insn (acc_a, operands[1]);
156     emit_insn (gen_negdi2_insn ());
157     emit_move_insn (operands[0], acc_a);
158     DONE;
159   })
160
161 (define_insn "negdi2_insn"
162   [(set (reg:DI ACC_A)
163         (neg:DI (reg:DI ACC_A)))]
164   "avr_have_dimode"
165   "%~call __negdi2"
166   [(set_attr "adjust_len" "call")
167    (set_attr "cc" "clobber")])
168
169
170 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
171 ;; Comparison
172 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
173
174 (define_expand "conditional_jump"
175   [(set (pc)
176         (if_then_else
177          (match_operator 0 "ordered_comparison_operator" [(cc0)
178                                                           (const_int 0)])
179          (label_ref (match_operand 1 "" ""))
180          (pc)))]
181   "avr_have_dimode")
182
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)
187                                                                (const_int 0)])
188               (label_ref (match_operand 3 "" ""))])]
189   "avr_have_dimode"
190   {
191     rtx acc_a = gen_rtx_REG (DImode, ACC_A);
192
193     emit_move_insn (acc_a, operands[1]);
194
195     if (s8_operand (operands[2], VOIDmode))
196       {
197         emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
198         emit_insn (gen_compare_const8_di2 ());
199       }        
200     else if (CONST_INT_P (operands[2])
201              || CONST_DOUBLE_P (operands[2]))
202       {
203         emit_insn (gen_compare_const_di2 (operands[2]));
204       }
205     else
206       {
207         emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
208         emit_insn (gen_compare_di2 ());
209       }
210
211     emit_jump_insn (gen_conditional_jump (operands[0], operands[3]));
212     DONE;
213   })
214
215 (define_insn "compare_di2"
216   [(set (cc0)
217         (compare (reg:DI ACC_A)
218                  (reg:DI ACC_B)))]
219   "avr_have_dimode"
220   "%~call __cmpdi2"
221   [(set_attr "adjust_len" "call")
222    (set_attr "cc" "compare")])
223
224 (define_insn "compare_const8_di2"
225   [(set (cc0)
226         (compare (reg:DI ACC_A)
227                  (sign_extend:DI (reg:QI REG_X))))]
228   "avr_have_dimode"
229   "%~call __cmpdi2_s8"
230   [(set_attr "adjust_len" "call")
231    (set_attr "cc" "compare")])
232
233 (define_insn "compare_const_di2"
234   [(set (cc0)
235         (compare (reg:DI ACC_A)
236                  (match_operand:DI 0 "const_double_operand" "n")))
237    (clobber (match_scratch:QI 1 "=&d"))]
238   "avr_have_dimode
239    && !s8_operand (operands[0], VOIDmode)"
240   {
241     return avr_out_compare64 (insn, operands, NULL);
242   }
243   [(set_attr "adjust_len" "compare64")
244    (set_attr "cc" "compare")])
245
246
247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
248 ;; Shifts and Rotate
249 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
250
251 (define_code_iterator di_shifts
252   [ashift ashiftrt lshiftrt rotate])
253
254 ;; Shift functions from libgcc are called without defining these insns,
255 ;; but with them we can describe their reduced register footprint.
256
257 ;; "ashldi3"
258 ;; "ashrdi3"
259 ;; "lshrdi3"
260 ;; "rotldi3"
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" ""))])]
265   "avr_have_dimode"
266   {
267     rtx acc_a = gen_rtx_REG (DImode, ACC_A);
268
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);
273     DONE;
274   })
275
276 (define_insn "<code_stdname>di3_insn"
277   [(set (reg:DI ACC_A)
278         (di_shifts:DI (reg:DI ACC_A)
279                       (reg:QI 16)))]
280   "avr_have_dimode"
281   "%~call __<code_stdname>di3"
282   [(set_attr "adjust_len" "call")
283    (set_attr "cc" "clobber")])