]>
Commit | Line | Data |
---|---|---|
b9fdd12b | 1 | ;; GCC machine description for CR16. |
aad93da1 | 2 | ;; Copyright (C) 2012-2017 Free Software Foundation, Inc. |
b9fdd12b | 3 | ;; Contributed by KPIT Cummins Infosystems Limited. |
4 | ||
5 | ;; This file is part of GCC. | |
6 | ||
7 | ;; GCC is free software; you can redistribute it and/or modify it | |
8 | ;; under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation; either version 3, or (at your option) | |
10 | ;; any later version. | |
11 | ||
12 | ;; GCC is distributed in the hope that it will be useful, but WITHOUT | |
13 | ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
15 | ;; License for more details. | |
16 | ||
17 | ;; You should have received a copy of the GNU General Public License | |
18 | ;; along with GCC; see the file COPYING3. If not see | |
19 | ;; <http://www.gnu.org/licenses/>. | |
20 | ||
21 | ;; Register numbers | |
22 | (define_constants | |
23 | [(SP_REGNUM 15); Stack pointer | |
24 | (RA_REGNUM 14); Return address | |
25 | ] | |
26 | ) | |
27 | ||
28 | ;; Predicates & Constraints | |
29 | (include "predicates.md") | |
30 | (include "constraints.md") | |
31 | ||
32 | ;; UNSPEC usage | |
33 | (define_constants | |
34 | [(UNSPEC_PIC_ADDR 0) | |
35 | (UNSPEC_PIC_LOAD_ADDR 1) | |
36 | (UNSPEC_LIBRARY_OFFSET 2) | |
37 | (UNSPEC_SH_LIB_PUSH_R12 3) | |
38 | (UNSPEC_SH_LIB_POP_R12 4) | |
39 | (UNSPEC_RETURN_ADDR 5) | |
40 | ] | |
41 | ) | |
42 | ||
43 | ;; Attributes | |
44 | (define_attr "length" "" (const_int 2)) | |
45 | ||
46 | (define_asm_attributes | |
47 | [(set_attr "length" "2")] | |
48 | ) | |
49 | ||
50 | ;; Mode Macro Definitions | |
51 | (define_mode_iterator CR16IM [QI HI SI]) | |
52 | (define_mode_iterator LONG [SI SF]) | |
53 | (define_mode_iterator ALLMTD [QI HI SI SF DI DF]) | |
54 | (define_mode_iterator DOUBLE [DI DF]) | |
55 | (define_mode_iterator SHORT [QI HI]) | |
56 | (define_mode_attr tIsa [(QI "b") (HI "w") (SI "d") (SF "d")]) | |
57 | (define_mode_attr lImmArith [(QI "4") (HI "4") (SI "6") (SF "6")]) | |
58 | (define_mode_attr lImmArithD [(QI "4") (HI "4") (SI "6") (SF "6") (DI "12") (DF "12")]) | |
59 | (define_mode_attr iF [(QI "i") (HI "i") (SI "i") (SF "F")]) | |
60 | (define_mode_attr iFD [(DI "i") (DF "F")]) | |
61 | (define_mode_attr LL [(QI "L") (HI "L")]) | |
62 | (define_mode_attr shImmBits [(QI "3") (HI "4") (SI "5")]) | |
63 | ||
64 | ; In QI mode we push 2 bytes instead of 1 byte. | |
65 | (define_mode_attr pushCnstr [(QI "X") (HI "<") (SI "<") (SF "<") (DI "<") (DF "<")]) | |
66 | ||
67 | ; tpush will be used to generate the 'number of registers to push' in the | |
68 | ; push instruction. | |
69 | (define_mode_attr tpush [(QI "1") (HI "1") (SI "2") (SF "2") (DI "4") (DF "4")]) | |
70 | ||
71 | ;; Code Macro Definitions | |
72 | (define_code_attr sIsa [(sign_extend "") (zero_extend "u")]) | |
73 | (define_code_attr sPat [(sign_extend "s") (zero_extend "u")]) | |
74 | (define_code_attr szPat [(sign_extend "") (zero_extend "zero_")]) | |
75 | (define_code_attr szIsa [(sign_extend "x") (zero_extend "z")]) | |
76 | ||
77 | (define_code_iterator sz_xtnd [ sign_extend zero_extend]) | |
78 | (define_code_iterator any_cond [eq ne gt gtu lt ltu ge geu le leu]) | |
79 | (define_code_iterator plusminus [plus minus]) | |
80 | ||
81 | (define_code_attr plusminus_insn [(plus "add") (minus "sub")]) | |
82 | (define_code_attr plusminus_flag [(plus "PLUS") (minus "MINUS")]) | |
83 | (define_code_attr comm [(plus "%") (minus "")]) | |
84 | ||
85 | (define_code_iterator any_logic [and ior xor]) | |
86 | (define_code_attr logic [(and "and") (ior "or") (xor "xor")]) | |
87 | (define_code_attr any_logic_insn [(and "and") (ior "ior") (xor "xor")]) | |
88 | (define_code_attr any_logic_flag [(and "AND") (ior "IOR") (xor "XOR")]) | |
89 | ||
90 | (define_mode_iterator QH [QI HI]) | |
91 | (define_mode_attr qh [(QI "qi") (HI "hi")]) | |
92 | (define_mode_attr QHsz [(QI "2,2,2") (HI "2,2,4")]) | |
93 | (define_mode_attr QHsuffix [(QI "b") (HI "w")]) | |
94 | ||
95 | ||
96 | ;; Function Prologue and Epilogue | |
97 | (define_expand "prologue" | |
98 | [(const_int 0)] | |
99 | "" | |
100 | { | |
101 | cr16_expand_prologue (); | |
102 | DONE; | |
103 | } | |
104 | ) | |
105 | ||
106 | (define_insn "push_for_prologue" | |
107 | [(set (reg:SI SP_REGNUM) | |
108 | (minus:SI (reg:SI SP_REGNUM) | |
109 | (match_operand:SI 0 "immediate_operand" "i")))] | |
110 | "reload_completed" | |
111 | { | |
112 | return cr16_prepare_push_pop_string (0); | |
113 | } | |
114 | [(set_attr "length" "4")] | |
115 | ) | |
116 | ||
117 | (define_expand "epilogue" | |
118 | [(return)] | |
119 | "" | |
120 | { | |
121 | cr16_expand_epilogue (); | |
122 | DONE; | |
123 | } | |
124 | ) | |
125 | ||
126 | (define_insn "pop_and_popret_return" | |
127 | [(set (reg:SI SP_REGNUM) | |
128 | (plus:SI (reg:SI SP_REGNUM) | |
129 | (match_operand:SI 0 "immediate_operand" "i"))) | |
130 | (use (reg:SI RA_REGNUM)) | |
131 | (return)] | |
132 | "reload_completed" | |
133 | { | |
134 | return cr16_prepare_push_pop_string (1); | |
135 | } | |
136 | [(set_attr "length" "4")] | |
137 | ) | |
138 | ||
139 | (define_insn "popret_RA_return" | |
140 | [(use (reg:SI RA_REGNUM)) | |
141 | (return)] | |
142 | "reload_completed" | |
143 | "popret\tra" | |
144 | [(set_attr "length" "2")] | |
145 | ) | |
146 | ||
9d75589a | 147 | ;; Arithmetic Instruction Patterns |
b9fdd12b | 148 | |
149 | ;; Addition-Subtraction "adddi3/subdi3" insns. | |
150 | (define_insn "<plusminus_insn>di3" | |
151 | [(set (match_operand:DI 0 "register_operand" "=r") | |
152 | (plusminus:DI (match_operand:DI 1 "register_operand" "<comm>0") | |
153 | (match_operand:DI 2 "register_operand" "r")))] | |
154 | "" | |
155 | { | |
156 | return cr16_emit_add_sub_di (operands, <plusminus_flag>); | |
157 | }) | |
158 | ||
159 | (define_insn "addsi3" | |
160 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") | |
161 | (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0") | |
162 | (match_operand:SI 2 "reg_si_int_operand" "r,M,N,O,i")))] | |
163 | "" | |
164 | "addd\t%2, %0" | |
165 | [(set_attr "length" "2,2,4,4,6")] | |
166 | ) | |
167 | ||
168 | ;; Addition-Subtraction "addhi3/subhi3" insns. | |
169 | (define_insn "<plusminus_insn>hi3" | |
170 | [(set (match_operand:HI 0 "register_operand" "=c,c,c") | |
171 | (plusminus:HI (match_operand:HI 1 "register_operand" "<comm>0,0,0") | |
172 | (match_operand:HI 2 "reg_hi_int_operand" "c,M,N")))] | |
173 | "" | |
174 | "<plusminus_insn>w\t%2, %0" | |
175 | [(set_attr "length" "2,2,4")] | |
176 | ) | |
177 | ||
178 | ;; Addition-Subtraction "addqi3/subqi3" insns. | |
179 | (define_insn "<plusminus_insn>qi3" | |
180 | [(set (match_operand:QI 0 "register_operand" "=c,c") | |
181 | (plusminus:QI (match_operand:QI 1 "register_operand" "<comm>0,0") | |
182 | (match_operand:QI 2 "reg_qi_int_operand" "c,M")))] | |
183 | "" | |
184 | "<plusminus_insn>b\t%2, %0" | |
185 | [(set_attr "length" "2,2")] | |
186 | ) | |
187 | ||
188 | ;; Subtract Instruction | |
189 | (define_insn "subsi3" | |
190 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
191 | (minus:SI (match_operand:SI 1 "register_operand" "0,0") | |
192 | (match_operand:SI 2 "reg_si_int_operand" "r,i")))] | |
193 | "" | |
194 | "subd\t%2, %0" | |
195 | [(set_attr "length" "4,6")] | |
196 | ) | |
197 | ||
198 | ;; Multiply and Accumulate Instructions "smachisi3/umachisi3" | |
199 | (define_insn "<sPat>maddhisi4" | |
200 | [(set (match_operand:SI 0 "register_operand" "=r") | |
201 | (plus:SI | |
202 | (mult:SI (sz_xtnd:SI (match_operand:HI 1 "register_operand" "r")) | |
203 | (sz_xtnd:SI (match_operand:HI 2 "register_operand" "r"))) | |
204 | (match_operand:SI 3 "register_operand" "0")))] | |
205 | "TARGET_MAC" | |
206 | "mac<sPat>w\t%1, %2, %0" | |
207 | [(set_attr "length" "2")] | |
208 | ) | |
209 | ||
210 | ;; Multiply Instructions | |
211 | (define_insn "mulhi3" | |
212 | [(set (match_operand:HI 0 "register_operand" "=c,c,c") | |
213 | (mult:HI (match_operand:HI 1 "register_operand" "%0,0,0") | |
214 | (match_operand:HI 2 "reg_or_int_operand" "c,M,N")))] | |
215 | "" | |
216 | "mulw\t%2, %0" | |
217 | [(set_attr "length" "2,2,4")] | |
218 | ) | |
219 | ||
220 | (define_insn "mulqihi3" | |
221 | [(set (match_operand:HI 0 "register_operand" "=c") | |
222 | (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0")) | |
223 | (sign_extend:HI (match_operand:QI 2 "register_operand" "c"))))] | |
224 | "" | |
225 | "mulsb\t%2, %0" | |
226 | [(set_attr "length" "2")] | |
227 | ) | |
228 | ||
229 | ;; Bit Set/Clear Instructions | |
230 | (define_expand "insv" | |
231 | [(set (zero_extract (match_operand 0 "memory_operand" "") | |
232 | (match_operand 1 "immediate_operand" "") | |
233 | (match_operand 2 "immediate_operand" "")) | |
234 | (match_operand 3 "immediate_operand" ""))] | |
235 | "TARGET_BIT_OPS" | |
236 | { | |
237 | if (INTVAL (operands[1]) != 1) | |
238 | FAIL; | |
239 | if (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) > 15) | |
240 | FAIL; | |
241 | if (INTVAL (operands[3]) == 1) | |
242 | { | |
243 | if (GET_MODE (operands[0]) == QImode) | |
244 | { | |
245 | emit_insn (gen_set_bitqi (operands[0], operands[2])); | |
246 | DONE; | |
247 | } | |
248 | else if (GET_MODE (operands[0]) == HImode) | |
249 | { | |
250 | emit_insn (gen_set_bithi (operands[0], operands[2])); | |
251 | DONE; | |
252 | } | |
253 | } | |
254 | if (INTVAL (operands[3]) == 0) | |
255 | { | |
256 | if (GET_MODE (operands[0]) == QImode) | |
257 | { | |
258 | emit_insn (gen_clr_bitqi (operands[0], operands[2])); | |
259 | DONE; | |
260 | } | |
261 | else if (GET_MODE (operands[0]) == HImode) | |
262 | { | |
263 | emit_insn (gen_clr_bithi (operands[0], operands[2])); | |
264 | DONE; | |
265 | } | |
266 | } | |
267 | } | |
268 | ) | |
269 | ||
270 | (define_insn "set_bit<mode>" | |
271 | [(set (zero_extract:SHORT (match_operand:SHORT 0 "memory_operand" "+m") | |
272 | (const_int 1) | |
273 | (match_operand 1 "immediate_operand" "i")) | |
274 | (const_int 1))] | |
275 | "TARGET_BIT_OPS" | |
276 | "sbit<tIsa>\t%1,%0" | |
277 | [(set_attr "length" "2")] | |
278 | ) | |
279 | ||
280 | (define_insn "clr_bit<mode>" | |
281 | [(set (zero_extract:SHORT (match_operand:SHORT 0 "memory_operand" "+m") | |
282 | (const_int 1) | |
283 | (match_operand 1 "immediate_operand" "i")) | |
284 | (const_int 0))] | |
285 | "TARGET_BIT_OPS" | |
286 | "cbit<tIsa>\t%1,%0" | |
287 | [(set_attr "length" "2")] | |
288 | ) | |
289 | ||
290 | (define_insn "set_bit<mode>_mem" | |
291 | [(set (match_operand:SHORT 0 "bit_operand" "=m") | |
292 | (ior:SHORT (match_dup 0) | |
293 | (match_operand:SHORT 1 "one_bit_operand" "i")) | |
294 | )] | |
295 | "TARGET_BIT_OPS" | |
296 | "sbit<tIsa>\t$%s1,%0" | |
297 | [(set_attr "length" "2")] | |
298 | ) | |
299 | ||
300 | (define_insn "clear_bit<mode>_mem" | |
301 | [(set (match_operand:SHORT 0 "bit_operand" "=m") | |
302 | (and:SHORT (match_dup 0) | |
303 | (match_operand:SHORT 1 "rev_one_bit_operand" "i")) | |
304 | )] | |
305 | "TARGET_BIT_OPS" | |
306 | "cbit<tIsa>\t$%r1,%0" | |
307 | [(set_attr "length" "2")] | |
308 | ) | |
309 | ||
310 | ;; Logical Instructions - and/ior/xor "anddi3/iordi3/xordi3" | |
311 | (define_insn "<any_logic_insn>di3" | |
312 | [(set (match_operand:DI 0 "register_operand" "=r") | |
313 | (any_logic:DI (match_operand:DI 1 "register_operand" "%0") | |
314 | (match_operand:DI 2 "register_operand" "r")))] | |
315 | "" | |
316 | { | |
317 | return cr16_emit_logical_di (operands, <any_logic_flag>); | |
318 | }) | |
319 | ||
320 | ; Logical and/ior/xor "andsi3/iorsi3/xorsi3" | |
321 | (define_insn "<any_logic_insn>si3" | |
322 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") | |
323 | (any_logic:SI (match_operand:SI 1 "register_operand" "%0,0,0,0") | |
324 | (match_operand:SI 2 "reg_si_int_operand" "r,M,N,i")))] | |
325 | "" | |
326 | "<logic>d\t%2, %0" | |
327 | [(set_attr "length" "2,2,4,6")] | |
328 | ) | |
329 | ||
330 | ; Logical and/ior/xor in HImode "andhi3/iorhi3/xorhi3" | |
331 | ; Logical and/ior/xor in QImode "andqi3/iorqi3/xorqi3" | |
332 | (define_insn "<any_logic_insn><qh>3" | |
333 | [(set (match_operand:QH 0 "register_operand" "=c,c,c") | |
334 | (any_logic:QH (match_operand:QH 1 "register_operand" "%0,0,0") | |
335 | (match_operand:QH 2 "reg_hi_int_operand" "c,M,N")))] | |
336 | "" | |
337 | "<logic><QHsuffix>\t%2, %0" | |
338 | [(set_attr "length" "<QHsz>")] | |
339 | ) | |
340 | ||
341 | ;; Sign and Zero Extend Instructions | |
342 | (define_insn "<szPat>extendhisi2" | |
343 | [(set (match_operand:SI 0 "register_operand" "=r") | |
344 | (sz_xtnd:SI (match_operand:HI 1 "register_operand" "r")))] | |
345 | "" | |
346 | "mov<szIsa>w\t%1, %0" | |
347 | [(set_attr "length" "4")] | |
348 | ) | |
349 | ||
350 | (define_insn "<szPat>extendqihi2" | |
351 | [(set (match_operand:HI 0 "register_operand" "=r") | |
352 | (sz_xtnd:HI (match_operand:QI 1 "register_operand" "r")))] | |
353 | "" | |
354 | "mov<szIsa>b\t%1, %0" | |
355 | [(set_attr "length" "4")] | |
356 | ) | |
357 | ||
358 | ;; One's Complement | |
359 | (define_insn "one_cmpldi2" | |
360 | [(set (match_operand:DI 0 "register_operand" "=r") | |
361 | (not:DI (match_operand:DI 1 "register_operand" "0")))] | |
362 | "" | |
363 | { | |
364 | rtx xoperand ; | |
365 | int reg0 = REGNO (operands[0]); | |
366 | ||
367 | xoperand = gen_rtx_REG (SImode, reg0 + 2); | |
368 | output_asm_insn ("xord\t$-1, %0", operands); | |
369 | output_asm_insn ("xord\t$-1, %0", &xoperand); | |
370 | return "" ; | |
371 | } | |
372 | [(set_attr "length" "12")] | |
373 | ) | |
374 | ||
375 | (define_insn "one_cmpl<mode>2" | |
376 | [(set (match_operand:CR16IM 0 "register_operand" "=r") | |
377 | (not:CR16IM (match_operand:CR16IM 1 "register_operand" "0")))] | |
378 | "" | |
379 | "xor<tIsa>\t$-1, %0" | |
380 | [(set_attr "length" "2")] | |
381 | ) | |
382 | ||
383 | ;; Arithmetic Left and Right Shift Instructions | |
384 | (define_insn "ashlqi3" | |
385 | [(set (match_operand:QI 0 "register_operand" "=c,c") | |
386 | (ashift:QI (match_operand:QI 1 "register_operand" "0,0") | |
387 | (match_operand:QI 2 "nonmemory_operand" "c,I")))] | |
388 | "" | |
389 | "ashub\t%2, %0" | |
390 | [(set_attr "length" "2,2")] | |
391 | ) | |
392 | ||
393 | (define_insn "ashlhi3" | |
394 | [(set (match_operand:HI 0 "register_operand" "=c,c") | |
395 | (ashift:HI (match_operand:HI 1 "register_operand" "0,0") | |
396 | (match_operand:QI 2 "nonmemory_operand" "c,J")))] | |
397 | "" | |
398 | "ashuw\t%2, %0" | |
399 | [(set_attr "length" "2,2")] | |
400 | ) | |
401 | ||
402 | (define_insn "ashlsi3" | |
403 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
404 | (ashift:SI (match_operand:SI 1 "register_operand" "0,0") | |
405 | (match_operand:QI 2 "nonmemory_operand" "r,K")))] | |
406 | "" | |
407 | "ashud\t%2, %0" | |
408 | [(set_attr "length" "2,2")] | |
409 | ) | |
410 | ||
411 | (define_expand "ashr<mode>3" | |
412 | [(set (match_operand:CR16IM 0 "register_operand" "") | |
413 | (ashiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "") | |
414 | (match_operand:QI 2 "nonmemory_operand" "")))] | |
415 | "" | |
416 | { | |
417 | if (GET_CODE (operands[2]) == CONST_INT) | |
418 | { | |
419 | /* If the constant is not in range, try placing it in a reg */ | |
420 | if (!UNSIGNED_INT_FITS_N_BITS(INTVAL (operands[2]),<shImmBits>)) | |
421 | operands[2] = copy_to_mode_reg(QImode, operands[2]); | |
422 | } | |
423 | ||
424 | if (GET_CODE (operands[2]) != CONST_INT) | |
425 | operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); | |
426 | } | |
427 | ) | |
428 | ||
429 | (define_insn "ashrqi3_imm_insn" | |
430 | [(set (match_operand:QI 0 "register_operand" "=c") | |
431 | (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") | |
432 | (match_operand:QI 2 "shift_qi_imm_operand" "i")))] | |
433 | "" | |
434 | "ashub\t$%n2, %0" | |
435 | [(set_attr "length" "2")] | |
436 | ) | |
437 | ||
438 | (define_insn "ashrhi3_imm_insn" | |
439 | [(set (match_operand:HI 0 "register_operand" "=c") | |
440 | (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
441 | (match_operand:QI 2 "shift_hi_imm_operand" "i")))] | |
442 | "" | |
443 | "ashuw\t$%n2, %0" | |
444 | [(set_attr "length" "2")] | |
445 | ) | |
446 | ||
447 | (define_insn "ashrsi3_imm_insn" | |
448 | [(set (match_operand:SI 0 "register_operand" "=r") | |
449 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") | |
450 | (match_operand:QI 2 "shift_si_imm_operand" "i")))] | |
451 | "" | |
452 | "ashud\t$%n2, %0" | |
453 | [(set_attr "length" "2")] | |
454 | ) | |
455 | ||
456 | (define_insn "ashrqi3_neg_insn" | |
457 | [(set (match_operand:QI 0 "register_operand" "=c") | |
458 | (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") | |
459 | (neg:QI (match_operand:QI 2 "register_operand" "c"))))] | |
460 | "" | |
461 | "ashub\t%2,%0" | |
462 | [(set_attr "length" "2")] | |
463 | ) | |
464 | ||
465 | (define_insn "ashrhi3_neg_insn" | |
466 | [(set (match_operand:HI 0 "register_operand" "=c") | |
467 | (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
468 | (neg:QI (match_operand:QI 2 "register_operand" "c"))))] | |
469 | "" | |
470 | "ashuw\t%2,%0" | |
471 | [(set_attr "length" "2")] | |
472 | ) | |
473 | ||
474 | (define_insn "ashrdi3_neg_insn" | |
475 | [(set (match_operand:SI 0 "register_operand" "=r") | |
476 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") | |
477 | (neg:QI (match_operand:QI 2 "register_operand" "r"))))] | |
478 | "" | |
479 | "ashud\t%2,%0" | |
480 | [(set_attr "length" "2")] | |
481 | ) | |
482 | ||
483 | (define_expand "lshr<mode>3" | |
484 | [(set (match_operand:CR16IM 0 "register_operand" "") | |
485 | (lshiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "") | |
486 | (match_operand:QI 2 "reg_or_int_operand" "")))] | |
487 | "" | |
488 | { | |
489 | if (GET_CODE (operands[2]) == CONST_INT) | |
490 | { | |
491 | /* If the constant is not in range, try placing it in a reg */ | |
492 | if (!UNSIGNED_INT_FITS_N_BITS(INTVAL (operands[2]),<shImmBits>)) | |
493 | operands[2] = copy_to_mode_reg(QImode, operands[2]); | |
494 | } | |
495 | ||
496 | if (GET_CODE (operands[2]) != CONST_INT) | |
497 | operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2])); | |
498 | } | |
499 | ) | |
500 | ||
501 | (define_insn "lshrqi3_imm_insn" | |
502 | [(set (match_operand:QI 0 "register_operand" "=c") | |
503 | (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") | |
504 | (match_operand:QI 2 "shift_qi_operand" "Q")))] | |
505 | "" | |
506 | "lshb\t$%n2, %0" | |
507 | [(set_attr "length" "2")] | |
508 | ) | |
509 | ||
510 | (define_insn "lshrhi3_imm_insn" | |
511 | [(set (match_operand:HI 0 "register_operand" "=c") | |
512 | (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
513 | (match_operand:QI 2 "shift_hi_operand" "R")))] | |
514 | "" | |
515 | "lshw\t$%n2, %0" | |
516 | [(set_attr "length" "2")] | |
517 | ) | |
518 | ||
519 | (define_insn "lshrsi3_imm_insn" | |
520 | [(set (match_operand:SI 0 "register_operand" "=r") | |
521 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") | |
522 | (match_operand:QI 2 "shift_si_operand" "S")))] | |
523 | "" | |
524 | "lshd\t$%n2, %0" | |
525 | [(set_attr "length" "2")] | |
526 | ) | |
527 | ||
528 | (define_insn "lshrqi3_neg_insn" | |
529 | [(set (match_operand:QI 0 "register_operand" "=c") | |
530 | (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") | |
531 | (neg:QI (match_operand:QI 2 "register_operand" "c"))))] | |
532 | "" | |
533 | "lshb\t%2,%0" | |
534 | [(set_attr "length" "2")] | |
535 | ) | |
536 | ||
537 | (define_insn "lshrhi3_neg_insn" | |
538 | [(set (match_operand:HI 0 "register_operand" "=c") | |
539 | (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
540 | (neg:QI (match_operand:QI 2 "register_operand" "c"))))] | |
541 | "" | |
542 | "lshw\t%2,%0" | |
543 | [(set_attr "length" "2")] | |
544 | ) | |
545 | ||
546 | (define_insn "lshrsi3_neg_insn" | |
547 | [(set (match_operand:SI 0 "register_operand" "=r") | |
548 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") | |
549 | (neg:QI (match_operand:QI 2 "register_operand" "r"))))] | |
550 | "" | |
551 | "lshd\t%2,%0" | |
552 | [(set_attr "length" "2")] | |
553 | ) | |
554 | ||
555 | ;; Move Instructions | |
556 | ||
557 | ;; Move any non-immediate operand 0 to a general operand 1. | |
558 | ;; This applies only before starting the reload process | |
559 | ;; Operand 0 is not a register operand of type mode MODE | |
560 | ;; If Operand 0 is a push operand of type mode MODE | |
561 | ;; then, if Operand 1 is a non-SP register | |
562 | ;; then, Operand 1 = copy_to_mode_reg (<MODE>mode, Operand 1) | |
563 | ;; endif | |
564 | ;; else | |
565 | ;; if Operand 1 is either register or 4-bit immediate constant | |
566 | ;; then, Operand 1 = copy_to_mode_reg (<MODE>mode, Operand 1) | |
567 | ;; endif | |
568 | ;; endif | |
569 | ;; | |
570 | ;; What does copy_to_mode_reg (mode, rtx val) do? | |
571 | ;; Copy the value into new temp reg and return the reg where the | |
572 | ;; mode of the new reg is always mode MODE when value is constant | |
573 | ;; | |
574 | ;; Why should copy_to_mode_reg be called? | |
575 | ;; All sorts of move are nor supported by CR16. Therefore, | |
576 | ;; when unsupported move is encountered, the additional instructions | |
577 | ;; will be introduced for the purpose. | |
578 | ;; | |
579 | ;; A new move insn is inserted for Op 1 when one of the following | |
580 | ;; conditions is met. | |
581 | ;; Case 1: Op 0 is push_operand | |
582 | ;; Op 1 is SP register | |
583 | ;; | |
584 | ;; Case 2: Op 0 is not push_operand | |
585 | ;; Op 1 is neither register nor unsigned 4-bit immediate | |
586 | ||
587 | (define_expand "mov<mode>" | |
588 | [(set (match_operand:ALLMTD 0 "nonimmediate_operand" "") | |
589 | (match_operand:ALLMTD 1 "general_operand" ""))] | |
590 | "" | |
591 | { | |
592 | if (!(reload_in_progress || reload_completed)) | |
593 | { | |
594 | /* Only if Op0 is a register operand. */ | |
595 | if (!register_operand (operands[0], <MODE>mode)) | |
596 | { | |
597 | if (push_operand (operands[0], <MODE>mode)) | |
598 | { | |
599 | /* Use copy_to_mode_reg only if the register needs | |
600 | to be pushed is SP as CR16 does not support pushing SP. */ | |
601 | if (!nosp_reg_operand (operands[1], <MODE>mode)) | |
602 | operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]); | |
603 | } | |
604 | else | |
605 | { | |
606 | /* Use copy_to_mode_reg if op1 is not register operand | |
607 | subject to conditions inside. */ | |
608 | if (!register_operand (operands[1], <MODE>mode)) | |
609 | { | |
610 | /* CR16 does not support moving immediate to SI or SF | |
611 | type memory. */ | |
612 | if (<MODE>mode == SImode || <MODE>mode == SFmode || | |
613 | <MODE>mode == DImode || <MODE>mode == DFmode) | |
614 | operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]); | |
615 | else | |
616 | /* moving imm4 is supported by CR16 instruction. */ | |
617 | if (!u4bits_operand (operands[1], <MODE>mode)) | |
618 | operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]); | |
619 | } | |
620 | } | |
621 | } | |
622 | ||
623 | /* If operand-1 is a symbol, convert it into a BRO or GOT Format. */ | |
624 | if (flag_pic && ! legitimate_pic_operand_p (operands[1])) | |
625 | { | |
626 | operands[1] = legitimize_pic_address (operands[1], <MODE>mode, 0); | |
627 | } | |
628 | } | |
629 | } | |
630 | ) | |
631 | ||
632 | ; ALLMT : QI,HI,SI,SF | |
633 | ; pushCnstr : Push constraints | |
634 | ; QI : X | |
635 | ; HI,SI,SF,DI,DF : < | |
636 | ; b : All non-sp registers | |
637 | ; tpush : Push count | |
638 | ; QI,HI : 1 | |
639 | ; SI,SF : 2 | |
640 | ; DI,DF : 4 | |
641 | (define_insn "push<mode>_internal" | |
642 | [(set (match_operand:ALLMTD 0 "push_operand" "=<pushCnstr>") | |
643 | (match_operand:ALLMTD 1 "nosp_reg_operand" "b"))] | |
644 | "" | |
645 | "push\t$<tpush>,%p1" | |
646 | [(set_attr "length" "2")] | |
647 | ) | |
648 | ||
649 | ; (DI, DF) move | |
650 | (define_insn "*mov<mode>_double" | |
651 | [(set (match_operand:DOUBLE 0 "nonimmediate_operand" "=r, r, r, m") | |
652 | (match_operand:DOUBLE 1 "general_operand" "r, <iFD>, m, r"))] | |
653 | "register_operand (operands[0], DImode) | |
654 | || register_operand (operands[0], DFmode) | |
655 | || register_operand (operands[1], DImode) | |
656 | || register_operand (operands[1], DFmode)" | |
657 | { | |
c9281ef8 | 658 | if (which_alternative == 0) { |
659 | rtx xoperands[2]; | |
b9fdd12b | 660 | int reg0 = REGNO (operands[0]); |
661 | int reg1 = REGNO (operands[1]); | |
662 | ||
663 | xoperands[0] = gen_rtx_REG (SImode, reg0 + 2); | |
664 | xoperands[1] = gen_rtx_REG (SImode, reg1 + 2); | |
665 | if ((reg1 + 2) != reg0) | |
666 | { | |
667 | output_asm_insn ("movd\t%1, %0", operands); | |
668 | output_asm_insn ("movd\t%1, %0", xoperands); | |
669 | } | |
670 | else | |
671 | { | |
672 | output_asm_insn ("movd\t%1, %0", xoperands); | |
673 | output_asm_insn ("movd\t%1, %0", operands); | |
674 | }} | |
675 | ||
c9281ef8 | 676 | else if (which_alternative == 1) { |
677 | rtx lo_operands[2]; | |
678 | rtx hi_operands[2]; | |
b9fdd12b | 679 | |
680 | lo_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); | |
681 | hi_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2); | |
682 | lo_operands[1] = simplify_gen_subreg (SImode, operands[1], | |
683 | VOIDmode == GET_MODE (operands[1]) | |
684 | ? DImode : GET_MODE (operands[1]), 0); | |
685 | hi_operands[1] = simplify_gen_subreg (SImode, operands[1], | |
686 | VOIDmode == GET_MODE (operands[1]) | |
687 | ? DImode : GET_MODE (operands[1]), 4); | |
688 | output_asm_insn ("movd\t%1, %0", lo_operands); | |
689 | output_asm_insn ("movd\t%1, %0", hi_operands);} | |
690 | ||
c9281ef8 | 691 | else if (which_alternative == 2) { |
692 | rtx xoperands[2]; | |
693 | int reg0 = REGNO (operands[0]), reg1 = -2; | |
694 | rtx addr; | |
b9fdd12b | 695 | |
696 | if (MEM_P (operands[1])) | |
697 | addr = XEXP (operands[1], 0); | |
698 | else | |
c9281ef8 | 699 | addr = NULL_RTX; |
b9fdd12b | 700 | switch (GET_CODE (addr)) |
701 | { | |
702 | case REG: | |
703 | case SUBREG: | |
704 | reg1 = REGNO (addr); | |
c9281ef8 | 705 | break; |
b9fdd12b | 706 | case PLUS: |
707 | switch (GET_CODE (XEXP (addr, 0))) { | |
708 | case REG: | |
709 | case SUBREG: | |
710 | reg1 = REGNO (XEXP (addr, 0)); | |
c9281ef8 | 711 | break; |
b9fdd12b | 712 | case PLUS: |
713 | reg1 = REGNO (XEXP (XEXP (addr, 0), 0)); | |
c9281ef8 | 714 | break; |
b9fdd12b | 715 | default: |
716 | inform (DECL_SOURCE_LOCATION (cfun->decl), "unexpected expression; addr:"); | |
717 | debug_rtx (addr); | |
718 | inform (DECL_SOURCE_LOCATION (cfun->decl), "operands[1]:"); | |
719 | debug_rtx (operands[1]); | |
720 | inform (DECL_SOURCE_LOCATION (cfun->decl), "generated code might now work\n"); | |
c9281ef8 | 721 | break;} |
722 | break; | |
b9fdd12b | 723 | default: |
c9281ef8 | 724 | break; |
b9fdd12b | 725 | } |
726 | ||
727 | xoperands[0] = gen_rtx_REG (SImode, reg0 + 2); | |
728 | xoperands[1] = offset_address (operands[1], GEN_INT (4), 2); | |
729 | gcc_assert ((reg0 + 1) != reg1); | |
730 | if (reg0 != reg1 && (reg1 + 1) != reg0) | |
731 | { | |
732 | output_asm_insn ("loadd\t%1, %0", operands); | |
733 | output_asm_insn ("loadd\t%1, %0", xoperands); | |
734 | } | |
735 | else | |
736 | { | |
737 | output_asm_insn ("loadd\t%1, %0", xoperands); | |
738 | output_asm_insn ("loadd\t%1, %0", operands); | |
739 | }} | |
740 | else | |
741 | { | |
c9281ef8 | 742 | rtx xoperands[2]; |
b9fdd12b | 743 | xoperands[0] = offset_address (operands[0], GEN_INT (4), 2); |
744 | xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); | |
745 | output_asm_insn ("stord\t%1, %0", operands); | |
746 | output_asm_insn ("stord\t%1, %0", xoperands); | |
747 | } | |
c9281ef8 | 748 | return ""; |
b9fdd12b | 749 | } |
750 | [(set_attr "length" "4, <lImmArithD>, <lImmArithD>, <lImmArithD>")] | |
751 | ) | |
752 | ||
753 | ; All long (SI, SF) register move, load and store operations | |
754 | ; The print_operand will take care of printing the register pair | |
755 | ; when mode is SI/SF and register is in SHORT_REGS | |
756 | (define_insn "*mov<mode>_long" | |
757 | [(set (match_operand:LONG 0 "nonimmediate_operand" "=r, r, r, m") | |
758 | (match_operand:LONG 1 "general_operand" "r, <iF>, m, r"))] | |
759 | "register_operand (operands[0], <MODE>mode) | |
760 | || register_operand (operands[1], <MODE>mode)" | |
761 | "@ | |
762 | mov<tIsa>\t%1, %0 | |
763 | mov<tIsa>\t%1, %0 | |
764 | load<tIsa>\t%1, %0 | |
765 | stor<tIsa>\t%1, %0" | |
766 | [(set_attr "length" "2,<lImmArith>,<lImmArith>,<lImmArith>")] | |
767 | ) | |
768 | ||
769 | ;; All short (QI, HI) register move, load and store operations | |
770 | (define_insn "*mov<mode>_short" | |
771 | [(set (match_operand:SHORT 0 "nonimmediate_operand" "=r, r, r, m, m") | |
772 | (match_operand:SHORT 1 "general_operand" "r, <iF>, m, r, <LL>"))] | |
773 | "(register_operand (operands[0], <MODE>mode)) | |
774 | || (store_operand (operands[0], <MODE>mode) | |
775 | && (register_operand (operands[1], <MODE>mode) | |
776 | || u4bits_operand (operands[1], <MODE>mode)))" | |
777 | "@ | |
778 | mov<tIsa>\t%1, %0 | |
779 | mov<tIsa>\t%1, %0 | |
780 | load<tIsa>\t%1, %0 | |
781 | stor<tIsa>\t%1, %0 | |
782 | stor<tIsa>\t%1, %0" | |
783 | [(set_attr "length" "2,<lImmArith>,<lImmArith>,<lImmArith>,<lImmArith>")] | |
784 | ) | |
785 | ||
786 | ;; Compare Instructions | |
787 | ; Instruction generated compares the operands in reverse order | |
788 | ; Therefore, while printing the asm, the reverse of the | |
789 | ; compare condition shall be printed. | |
790 | (define_insn "cbranch<mode>4" | |
791 | [(set (pc) | |
792 | (if_then_else (match_operator 0 "ordered_comparison_operator" | |
793 | [(match_operand:CR16IM 1 "register_operand" "r,r") | |
794 | (match_operand:CR16IM 2 "nonmemory_operand" "r,n")]) | |
795 | (label_ref (match_operand 3 "" "")) | |
796 | (pc))) | |
797 | (clobber (cc0))] | |
798 | "" | |
799 | "cmp<tIsa>\t%2, %1\;b%d0\t%l3" | |
800 | [(set_attr "length" "6,6")] | |
801 | ) | |
802 | ||
803 | (define_expand "cmp<mode>" | |
804 | [(parallel [(set (cc0) | |
805 | (compare (match_operand:CR16IM 0 "register_operand" "") | |
806 | (match_operand:CR16IM 1 "nonmemory_operand" ""))) | |
807 | (clobber (match_scratch:HI 2 "=r"))] ) ] | |
808 | "" | |
809 | "") | |
810 | ||
811 | ;; Scond Instructions | |
812 | (define_expand "cstore<mode>4" | |
813 | [(set (cc0) | |
814 | (compare (match_operand:CR16IM 2 "register_operand" "") | |
815 | (match_operand:CR16IM 3 "nonmemory_operand" ""))) | |
816 | (set (match_operand:HI 0 "register_operand") | |
817 | (match_operator:HI 1 "ordered_comparison_operator" | |
818 | [(cc0) (const_int 0)]))] | |
819 | "" | |
820 | "" | |
821 | ) | |
822 | ||
823 | (define_insn "*cmp<mode>_insn" | |
824 | [(set (cc0) | |
825 | (compare (match_operand:CR16IM 0 "register_operand" "r,r") | |
826 | (match_operand:CR16IM 1 "nonmemory_operand" "r,n")))] | |
827 | "" | |
828 | "cmp<tIsa>\t%1, %0" | |
829 | [(set_attr "length" "2,4")] | |
830 | ) | |
831 | ||
832 | (define_insn "sCOND_internal" | |
833 | [(set (match_operand:HI 0 "register_operand" "=r") | |
834 | (match_operator:HI 1 "ordered_comparison_operator" | |
835 | [(cc0) (const_int 0)]))] | |
836 | "" | |
837 | "s%d1\t%0" | |
838 | [(set_attr "length" "2")] | |
839 | ) | |
840 | ||
841 | ;; Jumps and Branches | |
842 | (define_insn "indirect_jump_return" | |
843 | [(set (pc) | |
844 | (reg:SI RA_REGNUM)) | |
845 | (return)] | |
846 | "reload_completed" | |
847 | "jump\t (ra)" | |
848 | [(set_attr "length" "2")] | |
849 | ) | |
850 | ||
851 | (define_insn "jump_return" | |
852 | [(unspec:SI [(const_int 0)] UNSPEC_RETURN_ADDR) | |
853 | (return)] | |
854 | "reload_completed" | |
855 | "jump\t(ra)" | |
856 | [(set_attr "length" "2")] | |
857 | ) | |
858 | ||
859 | (define_insn "indirect_jump" | |
860 | [(set (pc) | |
861 | (match_operand:SI 0 "reg_or_sym_operand" "r,i"))] | |
862 | "" | |
863 | "@ | |
864 | jump\t%0 | |
865 | br\t%a0" | |
866 | [(set_attr "length" "2,6")] | |
867 | ) | |
868 | ||
869 | (define_insn "interrupt_return" | |
870 | [(unspec_volatile [(const_int 0)] 0) | |
871 | (return)] | |
872 | "" | |
873 | { | |
874 | return cr16_prepare_push_pop_string (1); | |
875 | } | |
876 | [(set_attr "length" "14")] | |
877 | ) | |
878 | ||
879 | (define_insn "jump_to_imm" | |
880 | [(set (pc) | |
881 | (match_operand 0 "jump_imm_operand" "i"))] | |
882 | "" | |
883 | "br\t%c0" | |
884 | [(set_attr "length" "6")] | |
885 | ) | |
886 | ||
887 | (define_insn "jump" | |
888 | [(set (pc) | |
889 | (label_ref (match_operand 0 "" "")))] | |
890 | "" | |
891 | "br\t%l0" | |
892 | [(set_attr "length" "6")] | |
893 | ) | |
894 | ||
895 | ;; Table Jump | |
896 | (define_insn "tablejump" | |
897 | [(set (pc) | |
898 | (match_operand:SI 0 "register_operand" "r")) | |
899 | (use (label_ref:SI (match_operand 1 "" "")))] | |
900 | "!flag_pic" | |
901 | "jump\t%0" | |
902 | [(set_attr "length" "2")] | |
903 | ) | |
904 | ||
905 | ;; Call Instructions | |
906 | (define_expand "call" | |
907 | [(call (match_operand:QI 0 "memory_operand" "") | |
908 | (match_operand 1 "" ""))] | |
909 | "" | |
910 | { | |
911 | if (flag_pic && ! legitimate_pic_operand_p (operands[0])) | |
912 | { | |
913 | operands[0] = gen_const_mem (QImode, | |
914 | legitimize_pic_address (XEXP (operands[0], 0), Pmode, 0)); | |
915 | emit_call_insn (gen_cr16_call (operands[0], operands[1])); | |
916 | } | |
917 | else | |
918 | emit_call_insn (gen_cr16_call (operands[0], operands[1])); | |
919 | DONE; | |
920 | } | |
921 | ) | |
922 | ||
923 | (define_expand "cr16_call" | |
924 | [(parallel | |
925 | [(call (match_operand:QI 0 "memory_operand" "") | |
926 | (match_operand 1 "" "")) | |
927 | (clobber (reg:SI RA_REGNUM))])] | |
928 | "" | |
929 | "" | |
930 | ) | |
931 | ||
932 | (define_insn "cr16_call_insn_branch_pic" | |
933 | [(call (mem:QI (match_operand:SI 0 "call_imm_operand" "i")) | |
934 | (match_operand 1 "" "")) | |
935 | (clobber (match_operand:SI 2 "register_operand" "+r"))] | |
936 | "flag_pic == FAR_PIC" | |
937 | { | |
938 | if (GET_CODE (operands[0]) != CONST_INT) | |
939 | return "loadd\t%g0, %2 \n\tjal %2"; | |
940 | else | |
941 | return "jal %2"; | |
942 | } | |
943 | [(set_attr "length" "8")] | |
944 | ) | |
945 | ||
946 | (define_insn "cr16_call_insn_branch" | |
947 | [(call (mem:QI (match_operand:SI 0 "call_imm_operand" "i")) | |
948 | (match_operand 1 "" "")) | |
949 | (clobber (match_operand:SI 2 "register_operand" "+r"))] | |
950 | "flag_pic == 0 || flag_pic == NEAR_PIC" | |
951 | { | |
952 | /* Print the immediate address for bal | |
953 | 'b' is used instead of 'a' to avoid compiler calling | |
954 | the GO_IF_LEGITIMATE_ADDRESS which cannot | |
955 | perform checks on const_int code addresses as it | |
956 | assumes all const_int are data addresses. | |
957 | */ | |
958 | if (GET_CODE (operands[0]) != CONST_INT) | |
959 | return "bal (ra), %a0"; | |
960 | else | |
961 | operands[4] = GEN_INT ((INTVAL (operands[0]))>>1); | |
962 | return "movd\t%g4,\t(r1,r0)\n\tjal\t(r1,r0)"; | |
963 | } | |
964 | [(set_attr "length" "6")] | |
965 | ) | |
966 | ||
967 | (define_insn "cr16_call_insn_jump" | |
968 | [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) | |
969 | (match_operand 1 "" "")) | |
970 | (clobber (match_operand:SI 2 "register_operand" "+r"))] | |
971 | "" | |
972 | "jal\t%0" | |
973 | [(set_attr "length" "2")] | |
974 | ) | |
975 | ||
976 | ;; Call Value Instructions | |
977 | ||
978 | (define_expand "call_value" | |
979 | [(set (match_operand 0 "general_operand" "") | |
980 | (call (match_operand:QI 1 "memory_operand" "") | |
981 | (match_operand 2 "" "")))] | |
982 | "" | |
983 | { | |
984 | if (flag_pic && !legitimate_pic_operand_p (operands[1])) | |
985 | { | |
986 | operands[1] = gen_const_mem (QImode, | |
987 | legitimize_pic_address (XEXP (operands[1], 0), Pmode, 0)); | |
988 | emit_call_insn (gen_cr16_call_value (operands[0], operands[1], operands[2])); | |
989 | } | |
990 | else | |
991 | emit_call_insn (gen_cr16_call_value (operands[0], operands[1], operands[2])); | |
992 | DONE; | |
993 | } | |
994 | ) | |
995 | ||
996 | (define_expand "cr16_call_value" | |
997 | [(parallel | |
998 | [(set (match_operand 0 "general_operand" "") | |
999 | (call (match_operand 1 "memory_operand" "") | |
1000 | (match_operand 2 "" ""))) | |
1001 | (clobber (reg:SI RA_REGNUM))])] | |
1002 | "" | |
1003 | "" | |
1004 | ) | |
1005 | ||
1006 | (define_insn "cr16_call_value_insn_branch_pic" | |
1007 | [(set (match_operand 0 "" "=g") | |
1008 | (call (mem:QI (match_operand:SI 1 "call_imm_operand" "i")) | |
1009 | (match_operand 2 "" ""))) | |
1010 | (clobber (match_operand:SI 3 "register_operand" "+r"))] | |
1011 | "flag_pic == FAR_PIC" | |
1012 | { | |
1013 | if (GET_CODE (operands[1]) != CONST_INT) | |
1014 | return "loadd\t%g1, %3 \n\tjal %3"; | |
1015 | else | |
1016 | return "jal %3"; | |
1017 | } | |
1018 | [(set_attr "length" "8")] | |
1019 | ) | |
1020 | ||
1021 | (define_insn "cr16_call_value_insn_branch" | |
1022 | [(set (match_operand 0 "" "=g") | |
1023 | (call (mem:QI (match_operand:SI 1 "call_imm_operand" "i")) | |
1024 | (match_operand 2 "" ""))) | |
1025 | (clobber (match_operand:SI 3 "register_operand" "+r"))] | |
1026 | "flag_pic == 0 || flag_pic == NEAR_PIC" | |
1027 | { | |
1028 | /* Print the immediate address for bal | |
1029 | 'b' is used instead of 'a' to avoid compiler calling | |
1030 | the GO_IF_LEGITIMATE_ADDRESS which cannot | |
1031 | perform checks on const_int code addresses as it | |
1032 | assumes all const_int are data addresses. | |
1033 | */ | |
1034 | if (GET_CODE (operands[1]) != CONST_INT) | |
1035 | return "bal (ra), %a1"; | |
1036 | else | |
1037 | { | |
1038 | operands[4] = GEN_INT ((INTVAL (operands[1]))>>1); | |
1039 | return "movd\t%g4,\t(r1,r0)\n\tjal\t(r1,r0)"; | |
1040 | } | |
1041 | } | |
1042 | [(set_attr "length" "6")] | |
1043 | ) | |
1044 | ||
1045 | ||
1046 | (define_insn "cr16_call_value_insn_jump" | |
1047 | [(set (match_operand 0 "" "=g") | |
1048 | (call (mem:QI (match_operand:SI 1 "register_operand" "r")) | |
1049 | (match_operand 2 "" ""))) | |
1050 | (clobber (match_operand:SI 3 "register_operand" "+r"))] | |
1051 | "" | |
1052 | "jal\t%1" | |
1053 | [(set_attr "length" "2")] | |
1054 | ) | |
1055 | ||
1056 | ||
1057 | ;; Nop | |
1058 | (define_insn "nop" | |
1059 | [(const_int 0)] | |
1060 | "" | |
1061 | "nop\t" | |
1062 | ) | |
1063 | ||
1064 | ;; PIC | |
1065 | /* When generating pic, we need to load the symbol offset into a register. | |
1066 | So that the optimizer does not confuse this with a normal symbol load | |
1067 | we use an unspec. The offset will be loaded from a constant pool entry, | |
1068 | since that is the only type of relocation we can use. */ | |
1069 | ||
1070 | (define_insn "unspec_bro_addr" | |
1071 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1072 | (unspec:SI [(match_operand 1 "" "")] UNSPEC_PIC_ADDR))] | |
1073 | "" | |
1074 | "movd \t%f1, %0" | |
1075 | [(set_attr "length" "4")] | |
1076 | ) | |
1077 | ||
1078 | (define_insn "unspec_got_addr" | |
1079 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1080 | (unspec:SI [(match_operand 1 "" "")] UNSPEC_PIC_LOAD_ADDR))] | |
1081 | "" | |
1082 | "loadd \t%g1, %0" | |
1083 | [(set_attr "length" "6")] | |
1084 | ) |