upgrade Linaro GCC to 4.5-2011.05-0 - thanks to Mark Mentovai
[openwrt/openwrt.git] / toolchain / gcc / patches / linaro / 600-ubicom_support.patch
1 --- a/configure
2 +++ b/configure
3 @@ -3730,6 +3730,9 @@ case "${target}" in
4 ip2k-*-*)
5 noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj}"
6 ;;
7 + ubicom32-*-*)
8 + noconfigdirs="$noconfigdirs target-libffi"
9 + ;;
10 *-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu | *-*-kopensolaris*-gnu)
11 noconfigdirs="$noconfigdirs target-newlib target-libgloss"
12 ;;
13 --- /dev/null
14 +++ b/gcc/config/ubicom32/constraints.md
15 @@ -0,0 +1,149 @@
16 +; Constraint definitions for Ubicom32
17 +
18 +; Copyright (C) 2009 Free Software Foundation, Inc.
19 +; Contributed by Ubicom, Inc.
20 +
21 +; This file is part of GCC.
22 +
23 +; GCC is free software; you can redistribute it and/or modify it
24 +; under the terms of the GNU General Public License as published
25 +; by the Free Software Foundation; either version 3, or (at your
26 +; option) any later version.
27 +
28 +; GCC is distributed in the hope that it will be useful, but WITHOUT
29 +; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
30 +; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
31 +; License for more details.
32 +
33 +; You should have received a copy of the GNU General Public License
34 +; along with GCC; see the file COPYING3. If not see
35 +; <http://www.gnu.org/licenses/>.
36 +
37 +(define_register_constraint "a" "ALL_ADDRESS_REGS"
38 + "An An register.")
39 +
40 +(define_register_constraint "d" "DATA_REGS"
41 + "A Dn register.")
42 +
43 +(define_register_constraint "h" "ACC_REGS"
44 + "An accumulator register.")
45 +
46 +(define_register_constraint "l" "ACC_LO_REGS"
47 + "An accn_lo register.")
48 +
49 +(define_register_constraint "Z" "FDPIC_REG"
50 + "The FD-PIC GOT pointer: A0.")
51 +
52 +(define_constraint "I"
53 + "An 8-bit signed constant value."
54 + (and (match_code "const_int")
55 + (match_test "(ival >= -128) && (ival <= 127)")))
56 +
57 +(define_constraint "Q"
58 + "An 8-bit signed constant value represented as unsigned."
59 + (and (match_code "const_int")
60 + (match_test "(ival >= 0x00) && (ival <= 0xff)")))
61 +
62 +(define_constraint "R"
63 + "An 8-bit signed constant value represented as unsigned."
64 + (and (match_code "const_int")
65 + (match_test "((ival >= 0x0000) && (ival <= 0x007f)) || ((ival >= 0xff80) && (ival <= 0xffff))")))
66 +
67 +(define_constraint "J"
68 + "A 7-bit unsigned constant value."
69 + (and (match_code "const_int")
70 + (match_test "(ival >= 0) && (ival <= 127)")))
71 +
72 +(define_constraint "K"
73 + "A 7-bit unsigned constant value shifted << 1."
74 + (and (match_code "const_int")
75 + (match_test "(ival >= 0) && (ival <= 254) && ((ival & 1) == 0)")))
76 +
77 +(define_constraint "L"
78 + "A 7-bit unsigned constant value shifted << 2."
79 + (and (match_code "const_int")
80 + (match_test "(ival >= 0) && (ival <= 508) && ((ival & 3) == 0)")))
81 +
82 +(define_constraint "M"
83 + "A 5-bit unsigned constant value."
84 + (and (match_code "const_int")
85 + (match_test "(ival >= 0) && (ival <= 31)")))
86 +
87 +(define_constraint "N"
88 + "A signed 16 bit constant value."
89 + (and (match_code "const_int")
90 + (match_test "(ival >= -32768) && (ival <= 32767)")))
91 +
92 +(define_constraint "O"
93 + "An exact bitmask of contiguous 1 bits starting at bit 0."
94 + (and (match_code "const_int")
95 + (match_test "exact_log2 (ival + 1) != -1")))
96 +
97 +(define_constraint "P"
98 + "A 7-bit negative constant value shifted << 2."
99 + (and (match_code "const_int")
100 + (match_test "(ival >= -504) && (ival <= 0) && ((ival & 3) == 0)")))
101 +
102 +(define_constraint "S"
103 + "A symbolic reference."
104 + (match_code "symbol_ref"))
105 +
106 +(define_constraint "Y"
107 + "An FD-PIC symbolic reference."
108 + (and (match_test "TARGET_FDPIC")
109 + (match_test "GET_CODE (op) == UNSPEC")
110 + (ior (match_test "XINT (op, 1) == UNSPEC_FDPIC_GOT")
111 + (match_test "XINT (op, 1) == UNSPEC_FDPIC_GOT_FUNCDESC"))))
112 +
113 +(define_memory_constraint "T1"
114 + "A memory operand that can be used for .1 instruction."
115 + (and (match_test "memory_operand (op, GET_MODE(op))")
116 + (match_test "GET_MODE (op) == QImode")))
117 +
118 +(define_memory_constraint "T2"
119 + "A memory operand that can be used for .2 instruction."
120 + (and (match_test "memory_operand (op, GET_MODE(op))")
121 + (match_test "GET_MODE (op) == HImode")))
122 +
123 +(define_memory_constraint "T4"
124 + "A memory operand that can be used for .4 instruction."
125 + (and (match_test "memory_operand (op, GET_MODE(op))")
126 + (ior (match_test "GET_MODE (op) == SImode")
127 + (match_test "GET_MODE (op) == DImode")
128 + (match_test "GET_MODE (op) == SFmode"))))
129 +
130 +(define_memory_constraint "U1"
131 + "An offsettable memory operand that can be used for .1 instruction."
132 + (and (match_test "memory_operand (op, GET_MODE(op))")
133 + (match_test "GET_MODE (op) == QImode")
134 + (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
135 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
136 + (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
137 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
138 + (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
139 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
140 +
141 +(define_memory_constraint "U2"
142 + "An offsettable memory operand that can be used for .2 instruction."
143 + (and (match_test "memory_operand (op, GET_MODE(op))")
144 + (match_test "GET_MODE (op) == HImode")
145 + (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
146 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
147 + (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
148 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
149 + (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
150 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
151 +
152 +(define_memory_constraint "U4"
153 + "An offsettable memory operand that can be used for .4 instruction."
154 + (and (match_test "memory_operand (op, GET_MODE(op))")
155 + (ior (match_test "GET_MODE (op) == SImode")
156 + (match_test "GET_MODE (op) == DImode")
157 + (match_test "GET_MODE (op) == SFmode"))
158 + (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
159 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
160 + (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
161 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
162 + (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
163 + (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
164 +
165 --- /dev/null
166 +++ b/gcc/config/ubicom32/crti.S
167 @@ -0,0 +1,54 @@
168 +/* Specialized code needed to support construction and destruction of
169 + file-scope objects in C++ and Java code, and to support exception handling.
170 + Copyright (C) 1999 Free Software Foundation, Inc.
171 + Contributed by Charles-Antoine Gauthier (charles.gauthier@iit.nrc.ca).
172 +
173 +This file is part of GCC.
174 +
175 +GCC is free software; you can redistribute it and/or modify
176 +it under the terms of the GNU General Public License as published by
177 +the Free Software Foundation; either version 2, or (at your option)
178 +any later version.
179 +
180 +GCC is distributed in the hope that it will be useful,
181 +but WITHOUT ANY WARRANTY; without even the implied warranty of
182 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
183 +GNU General Public License for more details.
184 +
185 +You should have received a copy of the GNU General Public License
186 +along with GCC; see the file COPYING. If not, write to
187 +the Free Software Foundation, 59 Temple Place - Suite 330,
188 +Boston, MA 02111-1307, USA. */
189 +
190 +/* As a special exception, if you link this library with files
191 + compiled with GCC to produce an executable, this does not cause
192 + the resulting executable to be covered by the GNU General Public License.
193 + This exception does not however invalidate any other reasons why
194 + the executable file might be covered by the GNU General Public License. */
195 +
196 +/*
197 + * This file just supplies function prologues for the .init and .fini
198 + * sections. It is linked in before crtbegin.o.
199 + */
200 + .file "crti.o"
201 + .ident "GNU C crti.o"
202 +
203 + .section .init
204 + .align 2
205 + .globl _init
206 + .type _init, @function
207 +_init:
208 + move.4 -4(sp)++, a5
209 +#ifdef __UBICOM32_FDPIC__
210 + move.4 -4(sp)++, a0
211 +#endif
212 +
213 + .section .fini
214 + .align 2
215 + .globl _fini
216 + .type _fini, @function
217 +_fini:
218 + move.4 -4(sp)++, a5
219 +#ifdef __UBICOM32_FDPIC__
220 + move.4 -4(sp)++, a0
221 +#endif
222 --- /dev/null
223 +++ b/gcc/config/ubicom32/crtn.S
224 @@ -0,0 +1,47 @@
225 +/* Specialized code needed to support construction and destruction of
226 + file-scope objects in C++ and Java code, and to support exception handling.
227 + Copyright (C) 1999 Free Software Foundation, Inc.
228 + Contributed by Charles-Antoine Gauthier (charles.gauthier@iit.nrc.ca).
229 +
230 +This file is part of GCC.
231 +
232 +GCC is free software; you can redistribute it and/or modify
233 +it under the terms of the GNU General Public License as published by
234 +the Free Software Foundation; either version 2, or (at your option)
235 +any later version.
236 +
237 +GCC is distributed in the hope that it will be useful,
238 +but WITHOUT ANY WARRANTY; without even the implied warranty of
239 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
240 +GNU General Public License for more details.
241 +
242 +You should have received a copy of the GNU General Public License
243 +along with GCC; see the file COPYING. If not, write to
244 +the Free Software Foundation, 59 Temple Place - Suite 330,
245 +Boston, MA 02111-1307, USA. */
246 +
247 +/* As a special exception, if you link this library with files
248 + compiled with GCC to produce an executable, this does not cause
249 + the resulting executable to be covered by the GNU General Public License.
250 + This exception does not however invalidate any other reasons why
251 + the executable file might be covered by the GNU General Public License. */
252 +
253 +/*
254 + * This file supplies function epilogues for the .init and .fini sections.
255 + * It is linked in after all other files.
256 + */
257 +
258 + .file "crtn.o"
259 + .ident "GNU C crtn.o"
260 +
261 + .section .init
262 +#ifdef __UBICOM32_FDPIC__
263 + move.4 a0, (sp)4++
264 +#endif
265 + ret (sp)4++
266 +
267 + .section .fini
268 +#ifdef __UBICOM32_FDPIC__
269 + move.4 a0, (sp)4++
270 +#endif
271 + ret (sp)4++
272 --- /dev/null
273 +++ b/gcc/config/ubicom32/elf.h
274 @@ -0,0 +1,29 @@
275 +#undef STARTFILE_SPEC
276 +#define STARTFILE_SPEC "\
277 +%{msim:%{!shared:crt0%O%s}} \
278 +crti%O%s crtbegin%O%s"
279 +
280 +#undef ENDFILE_SPEC
281 +#define ENDFILE_SPEC "crtend%O%s crtn%O%s"
282 +
283 +#ifdef __UBICOM32_FDPIC__
284 +#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
285 + asm (SECTION_OP); \
286 + asm ("move.4 a0, 0(sp);\n\t" \
287 + "call a5," USER_LABEL_PREFIX #FUNC ";"); \
288 + asm (TEXT_SECTION_ASM_OP);
289 +#endif
290 +
291 +#undef SUBTARGET_DRIVER_SELF_SPECS
292 +#define SUBTARGET_DRIVER_SELF_SPECS \
293 + "%{mfdpic:-msim} "
294 +
295 +#define NO_IMPLICIT_EXTERN_C
296 +
297 +/*
298 + * We need this to compile crtbegin/crtend. This should really be picked
299 + * up from elfos.h but at the moment including elfos.h causes other more
300 + * serous linker issues.
301 + */
302 +#define INIT_SECTION_ASM_OP "\t.section\t.init"
303 +#define FINI_SECTION_ASM_OP "\t.section\t.fini"
304 --- /dev/null
305 +++ b/gcc/config/ubicom32/linux.h
306 @@ -0,0 +1,80 @@
307 +/* Definitions of target machine for Ubicom32-uclinux
308 +
309 + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
310 + 2009 Free Software Foundation, Inc.
311 + Contributed by Ubicom, Inc.
312 +
313 + This file is part of GCC.
314 +
315 + GCC is free software; you can redistribute it and/or modify it
316 + under the terms of the GNU General Public License as published
317 + by the Free Software Foundation; either version 3, or (at your
318 + option) any later version.
319 +
320 + GCC is distributed in the hope that it will be useful, but WITHOUT
321 + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
322 + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
323 + License for more details.
324 +
325 + You should have received a copy of the GNU General Public License
326 + along with GCC; see the file COPYING3. If not see
327 + <http://www.gnu.org/licenses/>. */
328 +
329 +/* Don't assume anything about the header files. */
330 +#define NO_IMPLICIT_EXTERN_C
331 +
332 +#undef LIB_SPEC
333 +#define LIB_SPEC \
334 + "%{pthread:-lpthread} " \
335 + "-lc"
336 +
337 +#undef LINK_GCC_C_SEQUENCE_SPEC
338 +#define LINK_GCC_C_SEQUENCE_SPEC \
339 + "%{static:--start-group} %G %L %{static:--end-group} " \
340 + "%{!static: %G}"
341 +
342 +#undef STARTFILE_SPEC
343 +#define STARTFILE_SPEC \
344 + "%{!shared: %{pg|p|profile:gcrt1%O%s;pie:Scrt1%O%s;:crt1%O%s}} " \
345 + "crtreloc%O%s crti%O%s %{shared|pie:crtbeginS%O%s;:crtbegin%O%s}"
346 +
347 +#undef ENDFILE_SPEC
348 +#define ENDFILE_SPEC \
349 + "%{shared|pie:crtendS%O%s;:crtend%O%s} crtn%O%s"
350 +
351 +/* taken from linux.h */
352 +/* The GNU C++ standard library requires that these macros be defined. */
353 +#undef CPLUSPLUS_CPP_SPEC
354 +#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
355 +
356 +#define TARGET_OS_CPP_BUILTINS() \
357 + do { \
358 + builtin_define_std ("__UBICOM32__"); \
359 + builtin_define_std ("__ubicom32__"); \
360 + builtin_define ("__gnu_linux__"); \
361 + builtin_define_std ("linux"); \
362 + builtin_define_std ("unix"); \
363 + builtin_assert ("system=linux"); \
364 + builtin_assert ("system=unix"); \
365 + builtin_assert ("system=posix"); \
366 + } while (0)
367 +
368 +#define OBJECT_FORMAT_ELF
369 +
370 +
371 +#undef DRIVER_SELF_SPECS
372 +#define DRIVER_SELF_SPECS \
373 + "%{!mno-fdpic:-mfdpic}"
374 +
375 +#undef LINK_SPEC
376 +#define LINK_SPEC "%{mfdpic: -m elf32ubicom32fdpic -z text } %{shared} %{pie} \
377 + %{static:-dn -Bstatic} \
378 + %{shared:-G -Bdynamic} \
379 + %{!shared: %{!static: \
380 + %{rdynamic:-export-dynamic} \
381 + %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}} \
382 + %{static}} "
383 +
384 +/*
385 +#define MD_UNWIND_SUPPORT "config/bfin/linux-unwind.h"
386 +*/
387 --- /dev/null
388 +++ b/gcc/config/ubicom32/predicates.md
389 @@ -0,0 +1,327 @@
390 +; Predicate definitions for Ubicom32.
391 +
392 +; Copyright (C) 2009 Free Software Foundation, Inc.
393 +; Contributed by Ubicom, Inc.
394 +
395 +; This file is part of GCC.
396 +
397 +; GCC is free software; you can redistribute it and/or modify it
398 +; under the terms of the GNU General Public License as published
399 +; by the Free Software Foundation; either version 3, or (at your
400 +; option) any later version.
401 +
402 +; GCC is distributed in the hope that it will be useful, but WITHOUT
403 +; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
404 +; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
405 +; License for more details.
406 +
407 +; You should have received a copy of the GNU General Public License
408 +; along with GCC; see the file COPYING3. If not see
409 +; <http://www.gnu.org/licenses/>.
410 +
411 +(define_predicate "ubicom32_move_operand"
412 + (match_code "const_int, const_double, const, mem, subreg, reg, lo_sum")
413 +{
414 + if (CONST_INT_P (op))
415 + return true;
416 +
417 + if (GET_CODE (op) == CONST_DOUBLE)
418 + return true;
419 +
420 + if (GET_CODE (op) == CONST)
421 + return memory_address_p (mode, op);
422 +
423 + if (GET_MODE (op) != mode)
424 + return false;
425 +
426 + if (MEM_P (op))
427 + return memory_address_p (mode, XEXP (op, 0));
428 +
429 + if (GET_CODE (op) == SUBREG) {
430 + op = SUBREG_REG (op);
431 +
432 + if (REG_P (op))
433 + return true;
434 +
435 + if (! MEM_P (op))
436 + return false;
437 +
438 + /* Paradoxical SUBREG. */
439 + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (op)))
440 + return false;
441 +
442 + return memory_address_p (GET_MODE (op), XEXP (op, 0));
443 + }
444 +
445 + return register_operand (op, mode);
446 +})
447 +
448 +;; Returns true if OP is either a symbol reference or a sum of a
449 +;; symbol reference and a constant.
450 +
451 +(define_predicate "ubicom32_symbolic_address_operand"
452 + (match_code "symbol_ref, label_ref, const")
453 +{
454 + switch (GET_CODE (op))
455 + {
456 + case SYMBOL_REF:
457 + case LABEL_REF:
458 + return true;
459 +
460 + case CONST:
461 + op = XEXP (op, 0);
462 + return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
463 + || GET_CODE (XEXP (op, 0)) == LABEL_REF)
464 + && CONST_INT_P (XEXP (op, 1)));
465 +
466 + default:
467 + return false;
468 + }
469 +})
470 +
471 +;; Return true if operand is the uClinux FD-PIC register.
472 +
473 +(define_predicate "ubicom32_fdpic_operand"
474 + (match_code "reg")
475 +{
476 + if (! TARGET_FDPIC)
477 + return false;
478 +
479 + if (!REG_P (op))
480 + return false;
481 +
482 + if (GET_MODE (op) != mode && mode != VOIDmode)
483 + return false;
484 +
485 + if (REGNO (op) != FDPIC_REGNUM && REGNO (op) < FIRST_PSEUDO_REGISTER)
486 + return false;
487 +
488 + return true;
489 +})
490 +
491 +(define_predicate "ubicom32_fdpic_got_offset_operand"
492 + (match_code "unspec")
493 +{
494 + if (! TARGET_FDPIC)
495 + return false;
496 +
497 + if (GET_CODE (op) != UNSPEC)
498 + return false;
499 +
500 + if (XINT (op, 1) != UNSPEC_FDPIC_GOT
501 + && XINT (op, 1) != UNSPEC_FDPIC_GOT_FUNCDESC)
502 + return false;
503 +
504 + return true;
505 +})
506 +
507 +(define_predicate "ubicom32_arith_operand"
508 + (match_code "subreg, reg, const_int, lo_sum, mem")
509 +{
510 + return (ubicom32_move_operand (op, mode)
511 + && ! ubicom32_symbolic_address_operand (op, mode)
512 + && (! CONST_INT_P (op)
513 + || satisfies_constraint_I (op)));
514 +})
515 +
516 +(define_predicate "ubicom32_arith_operand_dot1"
517 + (match_code "subreg, reg, const_int, lo_sum, mem")
518 +{
519 + return (ubicom32_move_operand (op, mode)
520 + && ! ubicom32_symbolic_address_operand (op, mode)
521 + && (! CONST_INT_P (op)
522 + || satisfies_constraint_Q (op)));
523 +})
524 +
525 +(define_predicate "ubicom32_arith_operand_dot2"
526 + (match_code "subreg, reg, const_int, lo_sum, mem")
527 +{
528 + return (ubicom32_move_operand (op, mode)
529 + && ! ubicom32_symbolic_address_operand (op, mode)
530 + && (! CONST_INT_P (op)
531 + || satisfies_constraint_R (op)));
532 +})
533 +
534 +(define_predicate "ubicom32_compare_operand"
535 + (match_code "subreg, reg, const_int, lo_sum, mem")
536 +{
537 + return (ubicom32_move_operand (op, mode)
538 + && ! ubicom32_symbolic_address_operand (op, mode)
539 + && (! CONST_INT_P (op)
540 + || satisfies_constraint_N (op)));
541 +})
542 +
543 +(define_predicate "ubicom32_compare_operator"
544 + (match_code "compare"))
545 +
546 +(define_predicate "ubicom32_and_or_si3_operand"
547 + (match_code "subreg, reg, const_int, lo_sum, mem")
548 +{
549 + return (ubicom32_arith_operand (op, mode)
550 + || (CONST_INT_P (op)
551 + && ((exact_log2 (INTVAL (op) + 1) != -1
552 + && exact_log2 (INTVAL (op) + 1) <= 31)
553 + || (exact_log2 (INTVAL (op)) != -1
554 + && exact_log2 (INTVAL (op)) <= 31)
555 + || (exact_log2 (~INTVAL (op)) != -1
556 + && exact_log2 (~INTVAL (op)) <= 31))));
557 +})
558 +
559 +(define_predicate "ubicom32_and_or_hi3_operand"
560 + (match_code "subreg, reg, const_int, lo_sum, mem")
561 +{
562 + return (ubicom32_arith_operand (op, mode)
563 + || (CONST_INT_P (op)
564 + && exact_log2 (INTVAL (op) + 1) != -1
565 + && exact_log2 (INTVAL (op) + 1) <= 15));
566 +})
567 +
568 +(define_predicate "ubicom32_mem_or_address_register_operand"
569 + (match_code "subreg, reg, mem")
570 +{
571 + unsigned int regno;
572 +
573 + if (MEM_P (op)
574 + && memory_operand (op, mode))
575 + return true;
576 +
577 + if (REG_P (op))
578 + regno = REGNO (op);
579 + else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
580 + {
581 + int offset;
582 + if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
583 + offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
584 + else
585 + offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
586 + GET_MODE (SUBREG_REG (op)),
587 + SUBREG_BYTE (op),
588 + GET_MODE (op));
589 + regno = REGNO (SUBREG_REG (op)) + offset;
590 + }
591 + else
592 + return false;
593 +
594 + return (regno >= FIRST_PSEUDO_REGISTER
595 + || REGNO_REG_CLASS (regno) == FDPIC_REG
596 + || REGNO_REG_CLASS (regno) == ADDRESS_REGS);
597 +})
598 +
599 +(define_predicate "ubicom32_data_register_operand"
600 + (match_code "subreg, reg")
601 +{
602 + unsigned int regno;
603 +
604 + if (REG_P (op))
605 + regno = REGNO (op);
606 + else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
607 + {
608 + int offset;
609 + if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
610 + offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
611 + else
612 + offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
613 + GET_MODE (SUBREG_REG (op)),
614 + SUBREG_BYTE (op),
615 + GET_MODE (op));
616 + regno = REGNO (SUBREG_REG (op)) + offset;
617 + }
618 + else
619 + return false;
620 +
621 + return ((regno >= FIRST_PSEUDO_REGISTER
622 + && regno != REGNO (virtual_stack_vars_rtx))
623 + || REGNO_REG_CLASS (regno) == DATA_REGS);
624 +})
625 +
626 +(define_predicate "ubicom32_address_register_operand"
627 + (match_code "subreg, reg")
628 +{
629 + unsigned int regno;
630 +
631 + if (REG_P (op))
632 + regno = REGNO (op);
633 + else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
634 + {
635 + int offset;
636 + if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
637 + offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
638 + else
639 + offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
640 + GET_MODE (SUBREG_REG (op)),
641 + SUBREG_BYTE (op),
642 + GET_MODE (op));
643 + regno = REGNO (SUBREG_REG (op)) + offset;
644 + }
645 + else
646 + return false;
647 +
648 + return (regno >= FIRST_PSEUDO_REGISTER
649 + || REGNO_REG_CLASS (regno) == FDPIC_REG
650 + || REGNO_REG_CLASS (regno) == ADDRESS_REGS);
651 +})
652 +
653 +(define_predicate "ubicom32_acc_lo_register_operand"
654 + (match_code "subreg, reg")
655 +{
656 + unsigned int regno;
657 +
658 + if (REG_P (op))
659 + regno = REGNO (op);
660 + else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
661 + {
662 + int offset;
663 + if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
664 + offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
665 + else
666 + offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
667 + GET_MODE (SUBREG_REG (op)),
668 + SUBREG_BYTE (op),
669 + GET_MODE (op));
670 + regno = REGNO (SUBREG_REG (op)) + offset;
671 + }
672 + else
673 + return false;
674 +
675 + return ((regno >= FIRST_PSEUDO_REGISTER
676 + && regno != REGNO (virtual_stack_vars_rtx))
677 + || REGNO_REG_CLASS (regno) == ACC_LO_REGS);
678 +})
679 +
680 +(define_predicate "ubicom32_acc_hi_register_operand"
681 + (match_code "subreg, reg")
682 +{
683 + unsigned int regno;
684 +
685 + if (REG_P (op))
686 + regno = REGNO (op);
687 + else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
688 + {
689 + int offset;
690 + if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
691 + offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
692 + else
693 + offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
694 + GET_MODE (SUBREG_REG (op)),
695 + SUBREG_BYTE (op),
696 + GET_MODE (op));
697 + regno = REGNO (SUBREG_REG (op)) + offset;
698 + }
699 + else
700 + return false;
701 +
702 + return ((regno >= FIRST_PSEUDO_REGISTER
703 + && regno != REGNO (virtual_stack_vars_rtx))
704 + || REGNO_REG_CLASS (regno) == ACC_REGS);
705 +})
706 +
707 +(define_predicate "ubicom32_call_address_operand"
708 + (match_code "symbol_ref, subreg, reg")
709 +{
710 + return (GET_CODE (op) == SYMBOL_REF || REG_P (op));
711 +})
712 +
713 +(define_special_predicate "ubicom32_cc_register_operand"
714 + (and (match_code "reg")
715 + (match_test "REGNO (op) == CC_REGNUM")))
716 +
717 --- /dev/null
718 +++ b/gcc/config/ubicom32/t-ubicom32
719 @@ -0,0 +1,52 @@
720 +# Name of assembly file containing libgcc1 functions.
721 +# This entry must be present, but it can be empty if the target does
722 +# not need any assembler functions to support its code generation.
723 +CROSS_LIBGCC1 =
724 +
725 +# Alternatively if assembler functions *are* needed then define the
726 +# entries below:
727 +# CROSS_LIBGCC1 = libgcc1-asm.a
728 +
729 +LIB2FUNCS_EXTRA = \
730 + $(srcdir)/config/udivmodsi4.c \
731 + $(srcdir)/config/divmod.c \
732 + $(srcdir)/config/udivmod.c
733 +
734 +# If any special flags are necessary when building libgcc2 put them here.
735 +#
736 +# TARGET_LIBGCC2_CFLAGS =
737 +
738 +# We want fine grained libraries, so use the new code to build the
739 +# floating point emulation libraries.
740 +FPBIT = fp-bit.c
741 +DPBIT = dp-bit.c
742 +
743 +fp-bit.c: $(srcdir)/config/fp-bit.c
744 + echo '#define FLOAT' > fp-bit.c
745 + cat $(srcdir)/config/fp-bit.c >> fp-bit.c
746 +
747 +dp-bit.c: $(srcdir)/config/fp-bit.c
748 + cat $(srcdir)/config/fp-bit.c > dp-bit.c
749 +
750 +# Commented out to speed up compiler development!
751 +#
752 +# MULTILIB_OPTIONS = march=ubicom32v1/march=ubicom32v2/march=ubicom32v3/march=ubicom32v4
753 +# MULTILIB_DIRNAMES = ubicom32v1 ubicom32v2 ubicom32v3 ubicom32v4
754 +
755 +MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
756 +MULTILIB_OPTIONS += mfdpic
757 +MULTILIB_OPTIONS += mno-ipos-abi/mipos-abi
758 +MULTILIB_OPTIONS += fno-leading-underscore/fleading-underscore
759 +
760 +# Assemble startup files.
761 +$(T)crti.o: $(srcdir)/config/ubicom32/crti.S $(GCC_PASSES)
762 + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
763 + -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/ubicom32/crti.S
764 +
765 +$(T)crtn.o: $(srcdir)/config/ubicom32/crtn.S $(GCC_PASSES)
766 + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
767 + -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/ubicom32/crtn.S
768 +
769 +# these parts are required because uClibc ldso needs them to link.
770 +# they are not in the specfile so they will not be included automatically.
771 +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o crti.o crtn.o
772 --- /dev/null
773 +++ b/gcc/config/ubicom32/t-ubicom32-linux
774 @@ -0,0 +1,35 @@
775 +# Name of assembly file containing libgcc1 functions.
776 +# This entry must be present, but it can be empty if the target does
777 +# not need any assembler functions to support its code generation.
778 +CROSS_LIBGCC1 =
779 +
780 +# Alternatively if assembler functions *are* needed then define the
781 +# entries below:
782 +# CROSS_LIBGCC1 = libgcc1-asm.a
783 +
784 +LIB2FUNCS_EXTRA = \
785 + $(srcdir)/config/udivmodsi4.c \
786 + $(srcdir)/config/divmod.c \
787 + $(srcdir)/config/udivmod.c
788 +
789 +# If any special flags are necessary when building libgcc2 put them here.
790 +#
791 +# TARGET_LIBGCC2_CFLAGS =
792 +
793 +# We want fine grained libraries, so use the new code to build the
794 +# floating point emulation libraries.
795 +FPBIT = fp-bit.c
796 +DPBIT = dp-bit.c
797 +
798 +fp-bit.c: $(srcdir)/config/fp-bit.c
799 + echo '#define FLOAT' > fp-bit.c
800 + cat $(srcdir)/config/fp-bit.c >> fp-bit.c
801 +
802 +dp-bit.c: $(srcdir)/config/fp-bit.c
803 + cat $(srcdir)/config/fp-bit.c > dp-bit.c
804 +
805 +# We only support v3 and v4 ISAs for uClinux.
806 +
807 +MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
808 +
809 +#EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o
810 --- /dev/null
811 +++ b/gcc/config/ubicom32/t-ubicom32-uclinux
812 @@ -0,0 +1,35 @@
813 +# Name of assembly file containing libgcc1 functions.
814 +# This entry must be present, but it can be empty if the target does
815 +# not need any assembler functions to support its code generation.
816 +CROSS_LIBGCC1 =
817 +
818 +# Alternatively if assembler functions *are* needed then define the
819 +# entries below:
820 +# CROSS_LIBGCC1 = libgcc1-asm.a
821 +
822 +LIB2FUNCS_EXTRA = \
823 + $(srcdir)/config/udivmodsi4.c \
824 + $(srcdir)/config/divmod.c \
825 + $(srcdir)/config/udivmod.c
826 +
827 +# If any special flags are necessary when building libgcc2 put them here.
828 +#
829 +# TARGET_LIBGCC2_CFLAGS =
830 +
831 +# We want fine grained libraries, so use the new code to build the
832 +# floating point emulation libraries.
833 +FPBIT = fp-bit.c
834 +DPBIT = dp-bit.c
835 +
836 +fp-bit.c: $(srcdir)/config/fp-bit.c
837 + echo '#define FLOAT' > fp-bit.c
838 + cat $(srcdir)/config/fp-bit.c >> fp-bit.c
839 +
840 +dp-bit.c: $(srcdir)/config/fp-bit.c
841 + cat $(srcdir)/config/fp-bit.c > dp-bit.c
842 +
843 +# We only support v3 and v4 ISAs for uClinux.
844 +
845 +MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
846 +
847 +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o # crtbeginS.o crtendS.o
848 --- /dev/null
849 +++ b/gcc/config/ubicom32/ubicom32-modes.def
850 @@ -0,0 +1,30 @@
851 +/* Definitions of target machine for GNU compiler, Ubicom32 architecture.
852 + Copyright (C) 2009 Free Software Foundation, Inc.
853 + Contributed by Ubicom, Inc.
854 +
855 + This file is part of GCC.
856 +
857 + GCC is free software; you can redistribute it and/or modify it
858 + under the terms of the GNU General Public License as published
859 + by the Free Software Foundation; either version 3, or (at your
860 + option) any later version.
861 +
862 + GCC is distributed in the hope that it will be useful, but WITHOUT
863 + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
864 + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
865 + License for more details.
866 +
867 + You should have received a copy of the GNU General Public License
868 + along with GCC; see the file COPYING3. If not see
869 + <http://www.gnu.org/licenses/>. */
870 +
871 +/* Some insns set all condition code flags, some only set the Z and N flags, and
872 + some only set the Z flag. */
873 +
874 +CC_MODE (CCW);
875 +CC_MODE (CCWZN);
876 +CC_MODE (CCWZ);
877 +CC_MODE (CCS);
878 +CC_MODE (CCSZN);
879 +CC_MODE (CCSZ);
880 +
881 --- /dev/null
882 +++ b/gcc/config/ubicom32/ubicom32-protos.h
883 @@ -0,0 +1,84 @@
884 +/* Function prototypes for Ubicom IP3000.
885 +
886 + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
887 + 2009 Free Software Foundation, Inc.
888 + Contributed by Ubicom, Inc.
889 +
890 + This file is part of GNU CC.
891 +
892 + GNU CC is free software; you can redistribute it and/or modify it under
893 + the terms of the GNU General Public License as published by the Free
894 + Software Foundation; either version 2, or (at your option) any later
895 + version.
896 +
897 + GNU CC is distributed in the hope that it will be useful, but WITHOUT
898 + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
899 + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
900 + for more details.
901 +
902 + You should have received a copy of the GNU General Public License along
903 + with GNU CC; see the file COPYING. If not, write to the Free Software
904 + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
905 +
906 +#ifdef RTX_CODE
907 +
908 +#ifdef TREE_CODE
909 +extern void ubicom32_va_start (tree, rtx);
910 +#endif /* TREE_CODE */
911 +
912 +extern void ubicom32_print_operand (FILE *, rtx, int);
913 +extern void ubicom32_print_operand_address (FILE *, rtx);
914 +
915 +extern void ubicom32_conditional_register_usage (void);
916 +extern enum reg_class ubicom32_preferred_reload_class (rtx, enum reg_class);
917 +extern int ubicom32_regno_ok_for_index_p (int, int);
918 +extern void ubicom32_expand_movsi (rtx *);
919 +extern void ubicom32_expand_addsi3 (rtx *);
920 +extern int ubicom32_emit_mult_sequence (rtx *);
921 +extern void ubicom32_emit_move_const_int (rtx, rtx);
922 +extern bool ubicom32_legitimate_constant_p (rtx);
923 +extern bool ubicom32_legitimate_address_p (enum machine_mode, rtx, int);
924 +extern rtx ubicom32_legitimize_address (rtx, rtx, enum machine_mode);
925 +extern rtx ubicom32_legitimize_reload_address (rtx, enum machine_mode, int, int);
926 +extern void ubicom32_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1);
927 +extern int ubicom32_mode_dependent_address_p (rtx);
928 +extern void ubicom32_output_cond_jump (rtx, rtx, rtx);
929 +extern void ubicom32_expand_eh_return (rtx *);
930 +extern void ubicom32_expand_call_fdpic (rtx *);
931 +extern void ubicom32_expand_call_value_fdpic (rtx *);
932 +extern enum machine_mode ubicom32_select_cc_mode (RTX_CODE, rtx, rtx);
933 +extern rtx ubicom32_gen_compare_reg (RTX_CODE, rtx, rtx);
934 +extern int ubicom32_shiftable_const_int (int);
935 +#endif /* RTX_CODE */
936 +
937 +#ifdef TREE_CODE
938 +extern void init_cumulative_args (CUMULATIVE_ARGS *cum,
939 + tree fntype,
940 + struct rtx_def *libname,
941 + int indirect);
942 +extern struct rtx_def *function_arg (CUMULATIVE_ARGS *,
943 + enum machine_mode, tree, int);
944 +extern struct rtx_def *function_incoming_arg (CUMULATIVE_ARGS *,
945 + enum machine_mode,
946 + tree, int);
947 +extern int function_arg_partial_nregs (CUMULATIVE_ARGS *,
948 + enum machine_mode, tree, int);
949 +extern struct rtx_def *ubicom32_va_arg (tree, tree);
950 +extern int ubicom32_reg_parm_stack_space (tree);
951 +#endif /* TREE_CODE */
952 +
953 +extern struct rtx_def * ubicom32_builtin_saveregs (void);
954 +extern void asm_file_start (FILE *);
955 +extern void ubicom32_expand_prologue (void);
956 +extern void ubicom32_expand_epilogue (void);
957 +extern int ubicom32_initial_elimination_offset (int, int);
958 +extern int ubicom32_regno_ok_for_base_p (int, int);
959 +extern bool ubicom32_hard_regno_mode_ok (unsigned int, enum machine_mode);
960 +extern int ubicom32_can_use_return_insn_p (void);
961 +extern rtx ubicom32_return_addr_rtx (int, rtx);
962 +extern void ubicom32_optimization_options (int, int);
963 +extern void ubicom32_override_options (void);
964 +extern bool ubicom32_match_cc_mode (rtx, enum machine_mode);
965 +
966 +extern int ubicom32_reorg_completed;
967 +
968 --- /dev/null
969 +++ b/gcc/config/ubicom32/ubicom32.c
970 @@ -0,0 +1,2881 @@
971 +/* Subroutines for insn-output.c for Ubicom32
972 +
973 + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
974 + 2009 Free Software Foundation, Inc.
975 + Contributed by Ubicom, Inc.
976 +
977 + This file is part of GCC.
978 +
979 + GCC is free software; you can redistribute it and/or modify it
980 + under the terms of the GNU General Public License as published
981 + by the Free Software Foundation; either version 3, or (at your
982 + option) any later version.
983 +
984 + GCC is distributed in the hope that it will be useful, but WITHOUT
985 + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
986 + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
987 + License for more details.
988 +
989 + You should have received a copy of the GNU General Public License
990 + along with GCC; see the file COPYING3. If not see
991 + <http://www.gnu.org/licenses/>. */
992 +
993 +#include "config.h"
994 +#include "system.h"
995 +#include "coretypes.h"
996 +#include "tm.h"
997 +#include "rtl.h"
998 +#include "tree.h"
999 +#include "regs.h"
1000 +#include "hard-reg-set.h"
1001 +#include "real.h"
1002 +#include "insn-config.h"
1003 +#include "conditions.h"
1004 +#include "insn-flags.h"
1005 +#include "output.h"
1006 +#include "insn-attr.h"
1007 +#include "insn-codes.h"
1008 +#include "flags.h"
1009 +#include "recog.h"
1010 +#include "expr.h"
1011 +#include "function.h"
1012 +#include "obstack.h"
1013 +#include "toplev.h"
1014 +#include "tm_p.h"
1015 +#include "tm-constrs.h"
1016 +#include "basic-block.h"
1017 +#include "integrate.h"
1018 +#include "target.h"
1019 +#include "target-def.h"
1020 +#include "reload.h"
1021 +#include "df.h"
1022 +#include "langhooks.h"
1023 +#include "optabs.h"
1024 +
1025 +static tree ubicom32_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
1026 +static void ubicom32_layout_frame (void);
1027 +static void ubicom32_function_prologue (FILE *, HOST_WIDE_INT);
1028 +static void ubicom32_function_epilogue (FILE *, HOST_WIDE_INT);
1029 +static bool ubicom32_rtx_costs (rtx, int, int, int *, bool speed);
1030 +static bool ubicom32_fixed_condition_code_regs (unsigned int *,
1031 + unsigned int *);
1032 +static enum machine_mode ubicom32_cc_modes_compatible (enum machine_mode,
1033 + enum machine_mode);
1034 +static int ubicom32_naked_function_p (void);
1035 +static void ubicom32_machine_dependent_reorg (void);
1036 +static bool ubicom32_assemble_integer (rtx, unsigned int, int);
1037 +static void ubicom32_asm_init_sections (void);
1038 +static int ubicom32_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,tree,
1039 + bool);
1040 +static bool ubicom32_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
1041 + enum machine_mode mode, const_tree type,
1042 + bool named ATTRIBUTE_UNUSED);
1043 +static bool ubicom32_callee_copies (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
1044 + enum machine_mode mode, const_tree type,
1045 + bool named ATTRIBUTE_UNUSED);
1046 +
1047 +static bool ubicom32_return_in_memory (const_tree type,
1048 + const_tree fntype ATTRIBUTE_UNUSED);
1049 +static bool ubicom32_is_base_reg (rtx, int);
1050 +static void ubicom32_init_builtins (void);
1051 +static rtx ubicom32_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
1052 +static tree ubicom32_fold_builtin (tree, tree, bool);
1053 +static int ubicom32_get_valid_offset_mask (enum machine_mode);
1054 +static bool ubicom32_cannot_force_const_mem (rtx);
1055 +
1056 +/* Case values threshold */
1057 +int ubicom32_case_values_threshold = 6;
1058 +
1059 +/* Nonzero if this chip supports the Ubicom32 v3 ISA. */
1060 +int ubicom32_v3 = 1;
1061 +
1062 +/* Nonzero if this chip supports the Ubicom32 v4 ISA. */
1063 +int ubicom32_v4 = 1;
1064 +
1065 +/* Valid attributes:
1066 + naked - don't generate function prologue/epilogue and `ret' command. */
1067 +const struct attribute_spec ubicom32_attribute_table[] =
1068 +{
1069 + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1070 + { "naked", 0, 0, true, false, false, ubicom32_handle_fndecl_attribute },
1071 + { NULL, 0, 0, false, false, false, NULL }
1072 +};
1073 +
1074 +#undef TARGET_ASM_FUNCTION_PROLOGUE
1075 +#define TARGET_ASM_FUNCTION_PROLOGUE ubicom32_function_prologue
1076 +
1077 +#undef TARGET_ASM_FUNCTION_EPILOGUE
1078 +#define TARGET_ASM_FUNCTION_EPILOGUE ubicom32_function_epilogue
1079 +
1080 +#undef TARGET_ATTRIBUTE_TABLE
1081 +#define TARGET_ATTRIBUTE_TABLE ubicom32_attribute_table
1082 +
1083 +/* All addresses cost the same amount. */
1084 +#undef TARGET_ADDRESS_COST
1085 +#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
1086 +
1087 +#undef TARGET_RTX_COSTS
1088 +#define TARGET_RTX_COSTS ubicom32_rtx_costs
1089 +
1090 +#undef TARGET_FIXED_CONDITION_CODE_REGS
1091 +#define TARGET_FIXED_CONDITION_CODE_REGS ubicom32_fixed_condition_code_regs
1092 +
1093 +#undef TARGET_CC_MODES_COMPATIBLE
1094 +#define TARGET_CC_MODES_COMPATIBLE ubicom32_cc_modes_compatible
1095 +
1096 +#undef TARGET_MACHINE_DEPENDENT_REORG
1097 +#define TARGET_MACHINE_DEPENDENT_REORG ubicom32_machine_dependent_reorg
1098 +
1099 +#undef TARGET_ASM_INTEGER
1100 +#define TARGET_ASM_INTEGER ubicom32_assemble_integer
1101 +
1102 +#undef TARGET_ASM_INIT_SECTIONS
1103 +#define TARGET_ASM_INIT_SECTIONS ubicom32_asm_init_sections
1104 +
1105 +#undef TARGET_ARG_PARTIAL_BYTES
1106 +#define TARGET_ARG_PARTIAL_BYTES ubicom32_arg_partial_bytes
1107 +
1108 +#undef TARGET_PASS_BY_REFERENCE
1109 +#define TARGET_PASS_BY_REFERENCE ubicom32_pass_by_reference
1110 +
1111 +#undef TARGET_CALLEE_COPIES
1112 +#define TARGET_CALLEE_COPIES ubicom32_callee_copies
1113 +
1114 +#undef TARGET_RETURN_IN_MEMORY
1115 +#define TARGET_RETURN_IN_MEMORY ubicom32_return_in_memory
1116 +
1117 +#undef TARGET_INIT_BUILTINS
1118 +#define TARGET_INIT_BUILTINS ubicom32_init_builtins
1119 +
1120 +#undef TARGET_EXPAND_BUILTIN
1121 +#define TARGET_EXPAND_BUILTIN ubicom32_expand_builtin
1122 +
1123 +#undef TARGET_FOLD_BUILTIN
1124 +#define TARGET_FOLD_BUILTIN ubicom32_fold_builtin
1125 +
1126 +#undef TARGET_CANNOT_FORCE_CONST_MEM
1127 +#define TARGET_CANNOT_FORCE_CONST_MEM ubicom32_cannot_force_const_mem
1128 +
1129 +struct gcc_target targetm = TARGET_INITIALIZER;
1130 +
1131 +static char save_regs[FIRST_PSEUDO_REGISTER];
1132 +static int nregs;
1133 +static int frame_size;
1134 +int ubicom32_stack_size = 0; /* size of allocated stack (including frame) */
1135 +int ubicom32_can_use_calli_to_ret;
1136 +
1137 +#define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
1138 +#define ROUND_CALL_BLOCK_SIZE(BYTES) \
1139 + (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
1140 +
1141 +/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
1142 + must report the mode of the memory reference from PRINT_OPERAND to
1143 + PRINT_OPERAND_ADDRESS. */
1144 +enum machine_mode output_memory_reference_mode;
1145 +
1146 +/* Flag for some split insns from the ubicom32.md. */
1147 +int ubicom32_reorg_completed;
1148 +
1149 +enum reg_class const ubicom32_regclass_map[FIRST_PSEUDO_REGISTER] =
1150 +{
1151 + DATA_REGS,
1152 + DATA_REGS,
1153 + DATA_REGS,
1154 + DATA_REGS,
1155 + DATA_REGS,
1156 + DATA_REGS,
1157 + DATA_REGS,
1158 + DATA_REGS,
1159 + DATA_REGS,
1160 + DATA_REGS,
1161 + DATA_REGS,
1162 + DATA_REGS,
1163 + DATA_REGS,
1164 + DATA_REGS,
1165 + DATA_REGS,
1166 + DATA_REGS,
1167 + FDPIC_REG,
1168 + ADDRESS_REGS,
1169 + ADDRESS_REGS,
1170 + ADDRESS_REGS,
1171 + ADDRESS_REGS,
1172 + ADDRESS_REGS,
1173 + ADDRESS_REGS,
1174 + ADDRESS_REGS,
1175 + ACC_REGS,
1176 + ACC_LO_REGS,
1177 + ACC_REGS,
1178 + ACC_LO_REGS,
1179 + SOURCE3_REG,
1180 + ADDRESS_REGS,
1181 + NO_REGS, /* CC_REG must be NO_REGS */
1182 + SPECIAL_REGS,
1183 + SPECIAL_REGS,
1184 + SPECIAL_REGS,
1185 + SPECIAL_REGS,
1186 + SPECIAL_REGS,
1187 + SPECIAL_REGS,
1188 + SPECIAL_REGS,
1189 + SPECIAL_REGS
1190 +};
1191 +
1192 +rtx ubicom32_compare_op0;
1193 +rtx ubicom32_compare_op1;
1194 +
1195 +/* Handle command line option overrides. */
1196 +
1197 +void
1198 +ubicom32_override_options (void)
1199 +{
1200 + flag_pic = 0;
1201 +
1202 + if (strcmp (ubicom32_arch_name, "ubicom32v1") == 0) {
1203 + /* If we have a version 1 architecture then we want to avoid using jump
1204 + tables. */
1205 + ubicom32_case_values_threshold = 30000;
1206 + ubicom32_v3 = 0;
1207 + ubicom32_v4 = 0;
1208 + } else if (strcmp (ubicom32_arch_name, "ubicom32v2") == 0) {
1209 + ubicom32_v3 = 0;
1210 + ubicom32_v4 = 0;
1211 + } else if (strcmp (ubicom32_arch_name, "ubicom32v3") == 0) {
1212 + ubicom32_v3 = 1;
1213 + ubicom32_v4 = 0;
1214 + } else if (strcmp (ubicom32_arch_name, "ubicom32v4") == 0) {
1215 + ubicom32_v3 = 1;
1216 + ubicom32_v4 = 1;
1217 + }
1218 +
1219 + /* There is no single unaligned SI op for PIC code. Sometimes we
1220 + need to use ".4byte" and sometimes we need to use ".picptr".
1221 + See ubicom32_assemble_integer for details. */
1222 + if (TARGET_FDPIC)
1223 + targetm.asm_out.unaligned_op.si = 0;
1224 +}
1225 +
1226 +void
1227 +ubicom32_conditional_register_usage (void)
1228 +{
1229 + /* If we're using the old ipOS ABI we need to make D10 through D13
1230 + caller-clobbered. */
1231 + if (TARGET_IPOS_ABI)
1232 + {
1233 + call_used_regs[D10_REGNUM] = 1;
1234 + call_used_regs[D11_REGNUM] = 1;
1235 + call_used_regs[D12_REGNUM] = 1;
1236 + call_used_regs[D13_REGNUM] = 1;
1237 + }
1238 +}
1239 +
1240 +/* We have some number of optimizations that don't really work for the Ubicom32
1241 + architecture so we deal with them here. */
1242 +
1243 +void
1244 +ubicom32_optimization_options (int level ATTRIBUTE_UNUSED,
1245 + int size ATTRIBUTE_UNUSED)
1246 +{
1247 + /* The tree IVOPTs pass seems to do really bad things for the Ubicom32
1248 + architecture - it tends to turn things that would happily use pre/post
1249 + increment/decrement into operations involving unecessary loop
1250 + indicies. */
1251 + flag_ivopts = 0;
1252 +
1253 + /* We have problems where DSE at the RTL level misses partial stores
1254 + to the stack. For now we disable it to avoid this. */
1255 + flag_dse = 0;
1256 +}
1257 +
1258 +/* Print operand X using operand code CODE to assembly language output file
1259 + FILE. */
1260 +
1261 +void
1262 +ubicom32_print_operand (FILE *file, rtx x, int code)
1263 +{
1264 + switch (code)
1265 + {
1266 + case 'A':
1267 + /* Identify the correct accumulator to use. */
1268 + if (REGNO (x) == ACC0_HI_REGNUM || REGNO (x) == ACC0_LO_REGNUM)
1269 + fprintf (file, "acc0");
1270 + else if (REGNO (x) == ACC1_HI_REGNUM || REGNO (x) == ACC1_LO_REGNUM)
1271 + fprintf (file, "acc1");
1272 + else
1273 + abort ();
1274 + break;
1275 +
1276 + case 'b':
1277 + case 'B':
1278 + {
1279 + enum machine_mode mode;
1280 +
1281 + mode = GET_MODE (XEXP (x, 0));
1282 +
1283 + /* These are normal and reversed branches. */
1284 + switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
1285 + {
1286 + case NE:
1287 + fprintf (file, "ne");
1288 + break;
1289 +
1290 + case EQ:
1291 + fprintf (file, "eq");
1292 + break;
1293 +
1294 + case GE:
1295 + if (mode == CCSZNmode || mode == CCWZNmode)
1296 + fprintf (file, "pl");
1297 + else
1298 + fprintf (file, "ge");
1299 + break;
1300 +
1301 + case GT:
1302 + fprintf (file, "gt");
1303 + break;
1304 +
1305 + case LE:
1306 + fprintf (file, "le");
1307 + break;
1308 +
1309 + case LT:
1310 + if (mode == CCSZNmode || mode == CCWZNmode)
1311 + fprintf (file, "mi");
1312 + else
1313 + fprintf (file, "lt");
1314 + break;
1315 +
1316 + case GEU:
1317 + fprintf (file, "cs");
1318 + break;
1319 +
1320 + case GTU:
1321 + fprintf (file, "hi");
1322 + break;
1323 +
1324 + case LEU:
1325 + fprintf (file, "ls");
1326 + break;
1327 +
1328 + case LTU:
1329 + fprintf (file, "cc");
1330 + break;
1331 +
1332 + default:
1333 + abort ();
1334 + }
1335 + }
1336 + break;
1337 +
1338 + case 'C':
1339 + /* This is used for the operand to a call instruction;
1340 + if it's a REG, enclose it in parens, else output
1341 + the operand normally. */
1342 + if (REG_P (x))
1343 + {
1344 + fputc ('(', file);
1345 + ubicom32_print_operand (file, x, 0);
1346 + fputc (')', file);
1347 + }
1348 + else
1349 + ubicom32_print_operand (file, x, 0);
1350 + break;
1351 +
1352 + case 'd':
1353 + /* Bit operations we need bit numbers. */
1354 + fprintf (file, "%d", exact_log2 (INTVAL (x)));
1355 + break;
1356 +
1357 + case 'D':
1358 + /* Bit operations we need bit numbers. */
1359 + fprintf (file, "%d", exact_log2 (~ INTVAL (x)));
1360 + break;
1361 +
1362 + case 'E':
1363 + /* For lea, which we use to add address registers.
1364 + We don't want the '#' on a constant. */
1365 + if (CONST_INT_P (x))
1366 + {
1367 + fprintf (file, "%ld", INTVAL (x));
1368 + break;
1369 + }
1370 + /* FALL THROUGH */
1371 +
1372 + default:
1373 + switch (GET_CODE (x))
1374 + {
1375 + case MEM:
1376 + output_memory_reference_mode = GET_MODE (x);
1377 + output_address (XEXP (x, 0));
1378 + break;
1379 +
1380 + case PLUS:
1381 + output_address (x);
1382 + break;
1383 +
1384 + case REG:
1385 + fprintf (file, "%s", reg_names[REGNO (x)]);
1386 + break;
1387 +
1388 + case SUBREG:
1389 + fprintf (file, "%s", reg_names[subreg_regno (x)]);
1390 + break;
1391 +
1392 + /* This will only be single precision.... */
1393 + case CONST_DOUBLE:
1394 + {
1395 + unsigned long val;
1396 + REAL_VALUE_TYPE rv;
1397 +
1398 + REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1399 + REAL_VALUE_TO_TARGET_SINGLE (rv, val);
1400 + fprintf (file, "0x%lx", val);
1401 + break;
1402 + }
1403 +
1404 + case CONST_INT:
1405 + case SYMBOL_REF:
1406 + case CONST:
1407 + case LABEL_REF:
1408 + case CODE_LABEL:
1409 + case LO_SUM:
1410 + ubicom32_print_operand_address (file, x);
1411 + break;
1412 +
1413 + case HIGH:
1414 + fprintf (file, "#%%hi(");
1415 + ubicom32_print_operand_address (file, XEXP (x, 0));
1416 + fprintf (file, ")");
1417 + break;
1418 +
1419 + case UNSPEC:
1420 + switch (XINT (x, 1))
1421 + {
1422 + case UNSPEC_FDPIC_GOT:
1423 + fprintf (file, "#%%got_lo(");
1424 + ubicom32_print_operand_address (file, XVECEXP (x, 0, 0));
1425 + fprintf (file, ")");
1426 + break;
1427 +
1428 + case UNSPEC_FDPIC_GOT_FUNCDESC:
1429 + fprintf (file, "#%%got_funcdesc_lo(");
1430 + ubicom32_print_operand_address (file, XVECEXP (x, 0, 0));
1431 + fprintf (file, ")");
1432 + break;
1433 +
1434 + default:
1435 + abort ();
1436 + }
1437 + break;
1438 +
1439 + default:
1440 + abort ();
1441 + }
1442 + break;
1443 + }
1444 +}
1445 +
1446 +/* Output assembly language output for the address ADDR to FILE. */
1447 +
1448 +void
1449 +ubicom32_print_operand_address (FILE *file, rtx addr)
1450 +{
1451 + switch (GET_CODE (addr))
1452 + {
1453 + case POST_INC:
1454 + ubicom32_print_operand_address (file, XEXP (addr, 0));
1455 + fprintf (file, "%d++", GET_MODE_SIZE (output_memory_reference_mode));
1456 + break;
1457 +
1458 + case PRE_INC:
1459 + fprintf (file, "%d", GET_MODE_SIZE (output_memory_reference_mode));
1460 + ubicom32_print_operand_address (file, XEXP (addr, 0));
1461 + fprintf (file, "++");
1462 + break;
1463 +
1464 + case POST_DEC:
1465 + ubicom32_print_operand_address (file, XEXP (addr, 0));
1466 + fprintf (file, "%d++", -GET_MODE_SIZE (output_memory_reference_mode));
1467 + break;
1468 +
1469 + case PRE_DEC:
1470 + fprintf (file, "%d", -GET_MODE_SIZE (output_memory_reference_mode));
1471 + ubicom32_print_operand_address (file, XEXP (addr, 0));
1472 + fprintf (file, "++");
1473 + break;
1474 +
1475 + case POST_MODIFY:
1476 + ubicom32_print_operand_address (file, XEXP (addr, 0));
1477 + fprintf (file, "%ld++", INTVAL (XEXP (XEXP (addr,1), 1)));
1478 + break;
1479 +
1480 + case PRE_MODIFY:
1481 + fprintf (file, "%ld", INTVAL (XEXP (XEXP (addr,1), 1)));
1482 + ubicom32_print_operand_address (file, XEXP (addr, 0));
1483 + fprintf (file, "++");
1484 + break;
1485 +
1486 + case REG:
1487 + fputc ('(', file);
1488 + fprintf (file, "%s", reg_names[REGNO (addr)]);
1489 + fputc (')', file);
1490 + break;
1491 +
1492 + case PLUS:
1493 + {
1494 + rtx base = XEXP (addr, 0);
1495 + rtx index = XEXP (addr, 1);
1496 +
1497 + /* Switch around addresses of the form index * scaling + base. */
1498 + if (! ubicom32_is_base_reg (base, 1))
1499 + {
1500 + rtx tmp = base;
1501 + base = index;
1502 + index = tmp;
1503 + }
1504 +
1505 + if (CONST_INT_P (index))
1506 + {
1507 + fprintf (file, "%ld", INTVAL (index));
1508 + fputc ('(', file);
1509 + fputs (reg_names[REGNO (base)], file);
1510 + }
1511 + else if (GET_CODE (index) == MULT
1512 + || REG_P (index))
1513 + {
1514 + if (GET_CODE (index) == MULT)
1515 + index = XEXP (index, 0);
1516 + fputc ('(', file);
1517 + fputs (reg_names[REGNO (base)], file);
1518 + fputc (',', file);
1519 + fputs (reg_names[REGNO (index)], file);
1520 + }
1521 + else
1522 + abort ();
1523 +
1524 + fputc (')', file);
1525 + break;
1526 + }
1527 +
1528 + case LO_SUM:
1529 + fprintf (file, "%%lo(");
1530 + ubicom32_print_operand (file, XEXP (addr, 1), 'L');
1531 + fprintf (file, ")(");
1532 + ubicom32_print_operand (file, XEXP (addr, 0), 0);
1533 + fprintf (file, ")");
1534 + break;
1535 +
1536 + case CONST_INT:
1537 + fputc ('#', file);
1538 + output_addr_const (file, addr);
1539 + break;
1540 +
1541 + default:
1542 + output_addr_const (file, addr);
1543 + break;
1544 + }
1545 +}
1546 +
1547 +/* X and Y are two things to compare using CODE. Emit the compare insn and
1548 + return the rtx for the cc reg in the proper mode. */
1549 +
1550 +rtx
1551 +ubicom32_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
1552 +{
1553 + enum machine_mode mode = SELECT_CC_MODE (code, x, y);
1554 + rtx cc_reg;
1555 +
1556 + cc_reg = gen_rtx_REG (mode, CC_REGNUM);
1557 +
1558 + emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
1559 + gen_rtx_COMPARE (mode, x, y)));
1560 +
1561 + return cc_reg;
1562 +}
1563 +
1564 +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
1565 + return the mode to be used for the comparison. */
1566 +
1567 +enum machine_mode
1568 +ubicom32_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1569 +{
1570 + /* Is this a short compare? */
1571 + if (GET_MODE (x) == QImode
1572 + || GET_MODE (x) == HImode
1573 + || GET_MODE (y) == QImode
1574 + || GET_MODE (y) == HImode)
1575 + {
1576 + switch (op)
1577 + {
1578 + case EQ :
1579 + case NE :
1580 + return CCSZmode;
1581 +
1582 + case GE:
1583 + case LT:
1584 + if (y == const0_rtx)
1585 + return CCSZNmode;
1586 +
1587 + default :
1588 + return CCSmode;
1589 + }
1590 + }
1591 +
1592 + /* We have a word compare. */
1593 + switch (op)
1594 + {
1595 + case EQ :
1596 + case NE :
1597 + return CCWZmode;
1598 +
1599 + case GE :
1600 + case LT :
1601 + if (y == const0_rtx)
1602 + return CCWZNmode;
1603 +
1604 + default :
1605 + return CCWmode;
1606 + }
1607 +}
1608 +
1609 +/* Return TRUE or FALSE depending on whether the first SET in INSN
1610 + has source and destination with matching CC modes, and that the
1611 + CC mode is at least as constrained as REQ_MODE. */
1612 +bool
1613 +ubicom32_match_cc_mode (rtx insn, enum machine_mode req_mode)
1614 +{
1615 + rtx set;
1616 + enum machine_mode set_mode;
1617 +
1618 + set = PATTERN (insn);
1619 + if (GET_CODE (set) == PARALLEL)
1620 + set = XVECEXP (set, 0, 0);
1621 + gcc_assert (GET_CODE (set) == SET);
1622 + gcc_assert (GET_CODE (SET_SRC (set)) == COMPARE);
1623 +
1624 + /* SET_MODE is the mode we have in the instruction. This must either
1625 + be the same or less restrictive that the required mode REQ_MODE. */
1626 + set_mode = GET_MODE (SET_DEST (set));
1627 +
1628 + switch (req_mode)
1629 + {
1630 + case CCSZmode:
1631 + if (set_mode != CCSZmode)
1632 + return 0;
1633 + break;
1634 +
1635 + case CCSZNmode:
1636 + if (set_mode != CCSZmode
1637 + && set_mode != CCSZNmode)
1638 + return 0;
1639 + break;
1640 +
1641 + case CCSmode:
1642 + if (set_mode != CCSmode
1643 + && set_mode != CCSZmode
1644 + && set_mode != CCSZNmode)
1645 + return 0;
1646 + break;
1647 +
1648 + case CCWZmode:
1649 + if (set_mode != CCWZmode)
1650 + return 0;
1651 + break;
1652 +
1653 + case CCWZNmode:
1654 + if (set_mode != CCWZmode
1655 + && set_mode != CCWZNmode)
1656 + return 0;
1657 + break;
1658 +
1659 + case CCWmode:
1660 + if (set_mode != CCWmode
1661 + && set_mode != CCWZmode
1662 + && set_mode != CCWZNmode)
1663 + return 0;
1664 + break;
1665 +
1666 + default:
1667 + gcc_unreachable ();
1668 + }
1669 +
1670 + return (GET_MODE (SET_SRC (set)) == set_mode);
1671 +}
1672 +
1673 +/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
1674 + that we can implement more efficiently. */
1675 +
1676 +void
1677 +ubicom32_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
1678 +{
1679 + /* If we have a REG and a MEM then compare the MEM with the REG and not
1680 + the other way round. */
1681 + if (REG_P (*op0) && MEM_P (*op1))
1682 + {
1683 + rtx tem = *op0;
1684 + *op0 = *op1;
1685 + *op1 = tem;
1686 + *code = swap_condition (*code);
1687 + return;
1688 + }
1689 +
1690 + /* If we have a REG and a CONST_INT then we may want to reverse things
1691 + if the constant can be represented as an "I" constraint. */
1692 + if (REG_P (*op0) && CONST_INT_P (*op1) && satisfies_constraint_I (*op1))
1693 + {
1694 + rtx tem = *op0;
1695 + *op0 = *op1;
1696 + *op1 = tem;
1697 + *code = swap_condition (*code);
1698 + return;
1699 + }
1700 +}
1701 +
1702 +/* Return the fixed registers used for condition codes. */
1703 +
1704 +static bool
1705 +ubicom32_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
1706 +{
1707 + *p1 = CC_REGNUM;
1708 + *p2 = INVALID_REGNUM;
1709 +
1710 + return true;
1711 +}
1712 +
1713 +/* If two condition code modes are compatible, return a condition code
1714 + mode which is compatible with both. Otherwise, return
1715 + VOIDmode. */
1716 +
1717 +static enum machine_mode
1718 +ubicom32_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
1719 +{
1720 + if (m1 == m2)
1721 + return m1;
1722 +
1723 + if (GET_MODE_CLASS (m1) != MODE_CC || GET_MODE_CLASS (m2) != MODE_CC)
1724 + return VOIDmode;
1725 +
1726 + switch (m1)
1727 + {
1728 + case CCWmode:
1729 + if (m2 == CCWZNmode || m2 == CCWZmode)
1730 + return m1;
1731 +
1732 + return VOIDmode;
1733 +
1734 + case CCWZNmode:
1735 + if (m2 == CCWmode)
1736 + return m2;
1737 +
1738 + if (m2 == CCWZmode)
1739 + return m1;
1740 +
1741 + return VOIDmode;
1742 +
1743 + case CCWZmode:
1744 + if (m2 == CCWmode || m2 == CCWZNmode)
1745 + return m2;
1746 +
1747 + return VOIDmode;
1748 +
1749 + case CCSmode:
1750 + if (m2 == CCSZNmode || m2 == CCSZmode)
1751 + return m1;
1752 +
1753 + return VOIDmode;
1754 +
1755 + case CCSZNmode:
1756 + if (m2 == CCSmode)
1757 + return m2;
1758 +
1759 + if (m2 == CCSZmode)
1760 + return m1;
1761 +
1762 + return VOIDmode;
1763 +
1764 + case CCSZmode:
1765 + if (m2 == CCSmode || m2 == CCSZNmode)
1766 + return m2;
1767 +
1768 + return VOIDmode;
1769 +
1770 + default:
1771 + gcc_unreachable ();
1772 + }
1773 +}
1774 +
1775 +static rtx
1776 +ubicom32_legitimize_fdpic_address_symbol (rtx orig, rtx reg, rtx fdpic_reg)
1777 +{
1778 + int unspec;
1779 + rtx got_offs;
1780 + rtx got_offs_scaled;
1781 + rtx plus_scaled;
1782 + rtx tmp;
1783 + rtx new_rtx;
1784 +
1785 + gcc_assert (reg != 0);
1786 +
1787 + if (GET_CODE (orig) == SYMBOL_REF
1788 + && SYMBOL_REF_FUNCTION_P (orig))
1789 + unspec = UNSPEC_FDPIC_GOT_FUNCDESC;
1790 + else
1791 + unspec = UNSPEC_FDPIC_GOT;
1792 +
1793 + got_offs = gen_reg_rtx (SImode);
1794 + tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig), unspec);
1795 + emit_move_insn (got_offs, tmp);
1796 +
1797 + got_offs_scaled = gen_rtx_MULT (SImode, got_offs, GEN_INT (4));
1798 + plus_scaled = gen_rtx_PLUS (Pmode, fdpic_reg, got_offs_scaled);
1799 + new_rtx = gen_const_mem (Pmode, plus_scaled);
1800 + emit_move_insn (reg, new_rtx);
1801 +
1802 + return reg;
1803 +}
1804 +
1805 +static rtx
1806 +ubicom32_legitimize_fdpic_address (rtx orig, rtx reg, rtx fdpic_reg)
1807 +{
1808 + rtx addr = orig;
1809 + rtx new_rtx = orig;
1810 +
1811 + if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
1812 + {
1813 + rtx base;
1814 +
1815 + if (GET_CODE (addr) == CONST)
1816 + {
1817 + addr = XEXP (addr, 0);
1818 + gcc_assert (GET_CODE (addr) == PLUS);
1819 + }
1820 +
1821 + base = ubicom32_legitimize_fdpic_address_symbol (XEXP (addr, 0), reg, fdpic_reg);
1822 + return gen_rtx_PLUS (Pmode, base, XEXP (addr, 1));
1823 + }
1824 +
1825 + return new_rtx;
1826 +}
1827 +
1828 +/* Code generation. */
1829 +
1830 +void
1831 +ubicom32_expand_movsi (rtx *operands)
1832 +{
1833 + if (GET_CODE (operands[1]) == SYMBOL_REF
1834 + || (GET_CODE (operands[1]) == CONST
1835 + && GET_CODE (XEXP (operands[1], 0)) == PLUS
1836 + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
1837 + || CONSTANT_ADDRESS_P (operands[1]))
1838 + {
1839 + if (TARGET_FDPIC)
1840 + {
1841 + rtx tmp;
1842 + rtx fdpic_reg;
1843 +
1844 + gcc_assert (can_create_pseudo_p ());
1845 + tmp = gen_reg_rtx (Pmode);
1846 + fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
1847 + if (GET_CODE (operands[1]) == SYMBOL_REF
1848 + || GET_CODE (operands[1]) == LABEL_REF)
1849 + operands[1] = ubicom32_legitimize_fdpic_address_symbol (operands[1], tmp, fdpic_reg);
1850 + else
1851 + operands[1] = ubicom32_legitimize_fdpic_address (operands[1], tmp, fdpic_reg);
1852 + }
1853 + else
1854 + {
1855 + rtx tmp;
1856 + enum machine_mode mode;
1857 +
1858 + /* We want to avoid reusing operand 0 if we can because it limits
1859 + our ability to optimize later. */
1860 + tmp = ! can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
1861 +
1862 + mode = GET_MODE (operands[0]);
1863 + emit_insn (gen_rtx_SET (VOIDmode, tmp,
1864 + gen_rtx_HIGH (mode, operands[1])));
1865 + operands[1] = gen_rtx_LO_SUM (mode, tmp, operands[1]);
1866 + if (can_create_pseudo_p() && ! REG_P (operands[0]))
1867 + {
1868 + tmp = gen_reg_rtx (mode);
1869 + emit_insn (gen_rtx_SET (VOIDmode, tmp, operands[1]));
1870 + operands[1] = tmp;
1871 + }
1872 + }
1873 + }
1874 +}
1875 +
1876 +/* Emit code for addsi3. */
1877 +
1878 +void
1879 +ubicom32_expand_addsi3 (rtx *operands)
1880 +{
1881 + rtx op, clob;
1882 +
1883 + if (can_create_pseudo_p ())
1884 + {
1885 + /* If we have a non-data reg for operand 1 then prefer that over
1886 + a CONST_INT in operand 2. */
1887 + if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
1888 + && CONST_INT_P (operands[2]))
1889 + operands[2] = copy_to_mode_reg (SImode, operands[2]);
1890 +
1891 + if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
1892 + operands[2] = copy_to_mode_reg (SImode, operands[2]);
1893 + }
1894 +
1895 + /* Emit the instruction. */
1896 +
1897 + op = gen_rtx_SET (VOIDmode, operands[0],
1898 + gen_rtx_PLUS (SImode, operands[1], operands[2]));
1899 +
1900 + if (! can_create_pseudo_p ())
1901 + {
1902 + /* Reload doesn't know about the flags register, and doesn't know that
1903 + it doesn't want to clobber it. We can only do this with PLUS. */
1904 + emit_insn (op);
1905 + }
1906 + else
1907 + {
1908 + clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
1909 + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
1910 + }
1911 +}
1912 +
1913 +/* Emit code for mulsi3. Return 1 if we have generated all the code
1914 + necessary to do the multiplication. */
1915 +
1916 +int
1917 +ubicom32_emit_mult_sequence (rtx *operands)
1918 +{
1919 + if (! ubicom32_v4)
1920 + {
1921 + rtx a1, a1_1, a2;
1922 + rtx b1, b1_1, b2;
1923 + rtx mac_lo_rtx;
1924 + rtx t1, t2, t3;
1925 +
1926 + /* Give up if we cannot create new pseudos. */
1927 + if (!can_create_pseudo_p())
1928 + return 0;
1929 +
1930 + /* Synthesize 32-bit multiplication using 16-bit operations:
1931 +
1932 + a1 = highpart (a)
1933 + a2 = lowpart (a)
1934 +
1935 + b1 = highpart (b)
1936 + b2 = lowpart (b)
1937 +
1938 + c = (a1 * b1) << 32 + (a1 * b2) << 16 + (a2 * b1) << 16 + a2 * b2
1939 + = 0 + (a1 * b2) << 16 + (a2 * b1) << 16 + a2 * b2
1940 + ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^
1941 + Signed Signed Unsigned */
1942 +
1943 + if (!ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
1944 + {
1945 + rtx op1;
1946 +
1947 + op1 = gen_reg_rtx (SImode);
1948 + emit_move_insn (op1, operands[1]);
1949 + operands[1] = op1;
1950 + }
1951 +
1952 + if (!ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
1953 + {
1954 + rtx op2;
1955 +
1956 + op2 = gen_reg_rtx (SImode);
1957 + emit_move_insn (op2, operands[2]);
1958 + operands[2] = op2;
1959 + }
1960 +
1961 + /* a1 = highpart (a) */
1962 + a1 = gen_reg_rtx (HImode);
1963 + a1_1 = gen_reg_rtx (SImode);
1964 + emit_insn (gen_ashrsi3 (a1_1, operands[1], GEN_INT (16)));
1965 + emit_move_insn (a1, gen_lowpart (HImode, a1_1));
1966 +
1967 + /* a2 = lowpart (a) */
1968 + a2 = gen_reg_rtx (HImode);
1969 + emit_move_insn (a2, gen_lowpart (HImode, operands[1]));
1970 +
1971 + /* b1 = highpart (b) */
1972 + b1 = gen_reg_rtx (HImode);
1973 + b1_1 = gen_reg_rtx (SImode);
1974 + emit_insn (gen_ashrsi3 (b1_1, operands[2], GEN_INT (16)));
1975 + emit_move_insn (b1, gen_lowpart (HImode, b1_1));
1976 +
1977 + /* b2 = lowpart (b) */
1978 + b2 = gen_reg_rtx (HImode);
1979 + emit_move_insn (b2, gen_lowpart (HImode, operands[2]));
1980 +
1981 + /* t1 = (a1 * b2) << 16 */
1982 + t1 = gen_reg_rtx (SImode);
1983 + mac_lo_rtx = gen_rtx_REG (SImode, ACC0_LO_REGNUM);
1984 + emit_insn (gen_mulhisi3 (mac_lo_rtx, a1, b2));
1985 + emit_insn (gen_ashlsi3 (t1, mac_lo_rtx, GEN_INT (16)));
1986 +
1987 + /* t2 = (a2 * b1) << 16 */
1988 + t2 = gen_reg_rtx (SImode);
1989 + emit_insn (gen_mulhisi3 (mac_lo_rtx, a2, b1));
1990 + emit_insn (gen_ashlsi3 (t2, mac_lo_rtx, GEN_INT (16)));
1991 +
1992 + /* mac_lo = a2 * b2 */
1993 + emit_insn (gen_umulhisi3 (mac_lo_rtx, a2, b2));
1994 +
1995 + /* t3 = t1 + t2 */
1996 + t3 = gen_reg_rtx (SImode);
1997 + emit_insn (gen_addsi3 (t3, t1, t2));
1998 +
1999 + /* c = t3 + mac_lo_rtx */
2000 + emit_insn (gen_addsi3 (operands[0], mac_lo_rtx, t3));
2001 +
2002 + return 1;
2003 + }
2004 + else
2005 + {
2006 + rtx acc_rtx;
2007 +
2008 + /* Give up if we cannot create new pseudos. */
2009 + if (!can_create_pseudo_p())
2010 + return 0;
2011 +
2012 + if (!ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
2013 + {
2014 + rtx op1;
2015 +
2016 + op1 = gen_reg_rtx (SImode);
2017 + emit_move_insn (op1, operands[1]);
2018 + operands[1] = op1;
2019 + }
2020 +
2021 + if (!ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
2022 + {
2023 + rtx op2;
2024 +
2025 + op2 = gen_reg_rtx (SImode);
2026 + emit_move_insn (op2, operands[2]);
2027 + operands[2] = op2;
2028 + }
2029 +
2030 + acc_rtx = gen_reg_rtx (DImode);
2031 + emit_insn (gen_umulsidi3 (acc_rtx, operands[1], operands[2]));
2032 + emit_move_insn (operands[0], gen_lowpart (SImode, acc_rtx));
2033 +
2034 + return 1;
2035 + }
2036 +}
2037 +
2038 +/* Move the integer value VAL into OPERANDS[0]. */
2039 +
2040 +void
2041 +ubicom32_emit_move_const_int (rtx dest, rtx imm)
2042 +{
2043 + rtx xoperands[2];
2044 +
2045 + xoperands[0] = dest;
2046 + xoperands[1] = imm;
2047 +
2048 + /* Treat mem destinations separately. Values must be explicitly sign
2049 + extended. */
2050 + if (MEM_P (dest))
2051 + {
2052 + rtx low_hword_mem;
2053 + rtx low_hword_addr;
2054 +
2055 + /* Emit shorter sequence for signed 7-bit quantities. */
2056 + if (satisfies_constraint_I (imm))
2057 + {
2058 + output_asm_insn ("move.4\t%0, %1", xoperands);
2059 + return;
2060 + }
2061 +
2062 + /* Special case for pushing constants. */
2063 + if (GET_CODE (XEXP (dest, 0)) == PRE_DEC
2064 + && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
2065 + {
2066 + output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
2067 + output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
2068 + return;
2069 + }
2070 +
2071 + /* See if we can add 2 to the original address. This is only
2072 + possible if the original address is of the form REG or
2073 + REG+const. */
2074 + low_hword_addr = plus_constant (XEXP (dest, 0), 2);
2075 + if (ubicom32_legitimate_address_p (HImode, low_hword_addr, 1))
2076 + {
2077 + low_hword_mem = gen_rtx_MEM (HImode, low_hword_addr);
2078 + MEM_COPY_ATTRIBUTES (low_hword_mem, dest);
2079 + output_asm_insn ("movei\t%0, #%%hi(%E1)", xoperands);
2080 + xoperands[0] = low_hword_mem;
2081 + output_asm_insn ("movei\t%0, #%%lo(%E1)", xoperands);
2082 + return;
2083 + }
2084 +
2085 + /* The original address is too complex. We need to use a
2086 + scratch memory by (sp) and move that to the original
2087 + destination. */
2088 + if (! reg_mentioned_p (stack_pointer_rtx, dest))
2089 + {
2090 + output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
2091 + output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
2092 + output_asm_insn ("move.4\t%0, (sp)4++", xoperands);
2093 + return;
2094 + }
2095 +
2096 + /* Our address mentions the stack pointer so we need to
2097 + use our scratch data register here as well as scratch
2098 + memory. */
2099 + output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
2100 + output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
2101 + output_asm_insn ("move.4\td15, (sp)4++", xoperands);
2102 + output_asm_insn ("move.4\t%0, d15", xoperands);
2103 + return;
2104 + }
2105 +
2106 + /* Move into registers are zero extended by default. */
2107 + if (! REG_P (dest))
2108 + abort ();
2109 +
2110 + if (satisfies_constraint_N (imm))
2111 + {
2112 + output_asm_insn ("movei\t%0, %1", xoperands);
2113 + return;
2114 + }
2115 +
2116 + if (INTVAL (xoperands[1]) >= 0xff80
2117 + && INTVAL (xoperands[1]) < 0x10000)
2118 + {
2119 + xoperands[1] = GEN_INT (INTVAL (xoperands[1]) - 0x10000);
2120 + output_asm_insn ("move.2\t%0, %1", xoperands);
2121 + return;
2122 + }
2123 +
2124 + if ((REGNO_REG_CLASS (REGNO (xoperands[0])) == ADDRESS_REGS
2125 + || REGNO_REG_CLASS (REGNO (xoperands[0])) == FDPIC_REG)
2126 + && ((INTVAL (xoperands[1]) & 0x80000000) == 0))
2127 + {
2128 + output_asm_insn ("moveai\t%0, #%%hi(%E1)", xoperands);
2129 + if ((INTVAL (xoperands[1]) & 0x7f) != 0)
2130 + output_asm_insn ("lea.1\t%0, %%lo(%E1)(%0)", xoperands);
2131 + return;
2132 + }
2133 +
2134 + if ((INTVAL (xoperands[1]) & 0xffff0000) == 0)
2135 + {
2136 + output_asm_insn ("movei\t%0, #%%lo(%E1)", xoperands);
2137 + output_asm_insn ("move.2\t%0, %0", xoperands);
2138 + return;
2139 + }
2140 +
2141 + /* This is very expensive. The constant is so large that we
2142 + need to use the stack to do the load. */
2143 + output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
2144 + output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
2145 + output_asm_insn ("move.4\t%0, (sp)4++", xoperands);
2146 +}
2147 +
2148 +/* Stack layout. Prologue/Epilogue. */
2149 +
2150 +static int save_regs_size;
2151 +
2152 +static void
2153 +ubicom32_layout_frame (void)
2154 +{
2155 + int regno;
2156 +
2157 + memset ((char *) &save_regs[0], 0, sizeof (save_regs));
2158 + nregs = 0;
2159 + frame_size = get_frame_size ();
2160 +
2161 + if (frame_pointer_needed || df_regs_ever_live_p (FRAME_POINTER_REGNUM))
2162 + {
2163 + save_regs[FRAME_POINTER_REGNUM] = 1;
2164 + ++nregs;
2165 + }
2166 +
2167 + if (current_function_is_leaf && ! df_regs_ever_live_p (LINK_REGNO))
2168 + ubicom32_can_use_calli_to_ret = 1;
2169 + else
2170 + {
2171 + ubicom32_can_use_calli_to_ret = 0;
2172 + save_regs[LINK_REGNO] = 1;
2173 + ++nregs;
2174 + }
2175 +
2176 + /* Figure out which register(s) needs to be saved. */
2177 + for (regno = 0; regno <= LAST_ADDRESS_REGNUM; regno++)
2178 + if (df_regs_ever_live_p(regno)
2179 + && ! call_used_regs[regno]
2180 + && ! fixed_regs[regno]
2181 + && ! save_regs[regno])
2182 + {
2183 + save_regs[regno] = 1;
2184 + ++nregs;
2185 + }
2186 +
2187 + save_regs_size = 4 * nregs;
2188 +}
2189 +
2190 +static void
2191 +ubicom32_emit_add_movsi (int regno, int adj)
2192 +{
2193 + rtx x;
2194 + rtx reg = gen_rtx_REG (SImode, regno);
2195 +
2196 + adj += 4;
2197 + if (adj > 8 * 4)
2198 + {
2199 + x = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2200 + GEN_INT (-adj)));
2201 + RTX_FRAME_RELATED_P (x) = 1;
2202 + x = emit_move_insn (gen_rtx_MEM (SImode, stack_pointer_rtx), reg);
2203 + }
2204 + else
2205 + {
2206 + rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
2207 + gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2208 + GEN_INT (-adj)));
2209 + x = emit_move_insn (gen_rtx_MEM (SImode, addr), reg);
2210 + }
2211 + RTX_FRAME_RELATED_P (x) = 1;
2212 +}
2213 +
2214 +void
2215 +ubicom32_expand_prologue (void)
2216 +{
2217 + rtx x;
2218 + int regno;
2219 + int outgoing_args_size = crtl->outgoing_args_size;
2220 + int adj;
2221 +
2222 + if (ubicom32_naked_function_p ())
2223 + return;
2224 +
2225 + ubicom32_builtin_saveregs ();
2226 +
2227 + ubicom32_layout_frame ();
2228 + adj = (outgoing_args_size + get_frame_size () + save_regs_size
2229 + + crtl->args.pretend_args_size);
2230 +
2231 + if (!adj)
2232 + ;
2233 + else if (outgoing_args_size + save_regs_size < 508
2234 + && get_frame_size () + save_regs_size > 508)
2235 + {
2236 + int i = 0;
2237 + x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2238 + GEN_INT (-adj));
2239 + x = emit_insn (x);
2240 + RTX_FRAME_RELATED_P (x) = 1;
2241 +
2242 + for (regno = LAST_ADDRESS_REGNUM; regno >= 0; --regno)
2243 + if (save_regs[regno] && regno != LINK_REGNO)
2244 + {
2245 + x = gen_rtx_MEM (SImode,
2246 + gen_rtx_PLUS (Pmode,
2247 + stack_pointer_rtx,
2248 + GEN_INT (i * 4 + outgoing_args_size)));
2249 + x = emit_move_insn (x, gen_rtx_REG (SImode, regno));
2250 + RTX_FRAME_RELATED_P (x) = 1;
2251 + ++i;
2252 + }
2253 + if (save_regs[LINK_REGNO])
2254 + {
2255 + x = gen_rtx_MEM (SImode,
2256 + gen_rtx_PLUS (Pmode,
2257 + stack_pointer_rtx,
2258 + GEN_INT (i * 4 + outgoing_args_size)));
2259 + x = emit_move_insn (x, gen_rtx_REG (SImode, LINK_REGNO));
2260 + RTX_FRAME_RELATED_P (x) = 1;
2261 + }
2262 + }
2263 + else
2264 + {
2265 + int regno;
2266 + int adj = get_frame_size () + crtl->args.pretend_args_size;
2267 + int i = 0;
2268 +
2269 + if (save_regs[LINK_REGNO])
2270 + {
2271 + ubicom32_emit_add_movsi (LINK_REGNO, adj);
2272 + ++i;
2273 + }
2274 +
2275 + for (regno = 0; regno <= LAST_ADDRESS_REGNUM; ++regno)
2276 + if (save_regs[regno] && regno != LINK_REGNO)
2277 + {
2278 + if (i)
2279 + {
2280 + rtx mem = gen_rtx_MEM (SImode,
2281 + gen_rtx_PRE_DEC (Pmode,
2282 + stack_pointer_rtx));
2283 + x = emit_move_insn (mem, gen_rtx_REG (SImode, regno));
2284 + RTX_FRAME_RELATED_P (x) = 1;
2285 + }
2286 + else
2287 + ubicom32_emit_add_movsi (regno, adj);
2288 + ++i;
2289 + }
2290 +
2291 + if (outgoing_args_size || (!i && adj))
2292 + {
2293 + x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2294 + GEN_INT (-outgoing_args_size - (i ? 0 : adj)));
2295 + x = emit_insn (x);
2296 + RTX_FRAME_RELATED_P (x) = 1;
2297 + }
2298 + }
2299 +
2300 + if (frame_pointer_needed)
2301 + {
2302 + int fp_adj = save_regs_size + outgoing_args_size;
2303 + x = gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx,
2304 + GEN_INT (fp_adj));
2305 + x = emit_insn (x);
2306 + RTX_FRAME_RELATED_P (x) = 1;
2307 + }
2308 +}
2309 +
2310 +void
2311 +ubicom32_expand_epilogue (void)
2312 +{
2313 + rtx x;
2314 + int regno;
2315 + int outgoing_args_size = crtl->outgoing_args_size;
2316 + int adj;
2317 + int i;
2318 +
2319 + if (ubicom32_naked_function_p ())
2320 + {
2321 + emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
2322 + LINK_REGNO)));
2323 + return;
2324 + }
2325 +
2326 + if (cfun->calls_alloca)
2327 + {
2328 + x = gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx,
2329 + GEN_INT (-save_regs_size));
2330 + emit_insn (x);
2331 + outgoing_args_size = 0;
2332 + }
2333 +
2334 + if (outgoing_args_size)
2335 + {
2336 + x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2337 + GEN_INT (outgoing_args_size));
2338 + emit_insn (x);
2339 + }
2340 +
2341 + i = 0;
2342 + for (regno = LAST_ADDRESS_REGNUM; regno >= 0; --regno)
2343 + if (save_regs[regno] && regno != LINK_REGNO)
2344 + {
2345 + x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
2346 + emit_move_insn (gen_rtx_REG (SImode, regno), x);
2347 + ++i;
2348 + }
2349 +
2350 + /* Do we have to adjust the stack after we've finished restoring regs? */
2351 + adj = get_frame_size() + crtl->args.pretend_args_size;
2352 + if (cfun->stdarg)
2353 + adj += UBICOM32_FUNCTION_ARG_REGS * UNITS_PER_WORD;
2354 +
2355 +#if 0
2356 + if (crtl->calls_eh_return && 0)
2357 + {
2358 + if (save_regs[LINK_REGNO])
2359 + {
2360 + x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
2361 + emit_move_insn (gen_rtx_REG (SImode, LINK_REGNO), x);
2362 + }
2363 +
2364 + if (adj)
2365 + {
2366 + x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2367 + GEN_INT (adj));
2368 + x = emit_insn (x);
2369 + }
2370 +
2371 + /* Perform the additional bump for __throw. */
2372 + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2373 + EH_RETURN_STACKADJ_RTX));
2374 + emit_jump_insn (gen_eh_return_internal ());
2375 + return;
2376 + }
2377 +#endif
2378 +
2379 + if (save_regs[LINK_REGNO])
2380 + {
2381 + if (adj >= 4 && adj <= (6 * 4))
2382 + {
2383 + x = GEN_INT (adj + 4);
2384 + emit_jump_insn (gen_return_from_post_modify_sp (x));
2385 + return;
2386 + }
2387 +
2388 + if (adj == 0)
2389 + {
2390 + x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
2391 + emit_jump_insn (gen_return_internal (x));
2392 + return;
2393 + }
2394 +
2395 + x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
2396 + emit_move_insn (gen_rtx_REG (SImode, LINK_REGNO), x);
2397 + }
2398 +
2399 + if (adj)
2400 + {
2401 + x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2402 + GEN_INT (adj));
2403 + x = emit_insn (x);
2404 + adj = 0;
2405 + }
2406 +
2407 + /* Given that we've just done all the hard work here we may as well use
2408 + a calli to return. */
2409 + ubicom32_can_use_calli_to_ret = 1;
2410 + emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode, LINK_REGNO)));
2411 +}
2412 +
2413 +void
2414 +ubicom32_expand_call_fdpic (rtx *operands)
2415 +{
2416 + rtx c;
2417 + rtx addr;
2418 + rtx fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
2419 +
2420 + addr = XEXP (operands[0], 0);
2421 +
2422 + c = gen_call_fdpic (addr, operands[1], fdpic_reg);
2423 + emit_call_insn (c);
2424 +}
2425 +
2426 +void
2427 +ubicom32_expand_call_value_fdpic (rtx *operands)
2428 +{
2429 + rtx c;
2430 + rtx addr;
2431 + rtx fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
2432 +
2433 + addr = XEXP (operands[1], 0);
2434 +
2435 + c = gen_call_value_fdpic (operands[0], addr, operands[2], fdpic_reg);
2436 + emit_call_insn (c);
2437 +}
2438 +
2439 +void
2440 +ubicom32_expand_eh_return (rtx *operands)
2441 +{
2442 + if (REG_P (operands[0])
2443 + || REGNO (operands[0]) != EH_RETURN_STACKADJ_REGNO)
2444 + {
2445 + rtx sp = EH_RETURN_STACKADJ_RTX;
2446 + emit_move_insn (sp, operands[0]);
2447 + operands[0] = sp;
2448 + }
2449 +
2450 + if (REG_P (operands[1])
2451 + || REGNO (operands[1]) != EH_RETURN_HANDLER_REGNO)
2452 + {
2453 + rtx ra = EH_RETURN_HANDLER_RTX;
2454 + emit_move_insn (ra, operands[1]);
2455 + operands[1] = ra;
2456 + }
2457 +}
2458 +
2459 +/* Compute the offsets between eliminable registers. */
2460 +
2461 +int
2462 +ubicom32_initial_elimination_offset (int from, int to)
2463 +{
2464 + ubicom32_layout_frame ();
2465 + if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
2466 + return save_regs_size + crtl->outgoing_args_size;
2467 +
2468 + if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
2469 + return get_frame_size ()/* + save_regs_size */;
2470 +
2471 + if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
2472 + return get_frame_size ()
2473 + + crtl->outgoing_args_size
2474 + + save_regs_size;
2475 +
2476 + return 0;
2477 +}
2478 +
2479 +/* Return 1 if it is appropriate to emit `ret' instructions in the
2480 + body of a function. Do this only if the epilogue is simple, needing a
2481 + couple of insns. Prior to reloading, we can't tell how many registers
2482 + must be saved, so return 0 then. Return 0 if there is no frame
2483 + marker to de-allocate.
2484 +
2485 + If NON_SAVING_SETJMP is defined and true, then it is not possible
2486 + for the epilogue to be simple, so return 0. This is a special case
2487 + since NON_SAVING_SETJMP will not cause regs_ever_live to change
2488 + until final, but jump_optimize may need to know sooner if a
2489 + `return' is OK. */
2490 +
2491 +int
2492 +ubicom32_can_use_return_insn_p (void)
2493 +{
2494 + if (! reload_completed || frame_pointer_needed)
2495 + return 0;
2496 +
2497 + return 1;
2498 +}
2499 +
2500 +/* Attributes and CC handling. */
2501 +
2502 +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
2503 + struct attribute_spec.handler. */
2504 +static tree
2505 +ubicom32_handle_fndecl_attribute (tree *node, tree name,
2506 + tree args ATTRIBUTE_UNUSED,
2507 + int flags ATTRIBUTE_UNUSED,
2508 + bool *no_add_attrs)
2509 +{
2510 + if (TREE_CODE (*node) != FUNCTION_DECL)
2511 + {
2512 + warning ("'%s' attribute only applies to functions",
2513 + IDENTIFIER_POINTER (name));
2514 + *no_add_attrs = true;
2515 + }
2516 +
2517 + return NULL_TREE;
2518 +}
2519 +
2520 +/* A C expression that places additional restrictions on the register class to
2521 + use when it is necessary to copy value X into a register in class CLASS.
2522 + The value is a register class; perhaps CLASS, or perhaps another, smaller
2523 + class. On many machines, the following definition is safe:
2524 +
2525 + #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
2526 +
2527 + Sometimes returning a more restrictive class makes better code. For
2528 + example, on the 68000, when X is an integer constant that is in range for a
2529 + `moveq' instruction, the value of this macro is always `DATA_REGS' as long
2530 + as CLASS includes the data registers. Requiring a data register guarantees
2531 + that a `moveq' will be used.
2532 +
2533 + If X is a `const_double', by returning `NO_REGS' you can force X into a
2534 + memory constant. This is useful on certain machines where immediate
2535 + floating values cannot be loaded into certain kinds of registers. */
2536 +
2537 +enum reg_class
2538 +ubicom32_preferred_reload_class (rtx x, enum reg_class class)
2539 +{
2540 + /* If a symbolic constant, HIGH or a PLUS is reloaded,
2541 + it is most likely being used as an address, so
2542 + prefer ADDRESS_REGS. If 'class' is not a superset
2543 + of ADDRESS_REGS, e.g. DATA_REGS, then reject this reload. */
2544 + if (GET_CODE (x) == PLUS
2545 + || GET_CODE (x) == HIGH
2546 + || GET_CODE (x) == LABEL_REF
2547 + || GET_CODE (x) == SYMBOL_REF
2548 + || GET_CODE (x) == CONST)
2549 + {
2550 + if (reg_class_subset_p (ALL_ADDRESS_REGS, class))
2551 + return ALL_ADDRESS_REGS;
2552 +
2553 + return NO_REGS;
2554 + }
2555 +
2556 + return class;
2557 +}
2558 +
2559 +/* Function arguments and varargs. */
2560 +
2561 +int
2562 +ubicom32_reg_parm_stack_space (tree fndecl)
2563 +{
2564 + return 0;
2565 +
2566 + if (fndecl
2567 + && TYPE_ARG_TYPES (TREE_TYPE (fndecl)) != 0
2568 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))))
2569 + != void_type_node))
2570 + return UBICOM32_FUNCTION_ARG_REGS * UNITS_PER_WORD;
2571 +
2572 + return 0;
2573 +}
2574 +
2575 +/* Flush the argument registers to the stack for a stdarg function;
2576 + return the new argument pointer. */
2577 +
2578 +rtx
2579 +ubicom32_builtin_saveregs (void)
2580 +{
2581 + int regno;
2582 +
2583 + if (! cfun->stdarg)
2584 + return 0;
2585 +
2586 + for (regno = UBICOM32_FUNCTION_ARG_REGS - 1; regno >= 0; --regno)
2587 + emit_move_insn (gen_rtx_MEM (SImode,
2588 + gen_rtx_PRE_DEC (SImode,
2589 + stack_pointer_rtx)),
2590 + gen_rtx_REG (SImode, regno));
2591 +
2592 + return stack_pointer_rtx;
2593 +}
2594 +
2595 +void
2596 +ubicom32_va_start (tree valist, rtx nextarg)
2597 +{
2598 + std_expand_builtin_va_start (valist, nextarg);
2599 +}
2600 +
2601 +rtx
2602 +ubicom32_va_arg (tree valist, tree type)
2603 +{
2604 + HOST_WIDE_INT size, rsize;
2605 + tree addr, incr, tmp;
2606 + rtx addr_rtx;
2607 + int indirect = 0;
2608 +
2609 + /* Round up sizeof(type) to a word. */
2610 + size = int_size_in_bytes (type);
2611 + rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
2612 +
2613 + /* Large types are passed by reference. */
2614 + if (size > 8)
2615 + {
2616 + indirect = 1;
2617 + size = rsize = UNITS_PER_WORD;
2618 + }
2619 +
2620 + incr = valist;
2621 + addr = incr = save_expr (incr);
2622 +
2623 + /* FIXME Nat's version - is it correct? */
2624 + tmp = fold_convert (ptr_type_node, size_int (rsize));
2625 + tmp = build2 (PLUS_EXPR, ptr_type_node, incr, tmp);
2626 + incr = fold (tmp);
2627 +
2628 + /* FIXME Nat's version - is it correct? */
2629 + incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
2630 +
2631 + TREE_SIDE_EFFECTS (incr) = 1;
2632 + expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
2633 +
2634 + addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
2635 +
2636 + if (size < UNITS_PER_WORD)
2637 + emit_insn (gen_addsi3 (addr_rtx, addr_rtx,
2638 + GEN_INT (UNITS_PER_WORD - size)));
2639 +
2640 + if (indirect)
2641 + {
2642 + addr_rtx = force_reg (Pmode, addr_rtx);
2643 + addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
2644 + set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
2645 + }
2646 +
2647 + return addr_rtx;
2648 +}
2649 +
2650 +void
2651 +init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
2652 + int indirect ATTRIBUTE_UNUSED)
2653 +{
2654 + cum->nbytes = 0;
2655 +
2656 + if (!libname)
2657 + {
2658 + cum->stdarg = (TYPE_ARG_TYPES (fntype) != 0
2659 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2660 + != void_type_node));
2661 + }
2662 +}
2663 +
2664 +/* Return an RTX to represent where a value in mode MODE will be passed
2665 + to a function. If the result is 0, the argument will be pushed. */
2666 +
2667 +rtx
2668 +function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
2669 + int named ATTRIBUTE_UNUSED)
2670 +{
2671 + rtx result = 0;
2672 + int size, align;
2673 + int nregs = UBICOM32_FUNCTION_ARG_REGS;
2674 +
2675 + /* Figure out the size of the object to be passed. */
2676 + if (mode == BLKmode)
2677 + size = int_size_in_bytes (type);
2678 + else
2679 + size = GET_MODE_SIZE (mode);
2680 +
2681 + /* Figure out the alignment of the object to be passed. */
2682 + align = size;
2683 +
2684 + cum->nbytes = (cum->nbytes + 3) & ~3;
2685 +
2686 + /* Don't pass this arg via a register if all the argument registers
2687 + are used up. */
2688 + if (cum->nbytes >= nregs * UNITS_PER_WORD)
2689 + return 0;
2690 +
2691 + /* Don't pass this arg via a register if it would be split between
2692 + registers and memory. */
2693 + result = gen_rtx_REG (mode, cum->nbytes / UNITS_PER_WORD);
2694 +
2695 + return result;
2696 +}
2697 +
2698 +rtx
2699 +function_incoming_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
2700 + int named ATTRIBUTE_UNUSED)
2701 +{
2702 + if (cfun->stdarg)
2703 + return 0;
2704 +
2705 + return function_arg (cum, mode, type, named);
2706 +}
2707 +
2708 +
2709 +/* Implement hook TARGET_ARG_PARTIAL_BYTES.
2710 +
2711 + Returns the number of bytes at the beginning of an argument that
2712 + must be put in registers. The value must be zero for arguments
2713 + that are passed entirely in registers or that are entirely pushed
2714 + on the stack. */
2715 +static int
2716 +ubicom32_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
2717 + tree type, bool named ATTRIBUTE_UNUSED)
2718 +{
2719 + int size, diff;
2720 +
2721 + int nregs = UBICOM32_FUNCTION_ARG_REGS;
2722 +
2723 + /* round up to full word */
2724 + cum->nbytes = (cum->nbytes + 3) & ~3;
2725 +
2726 + if (targetm.calls.pass_by_reference (cum, mode, type, named))
2727 + return 0;
2728 +
2729 + /* number of bytes left in registers */
2730 + diff = nregs*UNITS_PER_WORD - cum->nbytes;
2731 +
2732 + /* regs all used up */
2733 + if (diff <= 0)
2734 + return 0;
2735 +
2736 + /* Figure out the size of the object to be passed. */
2737 + if (mode == BLKmode)
2738 + size = int_size_in_bytes (type);
2739 + else
2740 + size = GET_MODE_SIZE (mode);
2741 +
2742 + /* enough space left in regs for size */
2743 + if (size <= diff)
2744 + return 0;
2745 +
2746 + /* put diff bytes in regs and rest on stack */
2747 + return diff;
2748 +
2749 +}
2750 +
2751 +static bool
2752 +ubicom32_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
2753 + enum machine_mode mode, const_tree type,
2754 + bool named ATTRIBUTE_UNUSED)
2755 +{
2756 + int size;
2757 +
2758 + if (type)
2759 + size = int_size_in_bytes (type);
2760 + else
2761 + size = GET_MODE_SIZE (mode);
2762 +
2763 + return size <= 0 || size > 8;
2764 +}
2765 +
2766 +static bool
2767 +ubicom32_callee_copies (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
2768 + enum machine_mode mode, const_tree type,
2769 + bool named ATTRIBUTE_UNUSED)
2770 +{
2771 + int size;
2772 +
2773 + if (type)
2774 + size = int_size_in_bytes (type);
2775 + else
2776 + size = GET_MODE_SIZE (mode);
2777 +
2778 + return size <= 0 || size > 8;
2779 +}
2780 +
2781 +static bool
2782 +ubicom32_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
2783 +{
2784 + int size, mode;
2785 +
2786 + if (!type)
2787 + return true;
2788 +
2789 + size = int_size_in_bytes(type);
2790 + if (size > 8)
2791 + return true;
2792 +
2793 + mode = TYPE_MODE(type);
2794 + if (mode == BLKmode)
2795 + return true;
2796 +
2797 + return false;
2798 +}
2799 +
2800 +/* Return true if a given register number REGNO is acceptable for machine
2801 + mode MODE. */
2802 +bool
2803 +ubicom32_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
2804 +{
2805 + /* If we're not at least a v3 ISA then ACC0_HI is only 16 bits. */
2806 + if (! ubicom32_v3)
2807 + {
2808 + if (regno == ACC0_HI_REGNUM)
2809 + return (mode == QImode || mode == HImode);
2810 + }
2811 +
2812 + /* Only the flags reg can hold CCmode. */
2813 + if (GET_MODE_CLASS (mode) == MODE_CC)
2814 + return regno == CC_REGNUM;
2815 +
2816 + /* We restrict the choice of DImode registers to only being address,
2817 + data or accumulator regs. We also restrict them to only start on
2818 + even register numbers so we never have to worry about partial
2819 + overlaps between operands in instructions. */
2820 + if (GET_MODE_SIZE (mode) > 4)
2821 + {
2822 + switch (REGNO_REG_CLASS (regno))
2823 + {
2824 + case ADDRESS_REGS:
2825 + case DATA_REGS:
2826 + case ACC_REGS:
2827 + return (regno & 1) == 0;
2828 +
2829 + default:
2830 + return false;
2831 + }
2832 + }
2833 +
2834 + return true;
2835 +}
2836 +
2837 +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
2838 + and check its validity for a certain class.
2839 + We have two alternate definitions for each of them.
2840 + The usual definition accepts all pseudo regs; the other rejects
2841 + them unless they have been allocated suitable hard regs.
2842 + The symbol REG_OK_STRICT causes the latter definition to be used.
2843 +
2844 + Most source files want to accept pseudo regs in the hope that
2845 + they will get allocated to the class that the insn wants them to be in.
2846 + Source files for reload pass need to be strict.
2847 + After reload, it makes no difference, since pseudo regs have
2848 + been eliminated by then.
2849 +
2850 + These assume that REGNO is a hard or pseudo reg number.
2851 + They give nonzero only if REGNO is a hard reg of the suitable class
2852 + or a pseudo reg currently allocated to a suitable hard reg.
2853 + Since they use reg_renumber, they are safe only once reg_renumber
2854 + has been allocated, which happens in local-alloc.c. */
2855 +
2856 +int
2857 +ubicom32_regno_ok_for_base_p (int regno, int strict)
2858 +{
2859 + if ((regno >= FIRST_ADDRESS_REGNUM && regno <= STACK_POINTER_REGNUM)
2860 + || (!strict
2861 + && (regno >= FIRST_PSEUDO_REGISTER
2862 + || regno == ARG_POINTER_REGNUM))
2863 + || (strict && (reg_renumber
2864 + && reg_renumber[regno] >= FIRST_ADDRESS_REGNUM
2865 + && reg_renumber[regno] <= STACK_POINTER_REGNUM)))
2866 + return 1;
2867 +
2868 + return 0;
2869 +}
2870 +
2871 +int
2872 +ubicom32_regno_ok_for_index_p (int regno, int strict)
2873 +{
2874 + if ((regno >= FIRST_DATA_REGNUM && regno <= LAST_DATA_REGNUM)
2875 + || (!strict && regno >= FIRST_PSEUDO_REGISTER)
2876 + || (strict && (reg_renumber
2877 + && reg_renumber[regno] >= FIRST_DATA_REGNUM
2878 + && reg_renumber[regno] <= LAST_DATA_REGNUM)))
2879 + return 1;
2880 +
2881 + return 0;
2882 +}
2883 +
2884 +/* Returns 1 if X is a valid index register. STRICT is 1 if only hard
2885 + registers should be accepted. Accept either REG or SUBREG where a
2886 + register is valid. */
2887 +
2888 +static bool
2889 +ubicom32_is_index_reg (rtx x, int strict)
2890 +{
2891 + if ((REG_P (x) && ubicom32_regno_ok_for_index_p (REGNO (x), strict))
2892 + || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
2893 + && ubicom32_regno_ok_for_index_p (REGNO (SUBREG_REG (x)), strict)))
2894 + return true;
2895 +
2896 + return false;
2897 +}
2898 +
2899 +/* Return 1 if X is a valid index for a memory address. */
2900 +
2901 +static bool
2902 +ubicom32_is_index_expr (enum machine_mode mode, rtx x, int strict)
2903 +{
2904 + /* Immediate index must be an unsigned 7-bit offset multiple of 1, 2
2905 + or 4 depending on mode. */
2906 + if (CONST_INT_P (x))
2907 + {
2908 + switch (mode)
2909 + {
2910 + case QImode:
2911 + return satisfies_constraint_J (x);
2912 +
2913 + case HImode:
2914 + return satisfies_constraint_K (x);
2915 +
2916 + case SImode:
2917 + case SFmode:
2918 + return satisfies_constraint_L (x);
2919 +
2920 + case DImode:
2921 + return satisfies_constraint_L (x)
2922 + && satisfies_constraint_L (GEN_INT (INTVAL (x) + 4));
2923 +
2924 + default:
2925 + return false;
2926 + }
2927 + }
2928 +
2929 + if (mode != SImode && mode != HImode && mode != QImode)
2930 + return false;
2931 +
2932 + /* Register index scaled by mode of operand: REG + REG * modesize.
2933 + Valid scaled index registers are:
2934 +
2935 + SImode (mult (dreg) 4))
2936 + HImode (mult (dreg) 2))
2937 + QImode (mult (dreg) 1)) */
2938 + if (GET_CODE (x) == MULT
2939 + && ubicom32_is_index_reg (XEXP (x, 0), strict)
2940 + && CONST_INT_P (XEXP (x, 1))
2941 + && INTVAL (XEXP (x, 1)) == (HOST_WIDE_INT)GET_MODE_SIZE (mode))
2942 + return true;
2943 +
2944 + /* REG + REG addressing is allowed for QImode. */
2945 + if (ubicom32_is_index_reg (x, strict) && mode == QImode)
2946 + return true;
2947 +
2948 + return false;
2949 +}
2950 +
2951 +static bool
2952 +ubicom32_is_valid_offset (enum machine_mode mode, HOST_WIDE_INT offs)
2953 +{
2954 + if (offs < 0)
2955 + return false;
2956 +
2957 + switch (mode)
2958 + {
2959 + case QImode:
2960 + return offs <= 127;
2961 +
2962 + case HImode:
2963 + return offs <= 254;
2964 +
2965 + case SImode:
2966 + case SFmode:
2967 + return offs <= 508;
2968 +
2969 + case DImode:
2970 + return offs <= 504;
2971 +
2972 + default:
2973 + return false;
2974 + }
2975 +}
2976 +
2977 +static int
2978 +ubicom32_get_valid_offset_mask (enum machine_mode mode)
2979 +{
2980 + switch (mode)
2981 + {
2982 + case QImode:
2983 + return 127;
2984 +
2985 + case HImode:
2986 + return 255;
2987 +
2988 + case SImode:
2989 + case SFmode:
2990 + return 511;
2991 +
2992 + case DImode:
2993 + return 255;
2994 +
2995 + default:
2996 + return 0;
2997 + }
2998 +}
2999 +
3000 +/* Returns 1 if X is a valid base register. STRICT is 1 if only hard
3001 + registers should be accepted. Accept either REG or SUBREG where a
3002 + register is valid. */
3003 +
3004 +static bool
3005 +ubicom32_is_base_reg (rtx x, int strict)
3006 +{
3007 + if ((REG_P (x) && ubicom32_regno_ok_for_base_p (REGNO (x), strict))
3008 + || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
3009 + && ubicom32_regno_ok_for_base_p (REGNO (SUBREG_REG (x)), strict)))
3010 + return true;
3011 +
3012 + return false;
3013 +}
3014 +
3015 +static bool
3016 +ubicom32_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
3017 +{
3018 + return TARGET_FDPIC;
3019 +}
3020 +
3021 +/* Determine if X is a legitimate constant. */
3022 +
3023 +bool
3024 +ubicom32_legitimate_constant_p (rtx x)
3025 +{
3026 + /* Among its other duties, LEGITIMATE_CONSTANT_P decides whether
3027 + a constant can be entered into reg_equiv_constant[]. If we return true,
3028 + reload can create new instances of the constant whenever it likes.
3029 +
3030 + The idea is therefore to accept as many constants as possible (to give
3031 + reload more freedom) while rejecting constants that can only be created
3032 + at certain times. In particular, anything with a symbolic component will
3033 + require use of the pseudo FDPIC register, which is only available before
3034 + reload. */
3035 + if (TARGET_FDPIC)
3036 + {
3037 + if (GET_CODE (x) == SYMBOL_REF
3038 + || (GET_CODE (x) == CONST
3039 + && GET_CODE (XEXP (x, 0)) == PLUS
3040 + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
3041 + || CONSTANT_ADDRESS_P (x))
3042 + return false;
3043 +
3044 + return true;
3045 + }
3046 +
3047 + /* For non-PIC code anything goes! */
3048 + return true;
3049 +}
3050 +
3051 +/* Address validation. */
3052 +
3053 +bool
3054 +ubicom32_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
3055 +{
3056 + if (TARGET_DEBUG_ADDRESS)
3057 + {
3058 + fprintf (stderr, "\n==> GO_IF_LEGITIMATE_ADDRESS%s\n",
3059 + (strict) ? " (STRICT)" : "");
3060 + debug_rtx (x);
3061 + }
3062 +
3063 + if (CONSTANT_ADDRESS_P (x))
3064 + return false;
3065 +
3066 + if (ubicom32_is_base_reg (x, strict))
3067 + return true;
3068 +
3069 + if ((GET_CODE (x) == POST_INC
3070 + || GET_CODE (x) == PRE_INC
3071 + || GET_CODE (x) == POST_DEC
3072 + || GET_CODE (x) == PRE_DEC)
3073 + && REG_P (XEXP (x, 0))
3074 + && ubicom32_is_base_reg (XEXP (x, 0), strict)
3075 + && mode != DImode)
3076 + return true;
3077 +
3078 + if ((GET_CODE (x) == PRE_MODIFY || GET_CODE (x) == POST_MODIFY)
3079 + && ubicom32_is_base_reg (XEXP (x, 0), strict)
3080 + && GET_CODE (XEXP (x, 1)) == PLUS
3081 + && rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0))
3082 + && CONST_INT_P (XEXP (XEXP (x, 1), 1))
3083 + && mode != DImode)
3084 + {
3085 + HOST_WIDE_INT disp = INTVAL (XEXP (XEXP (x, 1), 1));
3086 + switch (mode)
3087 + {
3088 + case QImode:
3089 + return disp >= -8 && disp <= 7;
3090 +
3091 + case HImode:
3092 + return disp >= -16 && disp <= 14 && ! (disp & 1);
3093 +
3094 + case SImode:
3095 + return disp >= -32 && disp <= 28 && ! (disp & 3);
3096 +
3097 + default:
3098 + return false;
3099 + }
3100 + }
3101 +
3102 + /* Accept base + index * scale. */
3103 + if (GET_CODE (x) == PLUS
3104 + && ubicom32_is_base_reg (XEXP (x, 0), strict)
3105 + && ubicom32_is_index_expr (mode, XEXP (x, 1), strict))
3106 + return true;
3107 +
3108 + /* Accept index * scale + base. */
3109 + if (GET_CODE (x) == PLUS
3110 + && ubicom32_is_base_reg (XEXP (x, 1), strict)
3111 + && ubicom32_is_index_expr (mode, XEXP (x, 0), strict))
3112 + return true;
3113 +
3114 + if (! TARGET_FDPIC)
3115 + {
3116 + /* Accept (lo_sum (reg) (symbol_ref)) that can be used as a mem+7bits
3117 + displacement operand:
3118 +
3119 + moveai a1, #%hi(SYM)
3120 + move.4 d3, %lo(SYM)(a1) */
3121 + if (GET_CODE (x) == LO_SUM
3122 + && ubicom32_is_base_reg (XEXP (x, 0), strict)
3123 + && (GET_CODE (XEXP (x, 1)) == SYMBOL_REF
3124 + || GET_CODE (XEXP (x, 1)) == LABEL_REF /* FIXME: wrong */)
3125 + && mode != DImode)
3126 + return true;
3127 + }
3128 +
3129 + if (TARGET_DEBUG_ADDRESS)
3130 + fprintf (stderr, "\nNot a legitimate address.\n");
3131 +
3132 + return false;
3133 +}
3134 +
3135 +rtx
3136 +ubicom32_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
3137 + enum machine_mode mode)
3138 +{
3139 + if (mode == BLKmode)
3140 + return NULL_RTX;
3141 +
3142 + if (GET_CODE (x) == PLUS
3143 + && REG_P (XEXP (x, 0))
3144 + && ! REGNO_PTR_FRAME_P (REGNO (XEXP (x, 0)))
3145 + && CONST_INT_P (XEXP (x, 1))
3146 + && ! ubicom32_is_valid_offset (mode, INTVAL (XEXP (x, 1))))
3147 + {
3148 + rtx base;
3149 + rtx plus;
3150 + rtx new_rtx;
3151 + HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
3152 + HOST_WIDE_INT low = val & ubicom32_get_valid_offset_mask (mode);
3153 + HOST_WIDE_INT high = val ^ low;
3154 +
3155 + if (val < 0)
3156 + return NULL_RTX;
3157 +
3158 + if (! low)
3159 + return NULL_RTX;
3160 +
3161 + /* Reload the high part into a base reg; leave the low part
3162 + in the mem directly. */
3163 + base = XEXP (x, 0);
3164 + if (! ubicom32_is_base_reg (base, 0))
3165 + base = copy_to_mode_reg (Pmode, base);
3166 +
3167 + plus = expand_simple_binop (Pmode, PLUS,
3168 + gen_int_mode (high, Pmode),
3169 + base, NULL, 0, OPTAB_WIDEN);
3170 + new_rtx = plus_constant (plus, low);
3171 +
3172 + return new_rtx;
3173 + }
3174 +
3175 + return NULL_RTX;
3176 +}
3177 +
3178 +/* Try a machine-dependent way of reloading an illegitimate address AD
3179 + operand. If we find one, push the reload and and return the new address.
3180 +
3181 + MODE is the mode of the enclosing MEM. OPNUM is the operand number
3182 + and TYPE is the reload type of the current reload. */
3183 +
3184 +rtx
3185 +ubicom32_legitimize_reload_address (rtx ad, enum machine_mode mode,
3186 + int opnum, int type)
3187 +{
3188 + /* Is this an address that we've already fixed up? If it is then
3189 + recognize it and move on. */
3190 + if (GET_CODE (ad) == PLUS
3191 + && GET_CODE (XEXP (ad, 0)) == PLUS
3192 + && REG_P (XEXP (XEXP (ad, 0), 0))
3193 + && CONST_INT_P (XEXP (XEXP (ad, 0), 1))
3194 + && CONST_INT_P (XEXP (ad, 1)))
3195 + {
3196 + push_reload (XEXP (ad, 0), NULL_RTX, &XEXP (ad, 0), NULL,
3197 + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3198 + opnum, (enum reload_type) type);
3199 + return ad;
3200 + }
3201 +
3202 + /* Have we got an address where the offset is simply out of range? If
3203 + yes then reload the range as a high part and smaller offset. */
3204 + if (GET_CODE (ad) == PLUS
3205 + && REG_P (XEXP (ad, 0))
3206 + && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
3207 + && REGNO_OK_FOR_BASE_P (REGNO (XEXP (ad, 0)))
3208 + && CONST_INT_P (XEXP (ad, 1))
3209 + && ! ubicom32_is_valid_offset (mode, INTVAL (XEXP (ad, 1))))
3210 + {
3211 + rtx temp;
3212 + rtx new_rtx;
3213 +
3214 + HOST_WIDE_INT val = INTVAL (XEXP (ad, 1));
3215 + HOST_WIDE_INT low = val & ubicom32_get_valid_offset_mask (mode);
3216 + HOST_WIDE_INT high = val ^ low;
3217 +
3218 + /* Reload the high part into a base reg; leave the low part
3219 + in the mem directly. */
3220 + temp = gen_rtx_PLUS (Pmode, XEXP (ad, 0), GEN_INT (high));
3221 + new_rtx = gen_rtx_PLUS (Pmode, temp, GEN_INT (low));
3222 +
3223 + push_reload (XEXP (new_rtx, 0), NULL_RTX, &XEXP (new_rtx, 0), NULL,
3224 + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3225 + opnum, (enum reload_type) type);
3226 + return new_rtx;
3227 + }
3228 +
3229 + /* If we're presented with an pre/post inc/dec then we must force this
3230 + to be done in an address register. The register allocator should
3231 + work this out for itself but at times ends up trying to use the wrong
3232 + class. If we get the wrong class then reload will end up generating
3233 + at least 3 instructions whereas this way we can hopefully keep it to
3234 + just 2. */
3235 + if ((GET_CODE (ad) == POST_INC
3236 + || GET_CODE (ad) == PRE_INC
3237 + || GET_CODE (ad) == POST_DEC
3238 + || GET_CODE (ad) == PRE_DEC)
3239 + && REG_P (XEXP (ad, 0))
3240 + && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
3241 + && ! REGNO_OK_FOR_BASE_P (REGNO (XEXP (ad, 0))))
3242 + {
3243 + push_reload (XEXP (ad, 0), XEXP (ad, 0), &XEXP (ad, 0), &XEXP (ad, 0),
3244 + BASE_REG_CLASS, GET_MODE (XEXP (ad, 0)), GET_MODE (XEXP (ad, 0)), 0, 0,
3245 + opnum, RELOAD_OTHER);
3246 + return ad;
3247 + }
3248 +
3249 + return NULL_RTX;
3250 +}
3251 +
3252 +/* Compute a (partial) cost for rtx X. Return true if the complete
3253 + cost has been computed, and false if subexpressions should be
3254 + scanned. In either case, *TOTAL contains the cost result. */
3255 +
3256 +static bool
3257 +ubicom32_rtx_costs (rtx x, int code, int outer_code, int *total,
3258 + bool speed ATTRIBUTE_UNUSED)
3259 +{
3260 + enum machine_mode mode = GET_MODE (x);
3261 +
3262 + switch (code)
3263 + {
3264 + case CONST_INT:
3265 + /* Very short constants often fold into instructions so
3266 + we pretend that they don't cost anything! This is
3267 + really important as regards zero values as otherwise
3268 + the compiler has a nasty habit of wanting to reuse
3269 + zeroes that are in regs but that tends to pessimize
3270 + the code. */
3271 + if (satisfies_constraint_I (x))
3272 + {
3273 + *total = 0;
3274 + return true;
3275 + }
3276 +
3277 + /* Bit clearing costs nothing */
3278 + if (outer_code == AND
3279 + && exact_log2 (~INTVAL (x)) != -1)
3280 + {
3281 + *total = 0;
3282 + return true;
3283 + }
3284 +
3285 + /* Masking the lower set of bits costs nothing. */
3286 + if (outer_code == AND
3287 + && exact_log2 (INTVAL (x) + 1) != -1)
3288 + {
3289 + *total = 0;
3290 + return true;
3291 + }
3292 +
3293 + /* Bit setting costs nothing. */
3294 + if (outer_code == IOR
3295 + && exact_log2 (INTVAL (x)) != -1)
3296 + {
3297 + *total = 0;
3298 + return true;
3299 + }
3300 +
3301 + /* Larger constants that can be loaded via movei aren't too
3302 + bad. If we're just doing a set they cost nothing extra. */
3303 + if (satisfies_constraint_N (x))
3304 + {
3305 + if (mode == DImode)
3306 + *total = COSTS_N_INSNS (2);
3307 + else
3308 + *total = COSTS_N_INSNS (1);
3309 + return true;
3310 + }
3311 +
3312 + if (mode == DImode)
3313 + *total = COSTS_N_INSNS (5);
3314 + else
3315 + *total = COSTS_N_INSNS (3);
3316 + return true;
3317 +
3318 + case CONST_DOUBLE:
3319 + /* We don't optimize CONST_DOUBLEs well nor do we relax them well,
3320 + so their cost is very high. */
3321 + *total = COSTS_N_INSNS (6);
3322 + return true;
3323 +
3324 + case CONST:
3325 + case SYMBOL_REF:
3326 + case MEM:
3327 + *total = 0;
3328 + return true;
3329 +
3330 + case IF_THEN_ELSE:
3331 + *total = COSTS_N_INSNS (1);
3332 + return true;
3333 +
3334 + case LABEL_REF:
3335 + case HIGH:
3336 + case LO_SUM:
3337 + case BSWAP:
3338 + case PLUS:
3339 + case MINUS:
3340 + case AND:
3341 + case IOR:
3342 + case XOR:
3343 + case ASHIFT:
3344 + case ASHIFTRT:
3345 + case LSHIFTRT:
3346 + case NEG:
3347 + case NOT:
3348 + case SIGN_EXTEND:
3349 + case ZERO_EXTEND:
3350 + case ZERO_EXTRACT:
3351 + if (outer_code == SET)
3352 + {
3353 + if (mode == DImode)
3354 + *total = COSTS_N_INSNS (2);
3355 + else
3356 + *total = COSTS_N_INSNS (1);
3357 + }
3358 + return true;
3359 +
3360 + case COMPARE:
3361 + if (outer_code == SET)
3362 + {
3363 + if (GET_MODE (XEXP (x, 0)) == DImode
3364 + || GET_MODE (XEXP (x, 1)) == DImode)
3365 + *total = COSTS_N_INSNS (2);
3366 + else
3367 + *total = COSTS_N_INSNS (1);
3368 + }
3369 + return true;
3370 +
3371 + case UMOD:
3372 + case UDIV:
3373 + case MOD:
3374 + case DIV:
3375 + if (outer_code == SET)
3376 + {
3377 + if (mode == DImode)
3378 + *total = COSTS_N_INSNS (600);
3379 + else
3380 + *total = COSTS_N_INSNS (200);
3381 + }
3382 + return true;
3383 +
3384 + case MULT:
3385 + if (outer_code == SET)
3386 + {
3387 + if (! ubicom32_v4)
3388 + {
3389 + if (mode == DImode)
3390 + *total = COSTS_N_INSNS (15);
3391 + else
3392 + *total = COSTS_N_INSNS (5);
3393 + }
3394 + else
3395 + {
3396 + if (mode == DImode)
3397 + *total = COSTS_N_INSNS (6);
3398 + else
3399 + *total = COSTS_N_INSNS (2);
3400 + }
3401 + }
3402 + return true;
3403 +
3404 + case UNSPEC:
3405 + if (XINT (x, 1) == UNSPEC_FDPIC_GOT
3406 + || XINT (x, 1) == UNSPEC_FDPIC_GOT_FUNCDESC)
3407 + *total = 0;
3408 + return true;
3409 +
3410 + default:
3411 + return false;
3412 + }
3413 +}
3414 +
3415 +/* Return 1 if ADDR can have different meanings depending on the machine
3416 + mode of the memory reference it is used for or if the address is
3417 + valid for some modes but not others.
3418 +
3419 + Autoincrement and autodecrement addresses typically have
3420 + mode-dependent effects because the amount of the increment or
3421 + decrement is the size of the operand being addressed. Some machines
3422 + have other mode-dependent addresses. Many RISC machines have no
3423 + mode-dependent addresses.
3424 +
3425 + You may assume that ADDR is a valid address for the machine. */
3426 +
3427 +int
3428 +ubicom32_mode_dependent_address_p (rtx addr)
3429 +{
3430 + if (GET_CODE (addr) == POST_INC
3431 + || GET_CODE (addr) == PRE_INC
3432 + || GET_CODE (addr) == POST_DEC
3433 + || GET_CODE (addr) == PRE_DEC
3434 + || GET_CODE (addr) == POST_MODIFY
3435 + || GET_CODE (addr) == PRE_MODIFY)
3436 + return 1;
3437 +
3438 + return 0;
3439 +}
3440 +
3441 +static void
3442 +ubicom32_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
3443 +{
3444 + fprintf (file, "/* frame/pretend: %ld/%d save_regs: %d out_args: %d %s */\n",
3445 + get_frame_size (), crtl->args.pretend_args_size,
3446 + save_regs_size, crtl->outgoing_args_size,
3447 + current_function_is_leaf ? "leaf" : "nonleaf");
3448 +}
3449 +
3450 +static void
3451 +ubicom32_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
3452 + HOST_WIDE_INT size ATTRIBUTE_UNUSED)
3453 +{
3454 + ubicom32_reorg_completed = 0;
3455 +}
3456 +
3457 +static void
3458 +ubicom32_machine_dependent_reorg (void)
3459 +{
3460 +#if 0 /* Commenting out this optimization until it is fixed */
3461 + if (optimize)
3462 + {
3463 + compute_bb_for_insn ();
3464 +
3465 + /* Do a very simple CSE pass over just the hard registers. */
3466 + reload_cse_regs (get_insns ());
3467 +
3468 + /* Reload_cse_regs can eliminate potentially-trapping MEMs.
3469 + Remove any EH edges associated with them. */
3470 + if (flag_non_call_exceptions)
3471 + purge_all_dead_edges ();
3472 + }
3473 +#endif
3474 + ubicom32_reorg_completed = 1;
3475 +}
3476 +
3477 +void
3478 +ubicom32_output_cond_jump (rtx insn, rtx cond, rtx target)
3479 +{
3480 + rtx note;
3481 + int mostly_false_jump;
3482 + rtx xoperands[2];
3483 + rtx cc_reg;
3484 +
3485 + note = find_reg_note (insn, REG_BR_PROB, 0);
3486 + mostly_false_jump = !note || (INTVAL (XEXP (note, 0))
3487 + <= REG_BR_PROB_BASE / 2);
3488 +
3489 + xoperands[0] = target;
3490 + xoperands[1] = cond;
3491 + cc_reg = XEXP (cond, 0);
3492 +
3493 + if (GET_MODE (cc_reg) == CCWmode
3494 + || GET_MODE (cc_reg) == CCWZmode
3495 + || GET_MODE (cc_reg) == CCWZNmode)
3496 + {
3497 + if (mostly_false_jump)
3498 + output_asm_insn ("jmp%b1.w.f\t%0", xoperands);
3499 + else
3500 + output_asm_insn ("jmp%b1.w.t\t%0", xoperands);
3501 + return;
3502 + }
3503 +
3504 + if (GET_MODE (cc_reg) == CCSmode
3505 + || GET_MODE (cc_reg) == CCSZmode
3506 + || GET_MODE (cc_reg) == CCSZNmode)
3507 + {
3508 + if (mostly_false_jump)
3509 + output_asm_insn ("jmp%b1.s.f\t%0", xoperands);
3510 + else
3511 + output_asm_insn ("jmp%b1.s.t\t%0", xoperands);
3512 + return;
3513 + }
3514 +
3515 + abort ();
3516 +}
3517 +
3518 +/* Return non-zero if FUNC is a naked function. */
3519 +
3520 +static int
3521 +ubicom32_naked_function_p (void)
3522 +{
3523 + return lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
3524 +}
3525 +
3526 +/* Return an RTX indicating where the return address to the
3527 + calling function can be found. */
3528 +rtx
3529 +ubicom32_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
3530 +{
3531 + if (count != 0)
3532 + return NULL_RTX;
3533 +
3534 + return get_hard_reg_initial_val (Pmode, LINK_REGNO);
3535 +}
3536 +
3537 +/*
3538 + * ubicom32_readonly_data_section: This routtine handles code
3539 + * at the start of readonly data sections
3540 + */
3541 +static void
3542 +ubicom32_readonly_data_section (const void *data ATTRIBUTE_UNUSED)
3543 +{
3544 + static int num = 0;
3545 + if (in_section == readonly_data_section){
3546 + fprintf (asm_out_file, "%s", DATA_SECTION_ASM_OP);
3547 + if (flag_data_sections){
3548 + fprintf (asm_out_file, ".rodata%d", num);
3549 + fprintf (asm_out_file, ",\"a\"");
3550 + }
3551 + fprintf (asm_out_file, "\n");
3552 + }
3553 + num++;
3554 +}
3555 +
3556 +/*
3557 + * ubicom32_text_section: not in readonly section
3558 + */
3559 +static void
3560 +ubicom32_text_section(const void *data ATTRIBUTE_UNUSED)
3561 +{
3562 + fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
3563 +}
3564 +
3565 +/*
3566 + * ubicom32_data_section: not in readonly section
3567 + */
3568 +static void
3569 +ubicom32_data_section(const void *data ATTRIBUTE_UNUSED)
3570 +{
3571 + fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
3572 +}
3573 +
3574 +/*
3575 + * ubicom32_asm_init_sections: This routine implements special
3576 + * section handling
3577 + */
3578 +static void
3579 +ubicom32_asm_init_sections(void)
3580 +{
3581 + text_section = get_unnamed_section(SECTION_CODE, ubicom32_text_section, NULL);
3582 +
3583 + data_section = get_unnamed_section(SECTION_WRITE, ubicom32_data_section, NULL);
3584 +
3585 + readonly_data_section = get_unnamed_section(0, ubicom32_readonly_data_section, NULL);
3586 +}
3587 +
3588 +/*
3589 + * ubicom32_profiler: This routine would call
3590 + * mcount to support prof and gprof if mcount
3591 + * was supported. Currently, do nothing.
3592 + */
3593 +void
3594 +ubicom32_profiler(void)
3595 +{
3596 +}
3597 +
3598 +/* Initialise the builtin functions. Start by initialising
3599 + descriptions of different types of functions (e.g., void fn(int),
3600 + int fn(void)), and then use these to define the builtins. */
3601 +static void
3602 +ubicom32_init_builtins (void)
3603 +{
3604 + tree endlink;
3605 + tree short_unsigned_endlink;
3606 + tree unsigned_endlink;
3607 + tree short_unsigned_ftype_short_unsigned;
3608 + tree unsigned_ftype_unsigned;
3609 +
3610 + endlink = void_list_node;
3611 +
3612 + short_unsigned_endlink
3613 + = tree_cons (NULL_TREE, short_unsigned_type_node, endlink);
3614 +
3615 + unsigned_endlink
3616 + = tree_cons (NULL_TREE, unsigned_type_node, endlink);
3617 +
3618 + short_unsigned_ftype_short_unsigned
3619 + = build_function_type (short_unsigned_type_node, short_unsigned_endlink);
3620 +
3621 + unsigned_ftype_unsigned
3622 + = build_function_type (unsigned_type_node, unsigned_endlink);
3623 +
3624 + /* Initialise the byte swap function. */
3625 + add_builtin_function ("__builtin_ubicom32_swapb_2",
3626 + short_unsigned_ftype_short_unsigned,
3627 + UBICOM32_BUILTIN_UBICOM32_SWAPB_2,
3628 + BUILT_IN_MD, NULL,
3629 + NULL_TREE);
3630 +
3631 + /* Initialise the byte swap function. */
3632 + add_builtin_function ("__builtin_ubicom32_swapb_4",
3633 + unsigned_ftype_unsigned,
3634 + UBICOM32_BUILTIN_UBICOM32_SWAPB_4,
3635 + BUILT_IN_MD, NULL,
3636 + NULL_TREE);
3637 +}
3638 +
3639 +/* Given a builtin function taking 2 operands (i.e., target + source),
3640 + emit the RTL for the underlying instruction. */
3641 +static rtx
3642 +ubicom32_expand_builtin_2op (enum insn_code icode, tree arglist, rtx target)
3643 +{
3644 + tree arg0;
3645 + rtx op0, pat;
3646 + enum machine_mode tmode, mode0;
3647 +
3648 + /* Grab the incoming argument and emit its RTL. */
3649 + arg0 = TREE_VALUE (arglist);
3650 + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
3651 +
3652 + /* Determine the modes of the instruction operands. */
3653 + tmode = insn_data[icode].operand[0].mode;
3654 + mode0 = insn_data[icode].operand[1].mode;
3655 +
3656 + /* Ensure that the incoming argument RTL is in a register of the
3657 + correct mode. */
3658 + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0))
3659 + op0 = copy_to_mode_reg (mode0, op0);
3660 +
3661 + /* If there isn't a suitable target, emit a target register. */
3662 + if (target == 0
3663 + || GET_MODE (target) != tmode
3664 + || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3665 + target = gen_reg_rtx (tmode);
3666 +
3667 + /* Emit and return the new instruction. */
3668 + pat = GEN_FCN (icode) (target, op0);
3669 + if (!pat)
3670 + return 0;
3671 + emit_insn (pat);
3672 +
3673 + return target;
3674 +}
3675 +
3676 +/* Expand a call to a builtin function. */
3677 +static rtx
3678 +ubicom32_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
3679 + enum machine_mode mode ATTRIBUTE_UNUSED,
3680 + int ignore ATTRIBUTE_UNUSED)
3681 +{
3682 + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3683 + tree arglist = CALL_EXPR_ARGS(exp);
3684 + int fcode = DECL_FUNCTION_CODE (fndecl);
3685 +
3686 + switch (fcode)
3687 + {
3688 + case UBICOM32_BUILTIN_UBICOM32_SWAPB_2:
3689 + return ubicom32_expand_builtin_2op (CODE_FOR_bswaphi, arglist, target);
3690 +
3691 + case UBICOM32_BUILTIN_UBICOM32_SWAPB_4:
3692 + return ubicom32_expand_builtin_2op (CODE_FOR_bswapsi, arglist, target);
3693 +
3694 + default:
3695 + gcc_unreachable();
3696 + }
3697 +
3698 + /* Should really do something sensible here. */
3699 + return NULL_RTX;
3700 +}
3701 +
3702 +/* Fold any constant argument for a swapb.2 instruction. */
3703 +static tree
3704 +ubicom32_fold_builtin_ubicom32_swapb_2 (tree fndecl, tree arglist)
3705 +{
3706 + tree arg0;
3707 +
3708 + arg0 = TREE_VALUE (arglist);
3709 +
3710 + /* Optimize constant value. */
3711 + if (TREE_CODE (arg0) == INTEGER_CST)
3712 + {
3713 + HOST_WIDE_INT v;
3714 + HOST_WIDE_INT res;
3715 +
3716 + v = TREE_INT_CST_LOW (arg0);
3717 + res = ((v >> 8) & 0xff)
3718 + | ((v & 0xff) << 8);
3719 +
3720 + return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), res);
3721 + }
3722 +
3723 + return NULL_TREE;
3724 +}
3725 +
3726 +/* Fold any constant argument for a swapb.4 instruction. */
3727 +static tree
3728 +ubicom32_fold_builtin_ubicom32_swapb_4 (tree fndecl, tree arglist)
3729 +{
3730 + tree arg0;
3731 +
3732 + arg0 = TREE_VALUE (arglist);
3733 +
3734 + /* Optimize constant value. */
3735 + if (TREE_CODE (arg0) == INTEGER_CST)
3736 + {
3737 + unsigned HOST_WIDE_INT v;
3738 + unsigned HOST_WIDE_INT res;
3739 +
3740 + v = TREE_INT_CST_LOW (arg0);
3741 + res = ((v >> 24) & 0xff)
3742 + | (((v >> 16) & 0xff) << 8)
3743 + | (((v >> 8) & 0xff) << 16)
3744 + | ((v & 0xff) << 24);
3745 +
3746 + return build_int_cst_wide (TREE_TYPE (TREE_TYPE (fndecl)), res, 0);
3747 + }
3748 +
3749 + return NULL_TREE;
3750 +}
3751 +
3752 +/* Fold any constant arguments for builtin functions. */
3753 +static tree
3754 +ubicom32_fold_builtin (tree fndecl, tree arglist, bool ignore ATTRIBUTE_UNUSED)
3755 +{
3756 + switch (DECL_FUNCTION_CODE (fndecl))