comparison gcc/config/nds32/nds32-md-auxiliary.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
comparison
equal deleted inserted replaced
111:04ced10e8804 131:84e7813d76e9
1 /* Auxiliary functions for output asm template or expand rtl 1 /* Auxiliary functions for output asm template or expand rtl
2 pattern of Andes NDS32 cpu for GNU compiler 2 pattern of Andes NDS32 cpu for GNU compiler
3 Copyright (C) 2012-2017 Free Software Foundation, Inc. 3 Copyright (C) 2012-2018 Free Software Foundation, Inc.
4 Contributed by Andes Technology Corporation. 4 Contributed by Andes Technology Corporation.
5 5
6 This file is part of GCC. 6 This file is part of GCC.
7 7
8 GCC is free software; you can redistribute it and/or modify it 8 GCC is free software; you can redistribute it and/or modify it
18 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see 19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */ 20 <http://www.gnu.org/licenses/>. */
21 21
22 /* ------------------------------------------------------------------------ */ 22 /* ------------------------------------------------------------------------ */
23
24 #define IN_TARGET_CODE 1
23 25
24 #include "config.h" 26 #include "config.h"
25 #include "system.h" 27 #include "system.h"
26 #include "coretypes.h" 28 #include "coretypes.h"
27 #include "backend.h" 29 #include "backend.h"
32 #include "tm_p.h" 34 #include "tm_p.h"
33 #include "optabs.h" /* For GEN_FCN. */ 35 #include "optabs.h" /* For GEN_FCN. */
34 #include "recog.h" 36 #include "recog.h"
35 #include "output.h" 37 #include "output.h"
36 #include "tm-constrs.h" 38 #include "tm-constrs.h"
39 #include "expr.h"
40 #include "emit-rtl.h"
41 #include "explow.h"
42 #include "stringpool.h"
43 #include "attribs.h"
44
37 45
38 /* ------------------------------------------------------------------------ */ 46 /* ------------------------------------------------------------------------ */
47
48 static int
49 nds32_regno_to_enable4 (unsigned regno)
50 {
51 switch (regno)
52 {
53 case 28: /* $r28/fp */
54 return 0x8;
55 case 29: /* $r29/gp */
56 return 0x4;
57 case 30: /* $r30/lp */
58 return 0x2;
59 case 31: /* $r31/sp */
60 return 0x1;
61 default:
62 gcc_unreachable ();
63 }
64 }
39 65
40 /* A helper function to return character based on byte size. */ 66 /* A helper function to return character based on byte size. */
41 static char 67 static char
42 nds32_byte_to_size (int byte) 68 nds32_byte_to_size (int byte)
43 { 69 {
53 /* Normally it should not be here. */ 79 /* Normally it should not be here. */
54 gcc_unreachable (); 80 gcc_unreachable ();
55 } 81 }
56 } 82 }
57 83
58 /* A helper function to return memory format. */ 84 static int
85 nds32_inverse_cond_code (int code)
86 {
87 switch (code)
88 {
89 case NE:
90 return EQ;
91 case EQ:
92 return NE;
93 case GT:
94 return LE;
95 case LE:
96 return GT;
97 case GE:
98 return LT;
99 case LT:
100 return GE;
101 default:
102 gcc_unreachable ();
103 }
104 }
105
106 static const char *
107 nds32_cond_code_str (int code)
108 {
109 switch (code)
110 {
111 case NE:
112 return "ne";
113 case EQ:
114 return "eq";
115 case GT:
116 return "gt";
117 case LE:
118 return "le";
119 case GE:
120 return "ge";
121 case LT:
122 return "lt";
123 default:
124 gcc_unreachable ();
125 }
126 }
127
128 static void
129 output_cond_branch (int code, const char *suffix, bool r5_p,
130 bool long_jump_p, rtx *operands)
131 {
132 char pattern[256];
133 const char *cond_code;
134 bool align_p = NDS32_ALIGN_P ();
135 const char *align = align_p ? "\t.align\t2\n" : "";
136
137 if (r5_p && REGNO (operands[2]) == 5 && TARGET_16_BIT)
138 {
139 /* This is special case for beqs38 and bnes38,
140 second operand 2 can't be $r5 and it's almost meanless,
141 however it may occur after copy propgation. */
142 if (code == EQ)
143 {
144 /* $r5 == $r5 always taken! */
145 if (long_jump_p)
146 snprintf (pattern, sizeof (pattern),
147 "j\t%%3");
148 else
149 snprintf (pattern, sizeof (pattern),
150 "j8\t%%3");
151 }
152 else
153 /* Don't output anything since $r5 != $r5 never taken! */
154 pattern[0] = '\0';
155 }
156 else if (long_jump_p)
157 {
158 int inverse_code = nds32_inverse_cond_code (code);
159 cond_code = nds32_cond_code_str (inverse_code);
160
161 /* b<cond><suffix> $r0, $r1, .L0
162 =>
163 b<inverse_cond><suffix> $r0, $r1, .LCB0
164 j .L0
165 .LCB0:
166
167 or
168
169 b<cond><suffix> $r0, $r1, .L0
170 =>
171 b<inverse_cond><suffix> $r0, $r1, .LCB0
172 j .L0
173 .LCB0:
174 */
175 if (r5_p && TARGET_16_BIT)
176 {
177 snprintf (pattern, sizeof (pattern),
178 "b%ss38\t %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:",
179 cond_code, align);
180 }
181 else
182 {
183 snprintf (pattern, sizeof (pattern),
184 "b%s%s\t%%1, %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:",
185 cond_code, suffix, align);
186 }
187 }
188 else
189 {
190 cond_code = nds32_cond_code_str (code);
191 if (r5_p && TARGET_16_BIT)
192 {
193 /* b<cond>s38 $r1, .L0 */
194 snprintf (pattern, sizeof (pattern),
195 "b%ss38\t %%2, %%3", cond_code);
196 }
197 else
198 {
199 /* b<cond><suffix> $r0, $r1, .L0 */
200 snprintf (pattern, sizeof (pattern),
201 "b%s%s\t%%1, %%2, %%3", cond_code, suffix);
202 }
203 }
204
205 output_asm_insn (pattern, operands);
206 }
207
208 static void
209 output_cond_branch_compare_zero (int code, const char *suffix,
210 bool long_jump_p, rtx *operands,
211 bool ta_implied_p)
212 {
213 char pattern[256];
214 const char *cond_code;
215 bool align_p = NDS32_ALIGN_P ();
216 const char *align = align_p ? "\t.align\t2\n" : "";
217 if (long_jump_p)
218 {
219 int inverse_code = nds32_inverse_cond_code (code);
220 cond_code = nds32_cond_code_str (inverse_code);
221
222 if (ta_implied_p && TARGET_16_BIT)
223 {
224 /* b<cond>z<suffix> .L0
225 =>
226 b<inverse_cond>z<suffix> .LCB0
227 j .L0
228 .LCB0:
229 */
230 snprintf (pattern, sizeof (pattern),
231 "b%sz%s\t.LCB%%=\n\tj\t%%2\n%s.LCB%%=:",
232 cond_code, suffix, align);
233 }
234 else
235 {
236 /* b<cond>z<suffix> $r0, .L0
237 =>
238 b<inverse_cond>z<suffix> $r0, .LCB0
239 j .L0
240 .LCB0:
241 */
242 snprintf (pattern, sizeof (pattern),
243 "b%sz%s\t%%1, .LCB%%=\n\tj\t%%2\n%s.LCB%%=:",
244 cond_code, suffix, align);
245 }
246 }
247 else
248 {
249 cond_code = nds32_cond_code_str (code);
250 if (ta_implied_p && TARGET_16_BIT)
251 {
252 /* b<cond>z<suffix> .L0 */
253 snprintf (pattern, sizeof (pattern),
254 "b%sz%s\t%%2", cond_code, suffix);
255 }
256 else
257 {
258 /* b<cond>z<suffix> $r0, .L0 */
259 snprintf (pattern, sizeof (pattern),
260 "b%sz%s\t%%1, %%2", cond_code, suffix);
261 }
262 }
263
264 output_asm_insn (pattern, operands);
265 }
266
267 static void
268 nds32_split_shiftrtdi3 (rtx dst, rtx src, rtx shiftamount, bool logic_shift_p)
269 {
270 rtx src_high_part;
271 rtx dst_high_part, dst_low_part;
272
273 dst_high_part = nds32_di_high_part_subreg (dst);
274 src_high_part = nds32_di_high_part_subreg (src);
275 dst_low_part = nds32_di_low_part_subreg (dst);
276
277 if (CONST_INT_P (shiftamount))
278 {
279 if (INTVAL (shiftamount) < 32)
280 {
281 if (logic_shift_p)
282 {
283 emit_insn (gen_uwext (dst_low_part, src,
284 shiftamount));
285 emit_insn (gen_lshrsi3 (dst_high_part, src_high_part,
286 shiftamount));
287 }
288 else
289 {
290 emit_insn (gen_wext (dst_low_part, src,
291 shiftamount));
292 emit_insn (gen_ashrsi3 (dst_high_part, src_high_part,
293 shiftamount));
294 }
295 }
296 else
297 {
298 rtx new_shift_amout = gen_int_mode(INTVAL (shiftamount) - 32, SImode);
299
300 if (logic_shift_p)
301 {
302 emit_insn (gen_lshrsi3 (dst_low_part, src_high_part,
303 new_shift_amout));
304 emit_move_insn (dst_high_part, const0_rtx);
305 }
306 else
307 {
308 emit_insn (gen_ashrsi3 (dst_low_part, src_high_part,
309 new_shift_amout));
310 emit_insn (gen_ashrsi3 (dst_high_part, src_high_part,
311 GEN_INT (31)));
312 }
313 }
314 }
315 else
316 {
317 rtx dst_low_part_l32, dst_high_part_l32;
318 rtx dst_low_part_g32, dst_high_part_g32;
319 rtx new_shift_amout, select_reg;
320 dst_low_part_l32 = gen_reg_rtx (SImode);
321 dst_high_part_l32 = gen_reg_rtx (SImode);
322 dst_low_part_g32 = gen_reg_rtx (SImode);
323 dst_high_part_g32 = gen_reg_rtx (SImode);
324 new_shift_amout = gen_reg_rtx (SImode);
325 select_reg = gen_reg_rtx (SImode);
326
327 emit_insn (gen_andsi3 (shiftamount, shiftamount, GEN_INT (0x3f)));
328
329 if (logic_shift_p)
330 {
331 /*
332 if (shiftamount < 32)
333 dst_low_part = wext (src, shiftamount)
334 dst_high_part = src_high_part >> shiftamount
335 else
336 dst_low_part = src_high_part >> (shiftamount & 0x1f)
337 dst_high_part = 0
338 */
339 emit_insn (gen_uwext (dst_low_part_l32, src, shiftamount));
340 emit_insn (gen_lshrsi3 (dst_high_part_l32, src_high_part,
341 shiftamount));
342
343 emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f)));
344 emit_insn (gen_lshrsi3 (dst_low_part_g32, src_high_part,
345 new_shift_amout));
346 emit_move_insn (dst_high_part_g32, const0_rtx);
347 }
348 else
349 {
350 /*
351 if (shiftamount < 32)
352 dst_low_part = wext (src, shiftamount)
353 dst_high_part = src_high_part >> shiftamount
354 else
355 dst_low_part = src_high_part >> (shiftamount & 0x1f)
356 # shift 31 for sign extend
357 dst_high_part = src_high_part >> 31
358 */
359 emit_insn (gen_wext (dst_low_part_l32, src, shiftamount));
360 emit_insn (gen_ashrsi3 (dst_high_part_l32, src_high_part,
361 shiftamount));
362
363 emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f)));
364 emit_insn (gen_ashrsi3 (dst_low_part_g32, src_high_part,
365 new_shift_amout));
366 emit_insn (gen_ashrsi3 (dst_high_part_g32, src_high_part,
367 GEN_INT (31)));
368 }
369
370 emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32)));
371
372 emit_insn (gen_cmovnsi (dst_low_part, select_reg,
373 dst_low_part_l32, dst_low_part_g32));
374 emit_insn (gen_cmovnsi (dst_high_part, select_reg,
375 dst_high_part_l32, dst_high_part_g32));
376 }
377 }
378
379 /* ------------------------------------------------------------------------ */
380
381 /* Auxiliary function for expand RTL pattern. */
382
383 enum nds32_expand_result_type
384 nds32_expand_cbranch (rtx *operands)
385 {
386 rtx tmp_reg;
387 enum rtx_code code;
388
389 code = GET_CODE (operands[0]);
390
391 /* If operands[2] is (const_int 0),
392 we can use beqz,bnez,bgtz,bgez,bltz,or blez instructions.
393 So we have gcc generate original template rtx. */
394 if (GET_CODE (operands[2]) == CONST_INT)
395 if (INTVAL (operands[2]) == 0)
396 if ((code != GTU)
397 && (code != GEU)
398 && (code != LTU)
399 && (code != LEU))
400 return EXPAND_CREATE_TEMPLATE;
401
402 /* For other comparison, NDS32 ISA only has slt (Set-on-Less-Than)
403 behavior for the comparison, we might need to generate other
404 rtx patterns to achieve same semantic. */
405 switch (code)
406 {
407 case GT:
408 case GTU:
409 if (GET_CODE (operands[2]) == CONST_INT)
410 {
411 /* GT reg_A, const_int => !(LT reg_A, const_int + 1) */
412 if (optimize_size || optimize == 0)
413 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
414 else
415 tmp_reg = gen_reg_rtx (SImode);
416
417 /* We want to plus 1 into the integer value
418 of operands[2] to create 'slt' instruction.
419 This caculation is performed on the host machine,
420 which may be 64-bit integer.
421 So the meaning of caculation result may be
422 different from the 32-bit nds32 target.
423
424 For example:
425 0x7fffffff + 0x1 -> 0x80000000,
426 this value is POSITIVE on 64-bit machine,
427 but the expected value on 32-bit nds32 target
428 should be NEGATIVE value.
429
430 Hence, instead of using GEN_INT(), we use gen_int_mode() to
431 explicitly create SImode constant rtx. */
432 enum rtx_code cmp_code;
433
434 rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
435 if (satisfies_constraint_Is15 (plus1))
436 {
437 operands[2] = plus1;
438 cmp_code = EQ;
439 if (code == GT)
440 {
441 /* GT, use slts instruction */
442 emit_insn (
443 gen_slts_compare (tmp_reg, operands[1], operands[2]));
444 }
445 else
446 {
447 /* GTU, use slt instruction */
448 emit_insn (
449 gen_slt_compare (tmp_reg, operands[1], operands[2]));
450 }
451 }
452 else
453 {
454 cmp_code = NE;
455 if (code == GT)
456 {
457 /* GT, use slts instruction */
458 emit_insn (
459 gen_slts_compare (tmp_reg, operands[2], operands[1]));
460 }
461 else
462 {
463 /* GTU, use slt instruction */
464 emit_insn (
465 gen_slt_compare (tmp_reg, operands[2], operands[1]));
466 }
467 }
468
469 PUT_CODE (operands[0], cmp_code);
470 operands[1] = tmp_reg;
471 operands[2] = const0_rtx;
472 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
473 operands[2], operands[3]));
474
475 return EXPAND_DONE;
476 }
477 else
478 {
479 /* GT reg_A, reg_B => LT reg_B, reg_A */
480 if (optimize_size || optimize == 0)
481 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
482 else
483 tmp_reg = gen_reg_rtx (SImode);
484
485 if (code == GT)
486 {
487 /* GT, use slts instruction */
488 emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
489 }
490 else
491 {
492 /* GTU, use slt instruction */
493 emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
494 }
495
496 PUT_CODE (operands[0], NE);
497 operands[1] = tmp_reg;
498 operands[2] = const0_rtx;
499 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
500 operands[2], operands[3]));
501
502 return EXPAND_DONE;
503 }
504
505 case GE:
506 case GEU:
507 /* GE reg_A, reg_B => !(LT reg_A, reg_B) */
508 /* GE reg_A, const_int => !(LT reg_A, const_int) */
509 if (optimize_size || optimize == 0)
510 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
511 else
512 tmp_reg = gen_reg_rtx (SImode);
513
514 if (code == GE)
515 {
516 /* GE, use slts instruction */
517 emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
518 }
519 else
520 {
521 /* GEU, use slt instruction */
522 emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
523 }
524
525 PUT_CODE (operands[0], EQ);
526 operands[1] = tmp_reg;
527 operands[2] = const0_rtx;
528 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
529 operands[2], operands[3]));
530
531 return EXPAND_DONE;
532
533 case LT:
534 case LTU:
535 /* LT reg_A, reg_B => LT reg_A, reg_B */
536 /* LT reg_A, const_int => LT reg_A, const_int */
537 if (optimize_size || optimize == 0)
538 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
539 else
540 tmp_reg = gen_reg_rtx (SImode);
541
542 if (code == LT)
543 {
544 /* LT, use slts instruction */
545 emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
546 }
547 else
548 {
549 /* LTU, use slt instruction */
550 emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
551 }
552
553 PUT_CODE (operands[0], NE);
554 operands[1] = tmp_reg;
555 operands[2] = const0_rtx;
556 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
557 operands[2], operands[3]));
558
559 return EXPAND_DONE;
560
561 case LE:
562 case LEU:
563 if (GET_CODE (operands[2]) == CONST_INT)
564 {
565 /* LE reg_A, const_int => LT reg_A, const_int + 1 */
566 if (optimize_size || optimize == 0)
567 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
568 else
569 tmp_reg = gen_reg_rtx (SImode);
570
571 enum rtx_code cmp_code;
572 /* Note that (le:SI X INT_MAX) is not the same as (lt:SI X INT_MIN).
573 We better have an assert here in case GCC does not properly
574 optimize it away. The INT_MAX here is 0x7fffffff for target. */
575 rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
576 if (satisfies_constraint_Is15 (plus1))
577 {
578 operands[2] = plus1;
579 cmp_code = NE;
580 if (code == LE)
581 {
582 /* LE, use slts instruction */
583 emit_insn (
584 gen_slts_compare (tmp_reg, operands[1], operands[2]));
585 }
586 else
587 {
588 /* LEU, use slt instruction */
589 emit_insn (
590 gen_slt_compare (tmp_reg, operands[1], operands[2]));
591 }
592 }
593 else
594 {
595 cmp_code = EQ;
596 if (code == LE)
597 {
598 /* LE, use slts instruction */
599 emit_insn (
600 gen_slts_compare (tmp_reg, operands[2], operands[1]));
601 }
602 else
603 {
604 /* LEU, use slt instruction */
605 emit_insn (
606 gen_slt_compare (tmp_reg, operands[2], operands[1]));
607 }
608 }
609
610 PUT_CODE (operands[0], cmp_code);
611 operands[1] = tmp_reg;
612 operands[2] = const0_rtx;
613 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
614 operands[2], operands[3]));
615
616 return EXPAND_DONE;
617 }
618 else
619 {
620 /* LE reg_A, reg_B => !(LT reg_B, reg_A) */
621 if (optimize_size || optimize == 0)
622 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
623 else
624 tmp_reg = gen_reg_rtx (SImode);
625
626 if (code == LE)
627 {
628 /* LE, use slts instruction */
629 emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
630 }
631 else
632 {
633 /* LEU, use slt instruction */
634 emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
635 }
636
637 PUT_CODE (operands[0], EQ);
638 operands[1] = tmp_reg;
639 operands[2] = const0_rtx;
640 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
641 operands[2], operands[3]));
642
643 return EXPAND_DONE;
644 }
645
646 case EQ:
647 case NE:
648 /* NDS32 ISA has various form for eq/ne behavior no matter
649 what kind of the operand is.
650 So just generate original template rtx. */
651
652 /* Put operands[2] into register if operands[2] is a large
653 const_int or ISAv2. */
654 if (GET_CODE (operands[2]) == CONST_INT
655 && (!satisfies_constraint_Is11 (operands[2])
656 || TARGET_ISA_V2))
657 operands[2] = force_reg (SImode, operands[2]);
658
659 return EXPAND_CREATE_TEMPLATE;
660
661 default:
662 return EXPAND_FAIL;
663 }
664 }
665
666 enum nds32_expand_result_type
667 nds32_expand_cstore (rtx *operands)
668 {
669 rtx tmp_reg;
670 enum rtx_code code;
671
672 code = GET_CODE (operands[1]);
673
674 switch (code)
675 {
676 case EQ:
677 case NE:
678 if (GET_CODE (operands[3]) == CONST_INT)
679 {
680 /* reg_R = (reg_A == const_int_B)
681 --> xori reg_C, reg_A, const_int_B
682 slti reg_R, reg_C, const_int_1
683 reg_R = (reg_A != const_int_B)
684 --> xori reg_C, reg_A, const_int_B
685 slti reg_R, const_int0, reg_C */
686 tmp_reg = gen_reg_rtx (SImode);
687
688 /* If the integer value is not in the range of imm15s,
689 we need to force register first because our addsi3 pattern
690 only accept nds32_rimm15s_operand predicate. */
691 rtx new_imm = gen_int_mode (-INTVAL (operands[3]), SImode);
692 if (satisfies_constraint_Is15 (new_imm))
693 emit_insn (gen_addsi3 (tmp_reg, operands[2], new_imm));
694 else
695 {
696 if (!(satisfies_constraint_Iu15 (operands[3])
697 || (TARGET_EXT_PERF
698 && satisfies_constraint_It15 (operands[3]))))
699 operands[3] = force_reg (SImode, operands[3]);
700 emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
701 }
702
703 if (code == EQ)
704 emit_insn (gen_slt_eq0 (operands[0], tmp_reg));
705 else
706 emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
707
708 return EXPAND_DONE;
709 }
710 else
711 {
712 /* reg_R = (reg_A == reg_B)
713 --> xor reg_C, reg_A, reg_B
714 slti reg_R, reg_C, const_int_1
715 reg_R = (reg_A != reg_B)
716 --> xor reg_C, reg_A, reg_B
717 slti reg_R, const_int0, reg_C */
718 tmp_reg = gen_reg_rtx (SImode);
719 emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
720 if (code == EQ)
721 emit_insn (gen_slt_eq0 (operands[0], tmp_reg));
722 else
723 emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
724
725 return EXPAND_DONE;
726 }
727 case GT:
728 case GTU:
729 /* reg_R = (reg_A > reg_B) --> slt reg_R, reg_B, reg_A */
730 /* reg_R = (reg_A > const_int_B) --> slt reg_R, const_int_B, reg_A */
731 if (code == GT)
732 {
733 /* GT, use slts instruction */
734 emit_insn (gen_slts_compare (operands[0], operands[3], operands[2]));
735 }
736 else
737 {
738 /* GTU, use slt instruction */
739 emit_insn (gen_slt_compare (operands[0], operands[3], operands[2]));
740 }
741
742 return EXPAND_DONE;
743
744 case GE:
745 case GEU:
746 if (GET_CODE (operands[3]) == CONST_INT)
747 {
748 /* reg_R = (reg_A >= const_int_B)
749 --> movi reg_C, const_int_B - 1
750 slt reg_R, reg_C, reg_A */
751 tmp_reg = gen_reg_rtx (SImode);
752
753 emit_insn (gen_movsi (tmp_reg,
754 gen_int_mode (INTVAL (operands[3]) - 1,
755 SImode)));
756 if (code == GE)
757 {
758 /* GE, use slts instruction */
759 emit_insn (gen_slts_compare (operands[0], tmp_reg, operands[2]));
760 }
761 else
762 {
763 /* GEU, use slt instruction */
764 emit_insn (gen_slt_compare (operands[0], tmp_reg, operands[2]));
765 }
766
767 return EXPAND_DONE;
768 }
769 else
770 {
771 /* reg_R = (reg_A >= reg_B)
772 --> slt reg_R, reg_A, reg_B
773 xori reg_R, reg_R, const_int_1 */
774 if (code == GE)
775 {
776 /* GE, use slts instruction */
777 emit_insn (gen_slts_compare (operands[0],
778 operands[2], operands[3]));
779 }
780 else
781 {
782 /* GEU, use slt instruction */
783 emit_insn (gen_slt_compare (operands[0],
784 operands[2], operands[3]));
785 }
786
787 /* perform 'not' behavior */
788 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
789
790 return EXPAND_DONE;
791 }
792
793 case LT:
794 case LTU:
795 /* reg_R = (reg_A < reg_B) --> slt reg_R, reg_A, reg_B */
796 /* reg_R = (reg_A < const_int_B) --> slt reg_R, reg_A, const_int_B */
797 if (code == LT)
798 {
799 /* LT, use slts instruction */
800 emit_insn (gen_slts_compare (operands[0], operands[2], operands[3]));
801 }
802 else
803 {
804 /* LTU, use slt instruction */
805 emit_insn (gen_slt_compare (operands[0], operands[2], operands[3]));
806 }
807
808 return EXPAND_DONE;
809
810 case LE:
811 case LEU:
812 if (GET_CODE (operands[3]) == CONST_INT)
813 {
814 /* reg_R = (reg_A <= const_int_B)
815 --> movi reg_C, const_int_B + 1
816 slt reg_R, reg_A, reg_C */
817 tmp_reg = gen_reg_rtx (SImode);
818
819 emit_insn (gen_movsi (tmp_reg,
820 gen_int_mode (INTVAL (operands[3]) + 1,
821 SImode)));
822 if (code == LE)
823 {
824 /* LE, use slts instruction */
825 emit_insn (gen_slts_compare (operands[0], operands[2], tmp_reg));
826 }
827 else
828 {
829 /* LEU, use slt instruction */
830 emit_insn (gen_slt_compare (operands[0], operands[2], tmp_reg));
831 }
832
833 return EXPAND_DONE;
834 }
835 else
836 {
837 /* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A
838 xori reg_R, reg_R, const_int_1 */
839 if (code == LE)
840 {
841 /* LE, use slts instruction */
842 emit_insn (gen_slts_compare (operands[0],
843 operands[3], operands[2]));
844 }
845 else
846 {
847 /* LEU, use slt instruction */
848 emit_insn (gen_slt_compare (operands[0],
849 operands[3], operands[2]));
850 }
851
852 /* perform 'not' behavior */
853 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
854
855 return EXPAND_DONE;
856 }
857
858
859 default:
860 gcc_unreachable ();
861 }
862 }
863
864 void
865 nds32_expand_float_cbranch (rtx *operands)
866 {
867 enum rtx_code code = GET_CODE (operands[0]);
868 enum rtx_code new_code = code;
869 rtx cmp_op0 = operands[1];
870 rtx cmp_op1 = operands[2];
871 rtx tmp_reg;
872 rtx tmp;
873
874 int reverse = 0;
875
876 /* Main Goal: Use compare instruction + branch instruction.
877
878 For example:
879 GT, GE: swap condition and swap operands and generate
880 compare instruction(LT, LE) + branch not equal instruction.
881
882 UNORDERED, LT, LE, EQ: no need to change and generate
883 compare instruction(UNORDERED, LT, LE, EQ) + branch not equal instruction.
884
885 ORDERED, NE: reverse condition and generate
886 compare instruction(EQ) + branch equal instruction. */
887
888 switch (code)
889 {
890 case GT:
891 case GE:
892 tmp = cmp_op0;
893 cmp_op0 = cmp_op1;
894 cmp_op1 = tmp;
895 new_code = swap_condition (new_code);
896 break;
897 case UNORDERED:
898 case LT:
899 case LE:
900 case EQ:
901 break;
902 case ORDERED:
903 case NE:
904 new_code = reverse_condition (new_code);
905 reverse = 1;
906 break;
907 case UNGT:
908 case UNGE:
909 new_code = reverse_condition_maybe_unordered (new_code);
910 reverse = 1;
911 break;
912 case UNLT:
913 case UNLE:
914 new_code = reverse_condition_maybe_unordered (new_code);
915 tmp = cmp_op0;
916 cmp_op0 = cmp_op1;
917 cmp_op1 = tmp;
918 new_code = swap_condition (new_code);
919 reverse = 1;
920 break;
921 default:
922 return;
923 }
924
925 tmp_reg = gen_reg_rtx (SImode);
926 emit_insn (gen_rtx_SET (tmp_reg,
927 gen_rtx_fmt_ee (new_code, SImode,
928 cmp_op0, cmp_op1)));
929
930 PUT_CODE (operands[0], reverse ? EQ : NE);
931 emit_insn (gen_cbranchsi4 (operands[0], tmp_reg,
932 const0_rtx, operands[3]));
933 }
934
935 void
936 nds32_expand_float_cstore (rtx *operands)
937 {
938 enum rtx_code code = GET_CODE (operands[1]);
939 enum rtx_code new_code = code;
940 machine_mode mode = GET_MODE (operands[2]);
941
942 rtx cmp_op0 = operands[2];
943 rtx cmp_op1 = operands[3];
944 rtx tmp;
945
946 /* Main Goal: Use compare instruction to store value.
947
948 For example:
949 GT, GE: swap condition and swap operands.
950 reg_R = (reg_A > reg_B) --> fcmplt reg_R, reg_B, reg_A
951 reg_R = (reg_A >= reg_B) --> fcmple reg_R, reg_B, reg_A
952
953 LT, LE, EQ: no need to change, it is already LT, LE, EQ.
954 reg_R = (reg_A < reg_B) --> fcmplt reg_R, reg_A, reg_B
955 reg_R = (reg_A <= reg_B) --> fcmple reg_R, reg_A, reg_B
956 reg_R = (reg_A == reg_B) --> fcmpeq reg_R, reg_A, reg_B
957
958 ORDERED: reverse condition and using xor insturction to achieve 'ORDERED'.
959 reg_R = (reg_A != reg_B) --> fcmpun reg_R, reg_A, reg_B
960 xor reg_R, reg_R, const1_rtx
961
962 NE: reverse condition and using xor insturction to achieve 'NE'.
963 reg_R = (reg_A != reg_B) --> fcmpeq reg_R, reg_A, reg_B
964 xor reg_R, reg_R, const1_rtx */
965 switch (code)
966 {
967 case GT:
968 case GE:
969 tmp = cmp_op0;
970 cmp_op0 = cmp_op1;
971 cmp_op1 =tmp;
972 new_code = swap_condition (new_code);
973 break;
974 case UNORDERED:
975 case LT:
976 case LE:
977 case EQ:
978 break;
979 case ORDERED:
980 if (mode == SFmode)
981 emit_insn (gen_cmpsf_un (operands[0], cmp_op0, cmp_op1));
982 else
983 emit_insn (gen_cmpdf_un (operands[0], cmp_op0, cmp_op1));
984
985 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
986 return;
987 case NE:
988 if (mode == SFmode)
989 emit_insn (gen_cmpsf_eq (operands[0], cmp_op0, cmp_op1));
990 else
991 emit_insn (gen_cmpdf_eq (operands[0], cmp_op0, cmp_op1));
992
993 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
994 return;
995 default:
996 return;
997 }
998
999 emit_insn (gen_rtx_SET (operands[0],
1000 gen_rtx_fmt_ee (new_code, SImode,
1001 cmp_op0, cmp_op1)));
1002 }
1003
1004 enum nds32_expand_result_type
1005 nds32_expand_movcc (rtx *operands)
1006 {
1007 enum rtx_code code = GET_CODE (operands[1]);
1008 enum rtx_code new_code = code;
1009 machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0));
1010 rtx cmp_op0 = XEXP (operands[1], 0);
1011 rtx cmp_op1 = XEXP (operands[1], 1);
1012 rtx tmp;
1013
1014 if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)
1015 && XEXP (operands[1], 1) == const0_rtx)
1016 {
1017 /* If the operands[1] rtx is already (eq X 0) or (ne X 0),
1018 we have gcc generate original template rtx. */
1019 return EXPAND_CREATE_TEMPLATE;
1020 }
1021 else if ((TARGET_FPU_SINGLE && cmp0_mode == SFmode)
1022 || (TARGET_FPU_DOUBLE && cmp0_mode == DFmode))
1023 {
1024 nds32_expand_float_movcc (operands);
1025 }
1026 else
1027 {
1028 /* Since there is only 'slt'(Set when Less Than) instruction for
1029 comparison in Andes ISA, the major strategy we use here is to
1030 convert conditional move into 'LT + EQ' or 'LT + NE' rtx combination.
1031 We design constraints properly so that the reload phase will assist
1032 to make one source operand to use same register as result operand.
1033 Then we can use cmovz/cmovn to catch the other source operand
1034 which has different register. */
1035 int reverse = 0;
1036
1037 /* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part
1038 Strategy : Reverse condition and swap comparison operands
1039
1040 For example:
1041
1042 a <= b ? P : Q (LE or LEU)
1043 --> a > b ? Q : P (reverse condition)
1044 --> b < a ? Q : P (swap comparison operands to achieve 'LT/LTU')
1045
1046 a >= b ? P : Q (GE or GEU)
1047 --> a < b ? Q : P (reverse condition to achieve 'LT/LTU')
1048
1049 a < b ? P : Q (LT or LTU)
1050 --> (NO NEED TO CHANGE, it is already 'LT/LTU')
1051
1052 a > b ? P : Q (GT or GTU)
1053 --> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */
1054 switch (code)
1055 {
1056 case GE: case GEU: case LE: case LEU:
1057 new_code = reverse_condition (code);
1058 reverse = 1;
1059 break;
1060 case EQ:
1061 case NE:
1062 /* no need to reverse condition */
1063 break;
1064 default:
1065 return EXPAND_FAIL;
1066 }
1067
1068 /* For '>' comparison operator, we swap operands
1069 so that we can have 'LT/LTU' operator. */
1070 if (new_code == GT || new_code == GTU)
1071 {
1072 tmp = cmp_op0;
1073 cmp_op0 = cmp_op1;
1074 cmp_op1 = tmp;
1075
1076 new_code = swap_condition (new_code);
1077 }
1078
1079 /* Use a temporary register to store slt/slts result. */
1080 tmp = gen_reg_rtx (SImode);
1081
1082 if (new_code == EQ || new_code == NE)
1083 {
1084 emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1));
1085 /* tmp == 0 if cmp_op0 == cmp_op1. */
1086 operands[1] = gen_rtx_fmt_ee (new_code, VOIDmode, tmp, const0_rtx);
1087 }
1088 else
1089 {
1090 /* This emit_insn will create corresponding 'slt/slts'
1091 insturction. */
1092 if (new_code == LT)
1093 emit_insn (gen_slts_compare (tmp, cmp_op0, cmp_op1));
1094 else if (new_code == LTU)
1095 emit_insn (gen_slt_compare (tmp, cmp_op0, cmp_op1));
1096 else
1097 gcc_unreachable ();
1098
1099 /* Change comparison semantic into (eq X 0) or (ne X 0) behavior
1100 so that cmovz or cmovn will be matched later.
1101
1102 For reverse condition cases, we want to create a semantic that:
1103 (eq X 0) --> pick up "else" part
1104 For normal cases, we want to create a semantic that:
1105 (ne X 0) --> pick up "then" part
1106
1107 Later we will have cmovz/cmovn instruction pattern to
1108 match corresponding behavior and output instruction. */
1109 operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE,
1110 VOIDmode, tmp, const0_rtx);
1111 }
1112 }
1113 return EXPAND_CREATE_TEMPLATE;
1114 }
1115
1116 void
1117 nds32_expand_float_movcc (rtx *operands)
1118 {
1119 if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)
1120 && GET_MODE (XEXP (operands[1], 0)) == SImode
1121 && XEXP (operands[1], 1) == const0_rtx)
1122 {
1123 /* If the operands[1] rtx is already (eq X 0) or (ne X 0),
1124 we have gcc generate original template rtx. */
1125 return;
1126 }
1127 else
1128 {
1129 enum rtx_code code = GET_CODE (operands[1]);
1130 enum rtx_code new_code = code;
1131 machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0));
1132 machine_mode cmp1_mode = GET_MODE (XEXP (operands[1], 1));
1133 rtx cmp_op0 = XEXP (operands[1], 0);
1134 rtx cmp_op1 = XEXP (operands[1], 1);
1135 rtx tmp;
1136
1137 /* Compare instruction Operations: (cmp_op0 condition cmp_op1) ? 1 : 0,
1138 when result is 1, and 'reverse' be set 1 for fcmovzs instructuin. */
1139 int reverse = 0;
1140
1141 /* Main Goal: Use cmpare instruction + conditional move instruction.
1142 Strategy : swap condition and swap comparison operands.
1143
1144 For example:
1145 a > b ? P : Q (GT)
1146 --> a < b ? Q : P (swap condition)
1147 --> b < a ? Q : P (swap comparison operands to achieve 'GT')
1148
1149 a >= b ? P : Q (GE)
1150 --> a <= b ? Q : P (swap condition)
1151 --> b <= a ? Q : P (swap comparison operands to achieve 'GE')
1152
1153 a < b ? P : Q (LT)
1154 --> (NO NEED TO CHANGE, it is already 'LT')
1155
1156 a >= b ? P : Q (LE)
1157 --> (NO NEED TO CHANGE, it is already 'LE')
1158
1159 a == b ? P : Q (EQ)
1160 --> (NO NEED TO CHANGE, it is already 'EQ') */
1161
1162 switch (code)
1163 {
1164 case GT:
1165 case GE:
1166 tmp = cmp_op0;
1167 cmp_op0 = cmp_op1;
1168 cmp_op1 =tmp;
1169 new_code = swap_condition (new_code);
1170 break;
1171 case UNORDERED:
1172 case LT:
1173 case LE:
1174 case EQ:
1175 break;
1176 case ORDERED:
1177 case NE:
1178 reverse = 1;
1179 new_code = reverse_condition (new_code);
1180 break;
1181 case UNGT:
1182 case UNGE:
1183 new_code = reverse_condition_maybe_unordered (new_code);
1184 reverse = 1;
1185 break;
1186 case UNLT:
1187 case UNLE:
1188 new_code = reverse_condition_maybe_unordered (new_code);
1189 tmp = cmp_op0;
1190 cmp_op0 = cmp_op1;
1191 cmp_op1 = tmp;
1192 new_code = swap_condition (new_code);
1193 reverse = 1;
1194 break;
1195 default:
1196 return;
1197 }
1198
1199 /* Use a temporary register to store fcmpxxs result. */
1200 tmp = gen_reg_rtx (SImode);
1201
1202 /* Create float compare instruction for SFmode and DFmode,
1203 other MODE using cstoresi create compare instruction. */
1204 if ((cmp0_mode == DFmode || cmp0_mode == SFmode)
1205 && (cmp1_mode == DFmode || cmp1_mode == SFmode))
1206 {
1207 /* This emit_insn create corresponding float compare instruction */
1208 emit_insn (gen_rtx_SET (tmp,
1209 gen_rtx_fmt_ee (new_code, SImode,
1210 cmp_op0, cmp_op1)));
1211 }
1212 else
1213 {
1214 /* This emit_insn using cstoresi create corresponding
1215 compare instruction */
1216 PUT_CODE (operands[1], new_code);
1217 emit_insn (gen_cstoresi4 (tmp, operands[1],
1218 cmp_op0, cmp_op1));
1219 }
1220 /* operands[1] crete corresponding condition move instruction
1221 for fcmovzs and fcmovns. */
1222 operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE,
1223 VOIDmode, tmp, const0_rtx);
1224 }
1225 }
1226
1227 void
1228 nds32_emit_push_fpr_callee_saved (int base_offset)
1229 {
1230 rtx fpu_insn;
1231 rtx reg, mem;
1232 unsigned int regno = cfun->machine->callee_saved_first_fpr_regno;
1233 unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno;
1234
1235 while (regno <= last_fpr)
1236 {
1237 /* Handling two registers, using fsdi instruction. */
1238 reg = gen_rtx_REG (DFmode, regno);
1239 mem = gen_frame_mem (DFmode, plus_constant (Pmode,
1240 stack_pointer_rtx,
1241 base_offset));
1242 base_offset += 8;
1243 regno += 2;
1244 fpu_insn = emit_move_insn (mem, reg);
1245 RTX_FRAME_RELATED_P (fpu_insn) = 1;
1246 }
1247 }
1248
1249 void
1250 nds32_emit_pop_fpr_callee_saved (int gpr_padding_size)
1251 {
1252 rtx fpu_insn;
1253 rtx reg, mem, addr;
1254 rtx dwarf, adjust_sp_rtx;
1255 unsigned int regno = cfun->machine->callee_saved_first_fpr_regno;
1256 unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno;
1257 int padding = 0;
1258
1259 while (regno <= last_fpr)
1260 {
1261 /* Handling two registers, using fldi.bi instruction. */
1262 if ((regno + 1) >= last_fpr)
1263 padding = gpr_padding_size;
1264
1265 reg = gen_rtx_REG (DFmode, (regno));
1266 addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
1267 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1268 GEN_INT (8 + padding)));
1269 mem = gen_frame_mem (DFmode, addr);
1270 regno += 2;
1271 fpu_insn = emit_move_insn (reg, mem);
1272
1273 adjust_sp_rtx =
1274 gen_rtx_SET (stack_pointer_rtx,
1275 plus_constant (Pmode, stack_pointer_rtx,
1276 8 + padding));
1277
1278 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX);
1279 /* Tell gcc we adjust SP in this insn. */
1280 dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx),
1281 dwarf);
1282 RTX_FRAME_RELATED_P (fpu_insn) = 1;
1283 REG_NOTES (fpu_insn) = dwarf;
1284 }
1285 }
1286
1287 void
1288 nds32_emit_v3pop_fpr_callee_saved (int base)
1289 {
1290 int fpu_base_addr = base;
1291 int regno;
1292 rtx fpu_insn;
1293 rtx reg, mem;
1294 rtx dwarf;
1295
1296 regno = cfun->machine->callee_saved_first_fpr_regno;
1297 while (regno <= cfun->machine->callee_saved_last_fpr_regno)
1298 {
1299 /* Handling two registers, using fldi instruction. */
1300 reg = gen_rtx_REG (DFmode, regno);
1301 mem = gen_frame_mem (DFmode, plus_constant (Pmode,
1302 stack_pointer_rtx,
1303 fpu_base_addr));
1304 fpu_base_addr += 8;
1305 regno += 2;
1306 fpu_insn = emit_move_insn (reg, mem);
1307 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX);
1308 RTX_FRAME_RELATED_P (fpu_insn) = 1;
1309 REG_NOTES (fpu_insn) = dwarf;
1310 }
1311 }
1312
1313 enum nds32_expand_result_type
1314 nds32_expand_extv (rtx *operands)
1315 {
1316 gcc_assert (CONST_INT_P (operands[2]) && CONST_INT_P (operands[3]));
1317 HOST_WIDE_INT width = INTVAL (operands[2]);
1318 HOST_WIDE_INT bitpos = INTVAL (operands[3]);
1319 rtx dst = operands[0];
1320 rtx src = operands[1];
1321
1322 if (MEM_P (src)
1323 && width == 32
1324 && (bitpos % BITS_PER_UNIT) == 0
1325 && GET_MODE_BITSIZE (GET_MODE (dst)) == width)
1326 {
1327 rtx newmem = adjust_address (src, GET_MODE (dst),
1328 bitpos / BITS_PER_UNIT);
1329
1330 rtx base_addr = force_reg (Pmode, XEXP (newmem, 0));
1331
1332 emit_insn (gen_unaligned_loadsi (dst, base_addr));
1333
1334 return EXPAND_DONE;
1335 }
1336 return EXPAND_FAIL;
1337 }
1338
1339 enum nds32_expand_result_type
1340 nds32_expand_insv (rtx *operands)
1341 {
1342 gcc_assert (CONST_INT_P (operands[1]) && CONST_INT_P (operands[2]));
1343 HOST_WIDE_INT width = INTVAL (operands[1]);
1344 HOST_WIDE_INT bitpos = INTVAL (operands[2]);
1345 rtx dst = operands[0];
1346 rtx src = operands[3];
1347
1348 if (MEM_P (dst)
1349 && width == 32
1350 && (bitpos % BITS_PER_UNIT) == 0
1351 && GET_MODE_BITSIZE (GET_MODE (src)) == width)
1352 {
1353 rtx newmem = adjust_address (dst, GET_MODE (src),
1354 bitpos / BITS_PER_UNIT);
1355
1356 rtx base_addr = force_reg (Pmode, XEXP (newmem, 0));
1357
1358 emit_insn (gen_unaligned_storesi (base_addr, src));
1359
1360 return EXPAND_DONE;
1361 }
1362 return EXPAND_FAIL;
1363 }
1364
1365 /* ------------------------------------------------------------------------ */
1366
1367 /* Function to generate PC relative jump table.
1368 Refer to nds32.md for more details.
1369
1370 The following is the sample for the case that diff value
1371 can be presented in '.short' size.
1372
1373 addi $r1, $r1, -(case_lower_bound)
1374 slti $ta, $r1, (case_number)
1375 beqz $ta, .L_skip_label
1376
1377 la $ta, .L35 ! get jump table address
1378 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
1379 addi $ta, $r1, $ta
1380 jr5 $ta
1381
1382 ! jump table entry
1383 L35:
1384 .short .L25-.L35
1385 .short .L26-.L35
1386 .short .L27-.L35
1387 .short .L28-.L35
1388 .short .L29-.L35
1389 .short .L30-.L35
1390 .short .L31-.L35
1391 .short .L32-.L35
1392 .short .L33-.L35
1393 .short .L34-.L35 */
1394 const char *
1395 nds32_output_casesi_pc_relative (rtx *operands)
1396 {
1397 machine_mode mode;
1398 rtx diff_vec;
1399
1400 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])));
1401
1402 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1403
1404 /* Step C: "t <-- operands[1]". */
1405 if (flag_pic)
1406 {
1407 output_asm_insn ("sethi\t$ta, hi20(%l1@GOTOFF)", operands);
1408 output_asm_insn ("ori\t$ta, $ta, lo12(%l1@GOTOFF)", operands);
1409 output_asm_insn ("add\t$ta, $ta, $gp", operands);
1410 }
1411 else
1412 output_asm_insn ("la\t$ta, %l1", operands);
1413
1414 /* Get the mode of each element in the difference vector. */
1415 mode = GET_MODE (diff_vec);
1416
1417 /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
1418 where m is 0, 1, or 2 to load address-diff value from table. */
1419 switch (mode)
1420 {
1421 case E_QImode:
1422 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
1423 break;
1424 case E_HImode:
1425 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
1426 break;
1427 case E_SImode:
1428 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
1429 break;
1430 default:
1431 gcc_unreachable ();
1432 }
1433
1434 /* Step E: "t <-- z + t".
1435 Add table label_ref with address-diff value to
1436 obtain target case address. */
1437 output_asm_insn ("add\t$ta, %2, $ta", operands);
1438
1439 /* Step F: jump to target with register t. */
1440 if (TARGET_16_BIT)
1441 return "jr5\t$ta";
1442 else
1443 return "jr\t$ta";
1444 }
1445
1446 /* Function to generate normal jump table. */
1447 const char *
1448 nds32_output_casesi (rtx *operands)
1449 {
1450 /* Step C: "t <-- operands[1]". */
1451 if (flag_pic)
1452 {
1453 output_asm_insn ("sethi\t$ta, hi20(%l1@GOTOFF)", operands);
1454 output_asm_insn ("ori\t$ta, $ta, lo12(%l1@GOTOFF)", operands);
1455 output_asm_insn ("add\t$ta, $ta, $gp", operands);
1456 }
1457 else
1458 output_asm_insn ("la\t$ta, %l1", operands);
1459
1460 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
1461 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
1462
1463 /* No need to perform Step E, which is only used for
1464 pc relative jump table. */
1465
1466 /* Step F: jump to target with register z. */
1467 if (TARGET_16_BIT)
1468 return "jr5\t%2";
1469 else
1470 return "jr\t%2";
1471 }
1472
1473 /* Function to return memory format. */
59 enum nds32_16bit_address_type 1474 enum nds32_16bit_address_type
60 nds32_mem_format (rtx op) 1475 nds32_mem_format (rtx op)
61 { 1476 {
62 machine_mode mode_test; 1477 machine_mode mode_test;
63 int val; 1478 int val;
69 mode_test = GET_MODE (op); 1484 mode_test = GET_MODE (op);
70 1485
71 op = XEXP (op, 0); 1486 op = XEXP (op, 0);
72 1487
73 /* 45 format. */ 1488 /* 45 format. */
74 if (GET_CODE (op) == REG && (mode_test == SImode)) 1489 if (GET_CODE (op) == REG
1490 && ((mode_test == SImode) || (mode_test == SFmode)))
75 return ADDRESS_REG; 1491 return ADDRESS_REG;
76 1492
77 /* 333 format for QI/HImode. */ 1493 /* 333 format for QI/HImode. */
78 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM)) 1494 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
79 return ADDRESS_LO_REG_IMM3U; 1495 return ADDRESS_LO_REG_IMM3U;
80 1496
81 /* post_inc 333 format. */ 1497 /* post_inc 333 format. */
82 if ((GET_CODE (op) == POST_INC) && (mode_test == SImode)) 1498 if ((GET_CODE (op) == POST_INC)
1499 && ((mode_test == SImode) || (mode_test == SFmode)))
83 { 1500 {
84 regno = REGNO(XEXP (op, 0)); 1501 regno = REGNO(XEXP (op, 0));
85 1502
86 if (regno < 8) 1503 if (regno < 8)
87 return ADDRESS_POST_INC_LO_REG_IMM3U; 1504 return ADDRESS_POST_INC_LO_REG_IMM3U;
88 } 1505 }
89 1506
90 /* post_inc 333 format. */ 1507 /* post_inc 333 format. */
91 if ((GET_CODE (op) == POST_MODIFY) 1508 if ((GET_CODE (op) == POST_MODIFY)
92 && (mode_test == SImode) 1509 && ((mode_test == SImode) || (mode_test == SFmode))
93 && (REG_P (XEXP (XEXP (op, 1), 0))) 1510 && (REG_P (XEXP (XEXP (op, 1), 0)))
94 && (CONST_INT_P (XEXP (XEXP (op, 1), 1)))) 1511 && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
95 { 1512 {
96 regno = REGNO (XEXP (XEXP (op, 1), 0)); 1513 regno = REGNO (XEXP (XEXP (op, 1), 0));
97 val = INTVAL (XEXP (XEXP (op, 1), 1)); 1514 val = INTVAL (XEXP (XEXP (op, 1), 1));
98 if (regno < 8 && val < 32) 1515 if (regno < 8 && val > 0 && val < 32)
99 return ADDRESS_POST_INC_LO_REG_IMM3U; 1516 return ADDRESS_POST_MODIFY_LO_REG_IMM3U;
100 } 1517 }
101 1518
102 if ((GET_CODE (op) == PLUS) 1519 if ((GET_CODE (op) == PLUS)
103 && (GET_CODE (XEXP (op, 0)) == REG) 1520 && (GET_CODE (XEXP (op, 0)) == REG)
104 && (GET_CODE (XEXP (op, 1)) == CONST_INT)) 1521 && (GET_CODE (XEXP (op, 1)) == CONST_INT))
105 { 1522 {
106 val = INTVAL (XEXP (op, 1)); 1523 val = INTVAL (XEXP (op, 1));
107 1524
108 regno = REGNO(XEXP (op, 0)); 1525 regno = REGNO(XEXP (op, 0));
109 1526
110 if (regno > 7 1527 if (regno > 8
111 && regno != SP_REGNUM 1528 && regno != SP_REGNUM
112 && regno != FP_REGNUM) 1529 && regno != FP_REGNUM)
113 return ADDRESS_NOT_16BIT_FORMAT; 1530 return ADDRESS_NOT_16BIT_FORMAT;
114 1531
115 switch (mode_test) 1532 switch (mode_test)
127 break; 1544 break;
128 1545
129 case E_SImode: 1546 case E_SImode:
130 case E_SFmode: 1547 case E_SFmode:
131 case E_DFmode: 1548 case E_DFmode:
1549 /* r8 imply fe format. */
1550 if ((regno == 8) &&
1551 (val >= -128 && val <= -4 && (val % 4 == 0)))
1552 return ADDRESS_R8_IMM7U;
132 /* fp imply 37 format. */ 1553 /* fp imply 37 format. */
133 if ((regno == FP_REGNUM) && 1554 if ((regno == FP_REGNUM) &&
134 (val >= 0 && val < 512 && (val % 4 == 0))) 1555 (val >= 0 && val < 512 && (val % 4 == 0)))
135 return ADDRESS_FP_IMM7U; 1556 return ADDRESS_FP_IMM7U;
136 /* sp imply 37 format. */ 1557 /* sp imply 37 format. */
169 case ADDRESS_LO_REG_IMM3U: 1590 case ADDRESS_LO_REG_IMM3U:
170 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size); 1591 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
171 output_asm_insn (pattern, operands); 1592 output_asm_insn (pattern, operands);
172 break; 1593 break;
173 case ADDRESS_POST_INC_LO_REG_IMM3U: 1594 case ADDRESS_POST_INC_LO_REG_IMM3U:
174 snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size); 1595 snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0, 4");
1596 output_asm_insn (pattern, operands);
1597 break;
1598 case ADDRESS_POST_MODIFY_LO_REG_IMM3U:
1599 snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0");
175 output_asm_insn (pattern, operands); 1600 output_asm_insn (pattern, operands);
176 break; 1601 break;
177 case ADDRESS_FP_IMM7U: 1602 case ADDRESS_FP_IMM7U:
178 output_asm_insn ("swi37\t%1, %0", operands); 1603 output_asm_insn ("swi37\t%1, %0", operands);
179 break; 1604 break;
208 case ADDRESS_LO_REG_IMM3U: 1633 case ADDRESS_LO_REG_IMM3U:
209 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size); 1634 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
210 output_asm_insn (pattern, operands); 1635 output_asm_insn (pattern, operands);
211 break; 1636 break;
212 case ADDRESS_POST_INC_LO_REG_IMM3U: 1637 case ADDRESS_POST_INC_LO_REG_IMM3U:
213 snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size); 1638 snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1, 4");
214 output_asm_insn (pattern, operands); 1639 output_asm_insn (pattern, operands);
1640 break;
1641 case ADDRESS_POST_MODIFY_LO_REG_IMM3U:
1642 snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1");
1643 output_asm_insn (pattern, operands);
1644 break;
1645 case ADDRESS_R8_IMM7U:
1646 output_asm_insn ("lwi45.fe\t%0, %e1", operands);
215 break; 1647 break;
216 case ADDRESS_FP_IMM7U: 1648 case ADDRESS_FP_IMM7U:
217 output_asm_insn ("lwi37\t%0, %1", operands); 1649 output_asm_insn ("lwi37\t%0, %1", operands);
218 break; 1650 break;
219 case ADDRESS_SP_IMM7U: 1651 case ADDRESS_SP_IMM7U:
555 int rb_va_args = cfun->machine->va_args_first_regno; 1987 int rb_va_args = cfun->machine->va_args_first_regno;
556 int re_va_args = cfun->machine->va_args_last_regno; 1988 int re_va_args = cfun->machine->va_args_last_regno;
557 int last_argument_regno = NDS32_FIRST_GPR_REGNUM 1989 int last_argument_regno = NDS32_FIRST_GPR_REGNUM
558 + NDS32_MAX_GPR_REGS_FOR_ARGS 1990 + NDS32_MAX_GPR_REGS_FOR_ARGS
559 - 1; 1991 - 1;
1992 /* Pick up first and last eh data regno for further use. */
1993 int rb_eh_data = cfun->machine->eh_return_data_first_regno;
1994 int re_eh_data = cfun->machine->eh_return_data_last_regno;
1995 int first_eh_data_regno = EH_RETURN_DATA_REGNO (0);
560 /* Pick up callee-saved first regno and last regno for further use. */ 1996 /* Pick up callee-saved first regno and last regno for further use. */
561 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; 1997 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
562 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; 1998 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
563 1999
564 /* First we need to check if we are pushing argument registers not used 2000 /* First we need to check if we are pushing argument registers not used
574 /* We use output_asm_insn() to output assembly code by ourself. */ 2010 /* We use output_asm_insn() to output assembly code by ourself. */
575 output_asm_insn (pattern, operands); 2011 output_asm_insn (pattern, operands);
576 return ""; 2012 return "";
577 } 2013 }
578 2014
2015 /* If last_argument_regno is not mentioned in par_rtx, we can confirm that
2016 we do not need to push argument registers for variadic function.
2017 But we still need to check if we need to push exception handling
2018 data registers. */
2019 if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx))
2020 {
2021 /* Set operands[0] and operands[1]. */
2022 operands[0] = gen_rtx_REG (SImode, rb_eh_data);
2023 operands[1] = gen_rtx_REG (SImode, re_eh_data);
2024 /* Create assembly code pattern: "Rb, Re, { }". */
2025 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
2026 /* We use output_asm_insn() to output assembly code by ourself. */
2027 output_asm_insn (pattern, operands);
2028 return "";
2029 }
2030
579 /* If we step here, we are going to do v3push or multiple push operation. */ 2031 /* If we step here, we are going to do v3push or multiple push operation. */
580 2032
581 /* The v3push/v3pop instruction should only be applied on 2033 /* Refer to nds32.h, where we comment when push25/pop25 are available. */
582 none-isr and none-variadic function. */ 2034 if (NDS32_V3PUSH_AVAILABLE_P)
583 if (TARGET_V3PUSH
584 && !nds32_isr_function_p (current_function_decl)
585 && (cfun->machine->va_args_size == 0))
586 { 2035 {
587 /* For stack v3push: 2036 /* For stack v3push:
588 operands[0]: Re 2037 operands[0]: Re
589 operands[1]: imm8u */ 2038 operands[1]: imm8u */
590 2039
596 2045
597 /* Check if we can generate 'push25 Re,imm8u', 2046 /* Check if we can generate 'push25 Re,imm8u',
598 otherwise, generate 'push25 Re,0'. */ 2047 otherwise, generate 'push25 Re,0'. */
599 sp_adjust = cfun->machine->local_size 2048 sp_adjust = cfun->machine->local_size
600 + cfun->machine->out_args_size 2049 + cfun->machine->out_args_size
601 + cfun->machine->callee_saved_area_gpr_padding_bytes; 2050 + cfun->machine->callee_saved_area_gpr_padding_bytes
2051 + cfun->machine->callee_saved_fpr_regs_size;
602 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) 2052 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
603 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)) 2053 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
604 operands[1] = GEN_INT (sp_adjust); 2054 operands[1] = GEN_INT (sp_adjust);
605 else 2055 else
606 operands[1] = GEN_INT (0); 2056 {
2057 /* Allocate callee saved fpr space. */
2058 if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM)
2059 {
2060 sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes
2061 + cfun->machine->callee_saved_fpr_regs_size;
2062 operands[1] = GEN_INT (sp_adjust);
2063 }
2064 else
2065 {
2066 operands[1] = GEN_INT (0);
2067 }
2068 }
607 2069
608 /* Create assembly code pattern. */ 2070 /* Create assembly code pattern. */
609 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1"); 2071 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
610 } 2072 }
611 else 2073 else
663 { 2125 {
664 /* A string pattern for output_asm_insn(). */ 2126 /* A string pattern for output_asm_insn(). */
665 char pattern[100]; 2127 char pattern[100];
666 /* The operands array which will be used in output_asm_insn(). */ 2128 /* The operands array which will be used in output_asm_insn(). */
667 rtx operands[3]; 2129 rtx operands[3];
2130 /* Pick up first and last eh data regno for further use. */
2131 int rb_eh_data = cfun->machine->eh_return_data_first_regno;
2132 int re_eh_data = cfun->machine->eh_return_data_last_regno;
2133 int first_eh_data_regno = EH_RETURN_DATA_REGNO (0);
668 /* Pick up callee-saved first regno and last regno for further use. */ 2134 /* Pick up callee-saved first regno and last regno for further use. */
669 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; 2135 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
670 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; 2136 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
671 2137
2138 /* We need to check if we need to push exception handling
2139 data registers. */
2140 if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx))
2141 {
2142 /* Set operands[0] and operands[1]. */
2143 operands[0] = gen_rtx_REG (SImode, rb_eh_data);
2144 operands[1] = gen_rtx_REG (SImode, re_eh_data);
2145 /* Create assembly code pattern: "Rb, Re, { }". */
2146 snprintf (pattern, sizeof (pattern), "pop.s\t%s", "%0, %1, { }");
2147 /* We use output_asm_insn() to output assembly code by ourself. */
2148 output_asm_insn (pattern, operands);
2149 return "";
2150 }
2151
672 /* If we step here, we are going to do v3pop or multiple pop operation. */ 2152 /* If we step here, we are going to do v3pop or multiple pop operation. */
673 2153
674 /* The v3push/v3pop instruction should only be applied on 2154 /* Refer to nds32.h, where we comment when push25/pop25 are available. */
675 none-isr and none-variadic function. */ 2155 if (NDS32_V3PUSH_AVAILABLE_P)
676 if (TARGET_V3PUSH
677 && !nds32_isr_function_p (current_function_decl)
678 && (cfun->machine->va_args_size == 0))
679 { 2156 {
680 /* For stack v3pop: 2157 /* For stack v3pop:
681 operands[0]: Re 2158 operands[0]: Re
682 operands[1]: imm8u */ 2159 operands[1]: imm8u */
683 2160
694 In that case, we cannot use 'pop25 Re,imm8u' directly. 2171 In that case, we cannot use 'pop25 Re,imm8u' directly.
695 We have to caculate stack pointer from frame pointer 2172 We have to caculate stack pointer from frame pointer
696 and then use 'pop25 Re,0'. */ 2173 and then use 'pop25 Re,0'. */
697 sp_adjust = cfun->machine->local_size 2174 sp_adjust = cfun->machine->local_size
698 + cfun->machine->out_args_size 2175 + cfun->machine->out_args_size
699 + cfun->machine->callee_saved_area_gpr_padding_bytes; 2176 + cfun->machine->callee_saved_area_gpr_padding_bytes
2177 + cfun->machine->callee_saved_fpr_regs_size;
700 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) 2178 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
701 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) 2179 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
702 && !cfun->calls_alloca) 2180 && !cfun->calls_alloca)
703 operands[1] = GEN_INT (sp_adjust); 2181 operands[1] = GEN_INT (sp_adjust);
704 else 2182 else
705 operands[1] = GEN_INT (0); 2183 {
2184 if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM)
2185 {
2186 /* If has fpr need to restore, the $sp on callee saved fpr
2187 position, so we need to consider gpr pading bytes and
2188 callee saved fpr size. */
2189 sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes
2190 + cfun->machine->callee_saved_fpr_regs_size;
2191 operands[1] = GEN_INT (sp_adjust);
2192 }
2193 else
2194 {
2195 operands[1] = GEN_INT (0);
2196 }
2197 }
706 2198
707 /* Create assembly code pattern. */ 2199 /* Create assembly code pattern. */
708 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); 2200 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
709 } 2201 }
710 else 2202 else
753 /* We use output_asm_insn() to output assembly code by ourself. */ 2245 /* We use output_asm_insn() to output assembly code by ourself. */
754 output_asm_insn (pattern, operands); 2246 output_asm_insn (pattern, operands);
755 return ""; 2247 return "";
756 } 2248 }
757 2249
758 /* Function to generate PC relative jump table. 2250 /* Function to output return operation. */
759 Refer to nds32.md for more details.
760
761 The following is the sample for the case that diff value
762 can be presented in '.short' size.
763
764 addi $r1, $r1, -(case_lower_bound)
765 slti $ta, $r1, (case_number)
766 beqz $ta, .L_skip_label
767
768 la $ta, .L35 ! get jump table address
769 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
770 addi $ta, $r1, $ta
771 jr5 $ta
772
773 ! jump table entry
774 L35:
775 .short .L25-.L35
776 .short .L26-.L35
777 .short .L27-.L35
778 .short .L28-.L35
779 .short .L29-.L35
780 .short .L30-.L35
781 .short .L31-.L35
782 .short .L32-.L35
783 .short .L33-.L35
784 .short .L34-.L35 */
785 const char * 2251 const char *
786 nds32_output_casesi_pc_relative (rtx *operands) 2252 nds32_output_return (void)
787 { 2253 {
788 machine_mode mode; 2254 /* A string pattern for output_asm_insn(). */
789 rtx diff_vec; 2255 char pattern[100];
790 2256 /* The operands array which will be used in output_asm_insn(). */
791 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1]))); 2257 rtx operands[2];
792 2258 /* For stack v3pop:
793 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); 2259 operands[0]: Re
794 2260 operands[1]: imm8u */
795 /* Step C: "t <-- operands[1]". */ 2261 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
796 output_asm_insn ("la\t$ta, %l1", operands); 2262 int sp_adjust;
797 2263
798 /* Get the mode of each element in the difference vector. */ 2264 /* Set operands[0]. */
799 mode = GET_MODE (diff_vec); 2265 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
800 2266
801 /* Step D: "z <-- (mem (plus (operands[0] << m) t))", 2267 /* Check if we can generate 'pop25 Re,imm8u',
802 where m is 0, 1, or 2 to load address-diff value from table. */ 2268 otherwise, generate 'pop25 Re,0'.
803 switch (mode) 2269 We have to consider alloca issue as well.
804 { 2270 If the function does call alloca(), the stack pointer is not fixed.
805 case E_QImode: 2271 In that case, we cannot use 'pop25 Re,imm8u' directly.
806 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands); 2272 We have to caculate stack pointer from frame pointer
807 break; 2273 and then use 'pop25 Re,0'. */
808 case E_HImode: 2274 sp_adjust = cfun->machine->local_size
809 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands); 2275 + cfun->machine->out_args_size
810 break; 2276 + cfun->machine->callee_saved_area_gpr_padding_bytes
811 case E_SImode: 2277 + cfun->machine->callee_saved_fpr_regs_size;
812 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); 2278 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
813 break; 2279 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
2280 && !cfun->calls_alloca)
2281 operands[1] = GEN_INT (sp_adjust);
2282 else
2283 operands[1] = GEN_INT (0);
2284
2285 /* Create assembly code pattern. */
2286 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
2287 /* We use output_asm_insn() to output assembly code by ourself. */
2288 output_asm_insn (pattern, operands);
2289 return "";
2290 }
2291
2292
2293 /* output a float load instruction */
2294 const char *
2295 nds32_output_float_load (rtx *operands)
2296 {
2297 char buff[100];
2298 const char *pattern;
2299 rtx addr, addr_op0, addr_op1;
2300 int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8;
2301 addr = XEXP (operands[1], 0);
2302 switch (GET_CODE (addr))
2303 {
2304 case REG:
2305 pattern = "fl%ci\t%%0, %%1";
2306 break;
2307
2308 case PLUS:
2309 addr_op0 = XEXP (addr, 0);
2310 addr_op1 = XEXP (addr, 1);
2311
2312 if (REG_P (addr_op0) && REG_P (addr_op1))
2313 pattern = "fl%c\t%%0, %%1";
2314 else if (REG_P (addr_op0) && CONST_INT_P (addr_op1))
2315 pattern = "fl%ci\t%%0, %%1";
2316 else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1)
2317 && REG_P (XEXP (addr_op0, 0))
2318 && CONST_INT_P (XEXP (addr_op0, 1)))
2319 pattern = "fl%c\t%%0, %%1";
2320 else
2321 gcc_unreachable ();
2322 break;
2323
2324 case POST_MODIFY:
2325 addr_op0 = XEXP (addr, 0);
2326 addr_op1 = XEXP (addr, 1);
2327
2328 if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2329 && REG_P (XEXP (addr_op1, 1)))
2330 pattern = "fl%c.bi\t%%0, %%1";
2331 else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2332 && CONST_INT_P (XEXP (addr_op1, 1)))
2333 pattern = "fl%ci.bi\t%%0, %%1";
2334 else
2335 gcc_unreachable ();
2336 break;
2337
2338 case POST_INC:
2339 if (REG_P (XEXP (addr, 0)))
2340 {
2341 if (dp)
2342 pattern = "fl%ci.bi\t%%0, %%1, 8";
2343 else
2344 pattern = "fl%ci.bi\t%%0, %%1, 4";
2345 }
2346 else
2347 gcc_unreachable ();
2348 break;
2349
2350 case POST_DEC:
2351 if (REG_P (XEXP (addr, 0)))
2352 {
2353 if (dp)
2354 pattern = "fl%ci.bi\t%%0, %%1, -8";
2355 else
2356 pattern = "fl%ci.bi\t%%0, %%1, -4";
2357 }
2358 else
2359 gcc_unreachable ();
2360 break;
2361
814 default: 2362 default:
815 gcc_unreachable (); 2363 gcc_unreachable ();
816 } 2364 }
817 2365
818 /* Step E: "t <-- z + t". 2366 sprintf (buff, pattern, dp ? 'd' : 's');
819 Add table label_ref with address-diff value to 2367 output_asm_insn (buff, operands);
820 obtain target case address. */ 2368 return "";
821 output_asm_insn ("add\t$ta, %2, $ta", operands); 2369 }
822 2370
823 /* Step F: jump to target with register t. */ 2371 /* output a float store instruction */
824 if (TARGET_16_BIT) 2372 const char *
825 return "jr5\t$ta"; 2373 nds32_output_float_store (rtx *operands)
2374 {
2375 char buff[100];
2376 const char *pattern;
2377 rtx addr, addr_op0, addr_op1;
2378 int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8;
2379 addr = XEXP (operands[0], 0);
2380 switch (GET_CODE (addr))
2381 {
2382 case REG:
2383 pattern = "fs%ci\t%%1, %%0";
2384 break;
2385
2386 case PLUS:
2387 addr_op0 = XEXP (addr, 0);
2388 addr_op1 = XEXP (addr, 1);
2389
2390 if (REG_P (addr_op0) && REG_P (addr_op1))
2391 pattern = "fs%c\t%%1, %%0";
2392 else if (REG_P (addr_op0) && CONST_INT_P (addr_op1))
2393 pattern = "fs%ci\t%%1, %%0";
2394 else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1)
2395 && REG_P (XEXP (addr_op0, 0))
2396 && CONST_INT_P (XEXP (addr_op0, 1)))
2397 pattern = "fs%c\t%%1, %%0";
2398 else
2399 gcc_unreachable ();
2400 break;
2401
2402 case POST_MODIFY:
2403 addr_op0 = XEXP (addr, 0);
2404 addr_op1 = XEXP (addr, 1);
2405
2406 if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2407 && REG_P (XEXP (addr_op1, 1)))
2408 pattern = "fs%c.bi\t%%1, %%0";
2409 else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2410 && CONST_INT_P (XEXP (addr_op1, 1)))
2411 pattern = "fs%ci.bi\t%%1, %%0";
2412 else
2413 gcc_unreachable ();
2414 break;
2415
2416 case POST_INC:
2417 if (REG_P (XEXP (addr, 0)))
2418 {
2419 if (dp)
2420 pattern = "fs%ci.bi\t%%1, %%0, 8";
2421 else
2422 pattern = "fs%ci.bi\t%%1, %%0, 4";
2423 }
2424 else
2425 gcc_unreachable ();
2426 break;
2427
2428 case POST_DEC:
2429 if (REG_P (XEXP (addr, 0)))
2430 {
2431 if (dp)
2432 pattern = "fs%ci.bi\t%%1, %%0, -8";
2433 else
2434 pattern = "fs%ci.bi\t%%1, %%0, -4";
2435 }
2436 else
2437 gcc_unreachable ();
2438 break;
2439
2440 default:
2441 gcc_unreachable ();
2442 }
2443
2444 sprintf (buff, pattern, dp ? 'd' : 's');
2445 output_asm_insn (buff, operands);
2446 return "";
2447 }
2448
2449 const char *
2450 nds32_output_smw_single_word (rtx *operands)
2451 {
2452 char buff[100];
2453 unsigned regno;
2454 int enable4;
2455 bool update_base_p;
2456 rtx base_addr = operands[0];
2457 rtx base_reg;
2458 rtx otherops[2];
2459
2460 if (REG_P (XEXP (base_addr, 0)))
2461 {
2462 update_base_p = false;
2463 base_reg = XEXP (base_addr, 0);
2464 }
826 else 2465 else
827 return "jr\t$ta"; 2466 {
828 } 2467 update_base_p = true;
829 2468 base_reg = XEXP (XEXP (base_addr, 0), 0);
830 /* Function to generate normal jump table. */ 2469 }
2470
2471 const char *update_base = update_base_p ? "m" : "";
2472
2473 regno = REGNO (operands[1]);
2474
2475 otherops[0] = base_reg;
2476 otherops[1] = operands[1];
2477
2478 if (regno >= 28)
2479 {
2480 enable4 = nds32_regno_to_enable4 (regno);
2481 sprintf (buff, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base, enable4);
2482 }
2483 else
2484 {
2485 sprintf (buff, "smw.bi%s\t%%1, [%%0], %%1", update_base);
2486 }
2487 output_asm_insn (buff, otherops);
2488 return "";
2489 }
2490
2491 /* ------------------------------------------------------------------------ */
831 const char * 2492 const char *
832 nds32_output_casesi (rtx *operands) 2493 nds32_output_smw_double_word (rtx *operands)
833 { 2494 {
834 /* Step C: "t <-- operands[1]". */ 2495 char buff[100];
835 output_asm_insn ("la\t$ta, %l1", operands); 2496 unsigned regno;
836 2497 int enable4;
837 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */ 2498 bool update_base_p;
838 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); 2499 rtx base_addr = operands[0];
839 2500 rtx base_reg;
840 /* No need to perform Step E, which is only used for 2501 rtx otherops[3];
841 pc relative jump table. */ 2502
842 2503 if (REG_P (XEXP (base_addr, 0)))
843 /* Step F: jump to target with register z. */ 2504 {
844 if (TARGET_16_BIT) 2505 update_base_p = false;
845 return "jr5\t%2"; 2506 base_reg = XEXP (base_addr, 0);
2507 }
846 else 2508 else
847 return "jr\t%2"; 2509 {
2510 update_base_p = true;
2511 base_reg = XEXP (XEXP (base_addr, 0), 0);
2512 }
2513
2514 const char *update_base = update_base_p ? "m" : "";
2515
2516 regno = REGNO (operands[1]);
2517
2518 otherops[0] = base_reg;
2519 otherops[1] = operands[1];
2520 otherops[2] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);;
2521
2522 if (regno >= 28)
2523 {
2524 enable4 = nds32_regno_to_enable4 (regno)
2525 | nds32_regno_to_enable4 (regno + 1);
2526 sprintf (buff, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base, enable4);
2527 }
2528 else if (regno == 27)
2529 {
2530 enable4 = nds32_regno_to_enable4 (regno + 1);
2531 sprintf (buff, "smw.bi%s\t%%1, [%%0], %%1, %x", update_base, enable4);
2532 }
2533 else
2534 {
2535 sprintf (buff, "smw.bi%s\t%%1, [%%0], %%2", update_base);
2536 }
2537 output_asm_insn (buff, otherops);
2538 return "";
2539 }
2540
2541 const char *
2542 nds32_output_lmw_single_word (rtx *operands)
2543 {
2544 char buff[100];
2545 unsigned regno;
2546 bool update_base_p;
2547 int enable4;
2548 rtx base_addr = operands[1];
2549 rtx base_reg;
2550 rtx otherops[2];
2551
2552 if (REG_P (XEXP (base_addr, 0)))
2553 {
2554 update_base_p = false;
2555 base_reg = XEXP (base_addr, 0);
2556 }
2557 else
2558 {
2559 update_base_p = true;
2560 base_reg = XEXP (XEXP (base_addr, 0), 0);
2561 }
2562
2563 const char *update_base = update_base_p ? "m" : "";
2564
2565 regno = REGNO (operands[0]);
2566
2567 otherops[0] = operands[0];
2568 otherops[1] = base_reg;
2569
2570 if (regno >= 28)
2571 {
2572 enable4 = nds32_regno_to_enable4 (regno);
2573 sprintf (buff, "lmw.bi%s\t$sp, [%%1], $sp, %x", update_base, enable4);
2574 }
2575 else
2576 {
2577 sprintf (buff, "lmw.bi%s\t%%0, [%%1], %%0", update_base);
2578 }
2579 output_asm_insn (buff, otherops);
2580 return "";
2581 }
2582
2583 void
2584 nds32_expand_unaligned_load (rtx *operands, enum machine_mode mode)
2585 {
2586 /* Initial memory offset. */
2587 int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0;
2588 int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1;
2589 /* Initial register shift byte. */
2590 int shift = 0;
2591 /* The first load byte instruction is not the same. */
2592 int width = GET_MODE_SIZE (mode) - 1;
2593 rtx mem[2];
2594 rtx reg[2];
2595 rtx sub_reg;
2596 rtx temp_reg, temp_sub_reg;
2597 int num_reg;
2598
2599 /* Generating a series of load byte instructions.
2600 The first load byte instructions and other
2601 load byte instructions are not the same. like:
2602 First:
2603 lbi reg0, [mem]
2604 zeh reg0, reg0
2605 Second:
2606 lbi temp_reg, [mem + offset]
2607 sll temp_reg, (8 * shift)
2608 ior reg0, temp_reg
2609
2610 lbi temp_reg, [mem + (offset + 1)]
2611 sll temp_reg, (8 * (shift + 1))
2612 ior reg0, temp_reg */
2613
2614 temp_reg = gen_reg_rtx (SImode);
2615 temp_sub_reg = gen_lowpart (QImode, temp_reg);
2616
2617 if (mode == DImode)
2618 {
2619 /* Load doubleword, we need two registers to access. */
2620 reg[0] = nds32_di_low_part_subreg (operands[0]);
2621 reg[1] = nds32_di_high_part_subreg (operands[0]);
2622 /* A register only store 4 byte. */
2623 width = GET_MODE_SIZE (SImode) - 1;
2624 }
2625 else
2626 {
2627 if (VECTOR_MODE_P (mode))
2628 reg[0] = gen_reg_rtx (SImode);
2629 else
2630 reg[0] = operands[0];
2631 }
2632
2633 for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--)
2634 {
2635 sub_reg = gen_lowpart (QImode, reg[0]);
2636 mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[1], offset));
2637
2638 /* Generating the first part instructions.
2639 lbi reg0, [mem]
2640 zeh reg0, reg0 */
2641 emit_move_insn (sub_reg, mem[0]);
2642 emit_insn (gen_zero_extendqisi2 (reg[0], sub_reg));
2643
2644 while (width > 0)
2645 {
2646 offset = offset + offset_adj;
2647 shift++;
2648 width--;
2649
2650 mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode,
2651 operands[1],
2652 offset));
2653 /* Generating the second part instructions.
2654 lbi temp_reg, [mem + offset]
2655 sll temp_reg, (8 * shift)
2656 ior reg0, temp_reg */
2657 emit_move_insn (temp_sub_reg, mem[1]);
2658 emit_insn (gen_ashlsi3 (temp_reg, temp_reg,
2659 GEN_INT (shift * 8)));
2660 emit_insn (gen_iorsi3 (reg[0], reg[0], temp_reg));
2661 }
2662
2663 if (mode == DImode)
2664 {
2665 /* Using the second register to load memory information. */
2666 reg[0] = reg[1];
2667 shift = 0;
2668 width = GET_MODE_SIZE (SImode) - 1;
2669 offset = offset + offset_adj;
2670 }
2671 }
2672 if (VECTOR_MODE_P (mode))
2673 convert_move (operands[0], reg[0], false);
2674 }
2675
2676 void
2677 nds32_expand_unaligned_store (rtx *operands, enum machine_mode mode)
2678 {
2679 /* Initial memory offset. */
2680 int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0;
2681 int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1;
2682 /* Initial register shift byte. */
2683 int shift = 0;
2684 /* The first load byte instruction is not the same. */
2685 int width = GET_MODE_SIZE (mode) - 1;
2686 rtx mem[2];
2687 rtx reg[2];
2688 rtx sub_reg;
2689 rtx temp_reg, temp_sub_reg;
2690 int num_reg;
2691
2692 /* Generating a series of store byte instructions.
2693 The first store byte instructions and other
2694 load byte instructions are not the same. like:
2695 First:
2696 sbi reg0, [mem + 0]
2697 Second:
2698 srli temp_reg, reg0, (8 * shift)
2699 sbi temp_reg, [mem + offset] */
2700
2701 temp_reg = gen_reg_rtx (SImode);
2702 temp_sub_reg = gen_lowpart (QImode, temp_reg);
2703
2704 if (mode == DImode)
2705 {
2706 /* Load doubleword, we need two registers to access. */
2707 reg[0] = nds32_di_low_part_subreg (operands[1]);
2708 reg[1] = nds32_di_high_part_subreg (operands[1]);
2709 /* A register only store 4 byte. */
2710 width = GET_MODE_SIZE (SImode) - 1;
2711 }
2712 else
2713 {
2714 if (VECTOR_MODE_P (mode))
2715 {
2716 reg[0] = gen_reg_rtx (SImode);
2717 convert_move (reg[0], operands[1], false);
2718 }
2719 else
2720 reg[0] = operands[1];
2721 }
2722
2723 for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--)
2724 {
2725 sub_reg = gen_lowpart (QImode, reg[0]);
2726 mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[0], offset));
2727
2728 /* Generating the first part instructions.
2729 sbi reg0, [mem + 0] */
2730 emit_move_insn (mem[0], sub_reg);
2731
2732 while (width > 0)
2733 {
2734 offset = offset + offset_adj;
2735 shift++;
2736 width--;
2737
2738 mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode,
2739 operands[0],
2740 offset));
2741 /* Generating the second part instructions.
2742 srli temp_reg, reg0, (8 * shift)
2743 sbi temp_reg, [mem + offset] */
2744 emit_insn (gen_lshrsi3 (temp_reg, reg[0],
2745 GEN_INT (shift * 8)));
2746 emit_move_insn (mem[1], temp_sub_reg);
2747 }
2748
2749 if (mode == DImode)
2750 {
2751 /* Using the second register to load memory information. */
2752 reg[0] = reg[1];
2753 shift = 0;
2754 width = GET_MODE_SIZE (SImode) - 1;
2755 offset = offset + offset_adj;
2756 }
2757 }
2758 }
2759
2760 /* Using multiple load/store instruction to output doubleword instruction. */
2761 const char *
2762 nds32_output_double (rtx *operands, bool load_p)
2763 {
2764 char pattern[100];
2765 int reg = load_p ? 0 : 1;
2766 int mem = load_p ? 1 : 0;
2767 rtx otherops[3];
2768 rtx addr = XEXP (operands[mem], 0);
2769
2770 otherops[0] = gen_rtx_REG (SImode, REGNO (operands[reg]));
2771 otherops[1] = gen_rtx_REG (SImode, REGNO (operands[reg]) + 1);
2772
2773 if (GET_CODE (addr) == POST_INC)
2774 {
2775 /* (mem (post_inc (reg))) */
2776 otherops[2] = XEXP (addr, 0);
2777 snprintf (pattern, sizeof (pattern),
2778 "%cmw.bim\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's');
2779 }
2780 else
2781 {
2782 /* (mem (reg)) */
2783 otherops[2] = addr;
2784 snprintf (pattern, sizeof (pattern),
2785 "%cmw.bi\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's');
2786
2787 }
2788
2789 output_asm_insn (pattern, otherops);
2790 return "";
2791 }
2792
2793 const char *
2794 nds32_output_cbranchsi4_equality_zero (rtx_insn *insn, rtx *operands)
2795 {
2796 enum rtx_code code;
2797 bool long_jump_p = false;
2798
2799 code = GET_CODE (operands[0]);
2800
2801 /* This zero-comparison conditional branch has two forms:
2802 32-bit instruction => beqz/bnez imm16s << 1
2803 16-bit instruction => beqzs8/bnezs8/beqz38/bnez38 imm8s << 1
2804
2805 For 32-bit case,
2806 we assume it is always reachable. (but check range -65500 ~ 65500)
2807
2808 For 16-bit case,
2809 it must satisfy { 255 >= (label - pc) >= -256 } condition.
2810 However, since the $pc for nds32 is at the beginning of the instruction,
2811 we should leave some length space for current insn.
2812 So we use range -250 ~ 250. */
2813
2814 switch (get_attr_length (insn))
2815 {
2816 case 8:
2817 long_jump_p = true;
2818 /* fall through */
2819 case 2:
2820 if (which_alternative == 0)
2821 {
2822 /* constraint: t */
2823 /* b<cond>zs8 .L0
2824 or
2825 b<inverse_cond>zs8 .LCB0
2826 j .L0
2827 .LCB0:
2828 */
2829 output_cond_branch_compare_zero (code, "s8", long_jump_p,
2830 operands, true);
2831 return "";
2832 }
2833 else if (which_alternative == 1)
2834 {
2835 /* constraint: l */
2836 /* b<cond>z38 $r0, .L0
2837 or
2838 b<inverse_cond>z38 $r0, .LCB0
2839 j .L0
2840 .LCB0:
2841 */
2842 output_cond_branch_compare_zero (code, "38", long_jump_p,
2843 operands, false);
2844 return "";
2845 }
2846 else
2847 {
2848 /* constraint: r */
2849 /* For which_alternative==2, it should not be here. */
2850 gcc_unreachable ();
2851 }
2852 case 10:
2853 /* including constraints: t, l, and r */
2854 long_jump_p = true;
2855 /* fall through */
2856 case 4:
2857 /* including constraints: t, l, and r */
2858 output_cond_branch_compare_zero (code, "", long_jump_p, operands, false);
2859 return "";
2860
2861 default:
2862 gcc_unreachable ();
2863 }
2864 }
2865
2866 const char *
2867 nds32_output_cbranchsi4_equality_reg (rtx_insn *insn, rtx *operands)
2868 {
2869 enum rtx_code code;
2870 bool long_jump_p, r5_p;
2871 int insn_length;
2872
2873 insn_length = get_attr_length (insn);
2874
2875 long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false;
2876 r5_p = (insn_length == 2 || insn_length == 8) ? true : false;
2877
2878 code = GET_CODE (operands[0]);
2879
2880 /* This register-comparison conditional branch has one form:
2881 32-bit instruction => beq/bne imm14s << 1
2882
2883 For 32-bit case,
2884 we assume it is always reachable. (but check range -16350 ~ 16350). */
2885
2886 switch (code)
2887 {
2888 case EQ:
2889 case NE:
2890 output_cond_branch (code, "", r5_p, long_jump_p, operands);
2891 return "";
2892
2893 default:
2894 gcc_unreachable ();
2895 }
2896 }
2897
2898 const char *
2899 nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *insn,
2900 rtx *operands)
2901 {
2902 enum rtx_code code;
2903 bool long_jump_p, r5_p;
2904 int insn_length;
2905
2906 insn_length = get_attr_length (insn);
2907
2908 long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false;
2909 r5_p = (insn_length == 2 || insn_length == 8) ? true : false;
2910
2911 code = GET_CODE (operands[0]);
2912
2913 /* This register-comparison conditional branch has one form:
2914 32-bit instruction => beq/bne imm14s << 1
2915 32-bit instruction => beqc/bnec imm8s << 1
2916
2917 For 32-bit case, we assume it is always reachable.
2918 (but check range -16350 ~ 16350 and -250 ~ 250). */
2919
2920 switch (code)
2921 {
2922 case EQ:
2923 case NE:
2924 if (which_alternative == 2)
2925 {
2926 /* r, Is11 */
2927 /* b<cond>c */
2928 output_cond_branch (code, "c", r5_p, long_jump_p, operands);
2929 }
2930 else
2931 {
2932 /* r, r */
2933 /* v, r */
2934 output_cond_branch (code, "", r5_p, long_jump_p, operands);
2935 }
2936 return "";
2937 default:
2938 gcc_unreachable ();
2939 }
2940 }
2941
2942 const char *
2943 nds32_output_cbranchsi4_greater_less_zero (rtx_insn *insn, rtx *operands)
2944 {
2945 enum rtx_code code;
2946 bool long_jump_p;
2947 int insn_length;
2948
2949 insn_length = get_attr_length (insn);
2950
2951 gcc_assert (insn_length == 4 || insn_length == 10);
2952
2953 long_jump_p = (insn_length == 10) ? true : false;
2954
2955 code = GET_CODE (operands[0]);
2956
2957 /* This zero-greater-less-comparison conditional branch has one form:
2958 32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1
2959
2960 For 32-bit case, we assume it is always reachable.
2961 (but check range -65500 ~ 65500). */
2962
2963 switch (code)
2964 {
2965 case GT:
2966 case GE:
2967 case LT:
2968 case LE:
2969 output_cond_branch_compare_zero (code, "", long_jump_p, operands, false);
2970 break;
2971 default:
2972 gcc_unreachable ();
2973 }
2974 return "";
2975 }
2976
2977 const char *
2978 nds32_output_unpkd8 (rtx output, rtx input,
2979 rtx high_idx_rtx, rtx low_idx_rtx,
2980 bool signed_p)
2981 {
2982 char pattern[100];
2983 rtx output_operands[2];
2984 HOST_WIDE_INT high_idx, low_idx;
2985 high_idx = INTVAL (high_idx_rtx);
2986 low_idx = INTVAL (low_idx_rtx);
2987
2988 gcc_assert (high_idx >= 0 && high_idx <= 3);
2989 gcc_assert (low_idx >= 0 && low_idx <= 3);
2990
2991 /* We only have 10, 20, 30 and 31. */
2992 if ((low_idx != 0 || high_idx == 0) &&
2993 !(low_idx == 1 && high_idx == 3))
2994 return "#";
2995
2996 char sign_char = signed_p ? 's' : 'z';
2997
2998 sprintf (pattern,
2999 "%cunpkd8" HOST_WIDE_INT_PRINT_DEC HOST_WIDE_INT_PRINT_DEC "\t%%0, %%1",
3000 sign_char, high_idx, low_idx);
3001 output_operands[0] = output;
3002 output_operands[1] = input;
3003 output_asm_insn (pattern, output_operands);
3004 return "";
3005 }
3006
3007 /* Return true if SYMBOL_REF X binds locally. */
3008
3009 static bool
3010 nds32_symbol_binds_local_p (const_rtx x)
3011 {
3012 return (SYMBOL_REF_DECL (x)
3013 ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
3014 : SYMBOL_REF_LOCAL_P (x));
3015 }
3016
3017 const char *
3018 nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call,
3019 const char *call, bool align_p)
3020 {
3021 char pattern[100];
3022 bool noreturn_p;
3023
3024 if (nds32_long_call_p (symbol))
3025 strcpy (pattern, long_call);
3026 else
3027 strcpy (pattern, call);
3028
3029 if (flag_pic && CONSTANT_P (symbol)
3030 && !nds32_symbol_binds_local_p (symbol))
3031 strcat (pattern, "@PLT");
3032
3033 if (align_p)
3034 strcat (pattern, "\n\t.align 2");
3035
3036 noreturn_p = find_reg_note (insn, REG_NORETURN, NULL_RTX) != NULL_RTX;
3037
3038 if (noreturn_p)
3039 {
3040 if (TARGET_16_BIT)
3041 strcat (pattern, "\n\tnop16");
3042 else
3043 strcat (pattern, "\n\tnop");
3044 }
3045
3046 output_asm_insn (pattern, operands);
3047 return "";
3048 }
3049
3050 bool
3051 nds32_need_split_sms_p (rtx in0_idx0, rtx in1_idx0,
3052 rtx in0_idx1, rtx in1_idx1)
3053 {
3054 /* smds or smdrs. */
3055 if (INTVAL (in0_idx0) == INTVAL (in1_idx0)
3056 && INTVAL (in0_idx1) == INTVAL (in1_idx1)
3057 && INTVAL (in0_idx0) != INTVAL (in0_idx1))
3058 return false;
3059
3060 /* smxds. */
3061 if (INTVAL (in0_idx0) != INTVAL (in0_idx1)
3062 && INTVAL (in1_idx0) != INTVAL (in1_idx1))
3063 return false;
3064
3065 return true;
3066 }
3067
3068 const char *
3069 nds32_output_sms (rtx in0_idx0, rtx in1_idx0,
3070 rtx in0_idx1, rtx in1_idx1)
3071 {
3072 if (nds32_need_split_sms_p (in0_idx0, in1_idx0,
3073 in0_idx1, in1_idx1))
3074 return "#";
3075 /* out = in0[in0_idx0] * in1[in1_idx0] - in0[in0_idx1] * in1[in1_idx1] */
3076
3077 /* smds or smdrs. */
3078 if (INTVAL (in0_idx0) == INTVAL (in1_idx0)
3079 && INTVAL (in0_idx1) == INTVAL (in1_idx1)
3080 && INTVAL (in0_idx0) != INTVAL (in0_idx1))
3081 {
3082 if (INTVAL (in0_idx0) == 0)
3083 {
3084 if (TARGET_BIG_ENDIAN)
3085 return "smds\t%0, %1, %2";
3086 else
3087 return "smdrs\t%0, %1, %2";
3088 }
3089 else
3090 {
3091 if (TARGET_BIG_ENDIAN)
3092 return "smdrs\t%0, %1, %2";
3093 else
3094 return "smds\t%0, %1, %2";
3095 }
3096 }
3097
3098 if (INTVAL (in0_idx0) != INTVAL (in0_idx1)
3099 && INTVAL (in1_idx0) != INTVAL (in1_idx1))
3100 {
3101 if (INTVAL (in0_idx0) == 1)
3102 {
3103 if (TARGET_BIG_ENDIAN)
3104 return "smxds\t%0, %2, %1";
3105 else
3106 return "smxds\t%0, %1, %2";
3107 }
3108 else
3109 {
3110 if (TARGET_BIG_ENDIAN)
3111 return "smxds\t%0, %1, %2";
3112 else
3113 return "smxds\t%0, %2, %1";
3114 }
3115 }
3116
3117 gcc_unreachable ();
3118 return "";
3119 }
3120
3121 void
3122 nds32_split_sms (rtx out, rtx in0, rtx in1,
3123 rtx in0_idx0, rtx in1_idx0,
3124 rtx in0_idx1, rtx in1_idx1)
3125 {
3126 rtx result0 = gen_reg_rtx (SImode);
3127 rtx result1 = gen_reg_rtx (SImode);
3128 emit_insn (gen_mulhisi3v (result0, in0, in1,
3129 in0_idx0, in1_idx0));
3130 emit_insn (gen_mulhisi3v (result1, in0, in1,
3131 in0_idx1, in1_idx1));
3132 emit_insn (gen_subsi3 (out, result0, result1));
3133 }
3134
3135 /* Spilt a doubleword instrucion to two single word instructions. */
3136 void
3137 nds32_spilt_doubleword (rtx *operands, bool load_p)
3138 {
3139 int reg = load_p ? 0 : 1;
3140 int mem = load_p ? 1 : 0;
3141 rtx reg_rtx = load_p ? operands[0] : operands[1];
3142 rtx mem_rtx = load_p ? operands[1] : operands[0];
3143 rtx low_part[2], high_part[2];
3144 rtx sub_mem = XEXP (mem_rtx, 0);
3145
3146 /* Generate low_part and high_part register pattern.
3147 i.e. register pattern like:
3148 (reg:DI) -> (subreg:SI (reg:DI))
3149 (subreg:SI (reg:DI)) */
3150 low_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 0);
3151 high_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 4);
3152
3153 /* Generate low_part and high_part memory pattern.
3154 Memory format is (post_dec) will generate:
3155 low_part: lwi.bi reg, [mem], 4
3156 high_part: lwi.bi reg, [mem], -12 */
3157 if (GET_CODE (sub_mem) == POST_DEC)
3158 {
3159 /* memory format is (post_dec (reg)),
3160 so that extract (reg) from the (post_dec (reg)) pattern. */
3161 sub_mem = XEXP (sub_mem, 0);
3162
3163 /* generate low_part and high_part memory format:
3164 low_part: (post_modify ((reg) (plus (reg) (const 4)))
3165 high_part: (post_modify ((reg) (plus (reg) (const -12))) */
3166 low_part[mem] = gen_frame_mem (SImode,
3167 gen_rtx_POST_MODIFY (Pmode, sub_mem,
3168 gen_rtx_PLUS (Pmode,
3169 sub_mem,
3170 GEN_INT (4))));
3171 high_part[mem] = gen_frame_mem (SImode,
3172 gen_rtx_POST_MODIFY (Pmode, sub_mem,
3173 gen_rtx_PLUS (Pmode,
3174 sub_mem,
3175 GEN_INT (-12))));
3176 }
3177 else if (GET_CODE (sub_mem) == POST_MODIFY)
3178 {
3179 /* Memory format is (post_modify (reg) (plus (reg) (const))),
3180 so that extract (reg) from the post_modify pattern. */
3181 rtx post_mem = XEXP (sub_mem, 0);
3182
3183 /* Extract (const) from the (post_modify (reg) (plus (reg) (const)))
3184 pattern. */
3185
3186 rtx plus_op = XEXP (sub_mem, 1);
3187 rtx post_val = XEXP (plus_op, 1);
3188
3189 /* Generate low_part and high_part memory format:
3190 low_part: (post_modify ((reg) (plus (reg) (const)))
3191 high_part: ((plus (reg) (const 4))) */
3192 low_part[mem] = gen_frame_mem (SImode,
3193 gen_rtx_POST_MODIFY (Pmode, post_mem,
3194 gen_rtx_PLUS (Pmode,
3195 post_mem,
3196 post_val)));
3197 high_part[mem] = gen_frame_mem (SImode, plus_constant (Pmode,
3198 post_mem,
3199 4));
3200 }
3201 else
3202 {
3203 /* memory format: (symbol_ref), (const), (reg + const_int). */
3204 low_part[mem] = adjust_address (mem_rtx, SImode, 0);
3205 high_part[mem] = adjust_address (mem_rtx, SImode, 4);
3206 }
3207
3208 /* After reload completed, we have dependent issue by low part register and
3209 higt part memory. i.e. we cannot split a sequence
3210 like:
3211 load $r0, [%r1]
3212 spilt to
3213 lw $r0, [%r0]
3214 lwi $r1, [%r0 + 4]
3215 swap position
3216 lwi $r1, [%r0 + 4]
3217 lw $r0, [%r0]
3218 For store instruction we don't have a problem.
3219
3220 When memory format is [post_modify], we need to emit high part instruction,
3221 before low part instruction.
3222 expamle:
3223 load $r0, [%r2], post_val
3224 spilt to
3225 load $r1, [%r2 + 4]
3226 load $r0, [$r2], post_val. */
3227 if ((load_p && reg_overlap_mentioned_p (low_part[0], high_part[1]))
3228 || GET_CODE (sub_mem) == POST_MODIFY)
3229 {
3230 operands[2] = high_part[0];
3231 operands[3] = high_part[1];
3232 operands[4] = low_part[0];
3233 operands[5] = low_part[1];
3234 }
3235 else
3236 {
3237 operands[2] = low_part[0];
3238 operands[3] = low_part[1];
3239 operands[4] = high_part[0];
3240 operands[5] = high_part[1];
3241 }
3242 }
3243
3244 void
3245 nds32_split_ashiftdi3 (rtx dst, rtx src, rtx shiftamount)
3246 {
3247 rtx src_high_part, src_low_part;
3248 rtx dst_high_part, dst_low_part;
3249
3250 dst_high_part = nds32_di_high_part_subreg (dst);
3251 dst_low_part = nds32_di_low_part_subreg (dst);
3252
3253 src_high_part = nds32_di_high_part_subreg (src);
3254 src_low_part = nds32_di_low_part_subreg (src);
3255
3256 /* We need to handle shift more than 32 bit!!!! */
3257 if (CONST_INT_P (shiftamount))
3258 {
3259 if (INTVAL (shiftamount) < 32)
3260 {
3261 rtx ext_start;
3262 ext_start = gen_int_mode(32 - INTVAL (shiftamount), SImode);
3263
3264 emit_insn (gen_wext (dst_high_part, src, ext_start));
3265 emit_insn (gen_ashlsi3 (dst_low_part, src_low_part, shiftamount));
3266 }
3267 else
3268 {
3269 rtx new_shift_amout = gen_int_mode(INTVAL (shiftamount) - 32, SImode);
3270
3271 emit_insn (gen_ashlsi3 (dst_high_part, src_low_part,
3272 new_shift_amout));
3273
3274 emit_move_insn (dst_low_part, GEN_INT (0));
3275 }
3276 }
3277 else
3278 {
3279 rtx dst_low_part_l32, dst_high_part_l32;
3280 rtx dst_low_part_g32, dst_high_part_g32;
3281 rtx new_shift_amout, select_reg;
3282 dst_low_part_l32 = gen_reg_rtx (SImode);
3283 dst_high_part_l32 = gen_reg_rtx (SImode);
3284 dst_low_part_g32 = gen_reg_rtx (SImode);
3285 dst_high_part_g32 = gen_reg_rtx (SImode);
3286 new_shift_amout = gen_reg_rtx (SImode);
3287 select_reg = gen_reg_rtx (SImode);
3288
3289 rtx ext_start;
3290 ext_start = gen_reg_rtx (SImode);
3291
3292 /*
3293 if (shiftamount < 32)
3294 dst_low_part = src_low_part << shiftamout
3295 dst_high_part = wext (src, 32 - shiftamount)
3296 # wext can't handle wext (src, 32) since it's only take rb[0:4]
3297 # for extract.
3298 dst_high_part = shiftamount == 0 ? src_high_part : dst_high_part
3299 else
3300 dst_low_part = 0
3301 dst_high_part = src_low_part << shiftamount & 0x1f
3302 */
3303
3304 emit_insn (gen_subsi3 (ext_start,
3305 gen_int_mode (32, SImode),
3306 shiftamount));
3307 emit_insn (gen_wext (dst_high_part_l32, src, ext_start));
3308
3309 /* Handle for shiftamout == 0. */
3310 emit_insn (gen_cmovzsi (dst_high_part_l32, shiftamount,
3311 src_high_part, dst_high_part_l32));
3312
3313 emit_insn (gen_ashlsi3 (dst_low_part_l32, src_low_part, shiftamount));
3314
3315 emit_move_insn (dst_low_part_g32, const0_rtx);
3316 emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f)));
3317 emit_insn (gen_ashlsi3 (dst_high_part_g32, src_low_part,
3318 new_shift_amout));
3319
3320 emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32)));
3321
3322 emit_insn (gen_cmovnsi (dst_low_part, select_reg,
3323 dst_low_part_l32, dst_low_part_g32));
3324 emit_insn (gen_cmovnsi (dst_high_part, select_reg,
3325 dst_high_part_l32, dst_high_part_g32));
3326 }
3327 }
3328
3329 void
3330 nds32_split_ashiftrtdi3 (rtx dst, rtx src, rtx shiftamount)
3331 {
3332 nds32_split_shiftrtdi3 (dst, src, shiftamount, false);
3333 }
3334
3335 void
3336 nds32_split_lshiftrtdi3 (rtx dst, rtx src, rtx shiftamount)
3337 {
3338 nds32_split_shiftrtdi3 (dst, src, shiftamount, true);
3339 }
3340
3341 void
3342 nds32_split_rotatertdi3 (rtx dst, rtx src, rtx shiftamount)
3343 {
3344 rtx dst_low_part_l32, dst_high_part_l32;
3345 rtx dst_low_part_g32, dst_high_part_g32;
3346 rtx select_reg, low5bit, low5bit_inv, minus32sa;
3347 rtx dst_low_part_g32_tmph;
3348 rtx dst_low_part_g32_tmpl;
3349 rtx dst_high_part_l32_tmph;
3350 rtx dst_high_part_l32_tmpl;
3351
3352 rtx src_low_part, src_high_part;
3353 rtx dst_high_part, dst_low_part;
3354
3355 shiftamount = force_reg (SImode, shiftamount);
3356
3357 emit_insn (gen_andsi3 (shiftamount,
3358 shiftamount,
3359 gen_int_mode (0x3f, SImode)));
3360
3361 dst_high_part = nds32_di_high_part_subreg (dst);
3362 dst_low_part = nds32_di_low_part_subreg (dst);
3363
3364 src_high_part = nds32_di_high_part_subreg (src);
3365 src_low_part = nds32_di_low_part_subreg (src);
3366
3367 dst_low_part_l32 = gen_reg_rtx (SImode);
3368 dst_high_part_l32 = gen_reg_rtx (SImode);
3369 dst_low_part_g32 = gen_reg_rtx (SImode);
3370 dst_high_part_g32 = gen_reg_rtx (SImode);
3371 low5bit = gen_reg_rtx (SImode);
3372 low5bit_inv = gen_reg_rtx (SImode);
3373 minus32sa = gen_reg_rtx (SImode);
3374 select_reg = gen_reg_rtx (SImode);
3375
3376 dst_low_part_g32_tmph = gen_reg_rtx (SImode);
3377 dst_low_part_g32_tmpl = gen_reg_rtx (SImode);
3378
3379 dst_high_part_l32_tmph = gen_reg_rtx (SImode);
3380 dst_high_part_l32_tmpl = gen_reg_rtx (SImode);
3381
3382 emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32)));
3383
3384 /* if shiftamount < 32
3385 dst_low_part = wext(src, shiftamount)
3386 else
3387 dst_low_part = ((src_high_part >> (shiftamount & 0x1f))
3388 | (src_low_part << (32 - (shiftamount & 0x1f))))
3389 */
3390 emit_insn (gen_andsi3 (low5bit, shiftamount, gen_int_mode (0x1f, SImode)));
3391 emit_insn (gen_subsi3 (low5bit_inv, gen_int_mode (32, SImode), low5bit));
3392
3393 emit_insn (gen_wext (dst_low_part_l32, src, shiftamount));
3394
3395 emit_insn (gen_lshrsi3 (dst_low_part_g32_tmpl, src_high_part, low5bit));
3396 emit_insn (gen_ashlsi3 (dst_low_part_g32_tmph, src_low_part, low5bit_inv));
3397
3398 emit_insn (gen_iorsi3 (dst_low_part_g32,
3399 dst_low_part_g32_tmpl,
3400 dst_low_part_g32_tmph));
3401
3402 emit_insn (gen_cmovnsi (dst_low_part, select_reg,
3403 dst_low_part_l32, dst_low_part_g32));
3404
3405 /* if shiftamount < 32
3406 dst_high_part = ((src_high_part >> shiftamount)
3407 | (src_low_part << (32 - shiftamount)))
3408 dst_high_part = shiftamount == 0 ? src_high_part : dst_high_part
3409 else
3410 dst_high_part = wext(src, shiftamount & 0x1f)
3411 */
3412
3413 emit_insn (gen_subsi3 (minus32sa, gen_int_mode (32, SImode), shiftamount));
3414
3415 emit_insn (gen_lshrsi3 (dst_high_part_l32_tmpl, src_high_part, shiftamount));
3416 emit_insn (gen_ashlsi3 (dst_high_part_l32_tmph, src_low_part, minus32sa));
3417
3418 emit_insn (gen_iorsi3 (dst_high_part_l32,
3419 dst_high_part_l32_tmpl,
3420 dst_high_part_l32_tmph));
3421
3422 emit_insn (gen_cmovzsi (dst_high_part_l32, shiftamount,
3423 src_high_part, dst_high_part_l32));
3424
3425 emit_insn (gen_wext (dst_high_part_g32, src, low5bit));
3426
3427 emit_insn (gen_cmovnsi (dst_high_part, select_reg,
3428 dst_high_part_l32, dst_high_part_g32));
3429 }
3430
3431 /* Return true if OP contains a symbol reference. */
3432 bool
3433 symbolic_reference_mentioned_p (rtx op)
3434 {
3435 const char *fmt;
3436 int i;
3437
3438 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
3439 return true;
3440
3441 fmt = GET_RTX_FORMAT (GET_CODE (op));
3442 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
3443 {
3444 if (fmt[i] == 'E')
3445 {
3446 int j;
3447
3448 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
3449 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
3450 return true;
3451 }
3452
3453 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
3454 return true;
3455 }
3456
3457 return false;
3458 }
3459
3460 /* Expand PIC code for @GOTOFF and @GOT.
3461
3462 Example for @GOTOFF:
3463
3464 la $r0, symbol@GOTOFF
3465 -> sethi $ta, hi20(symbol@GOTOFF)
3466 ori $ta, $ta, lo12(symbol@GOTOFF)
3467 add $r0, $ta, $gp
3468
3469 Example for @GOT:
3470
3471 la $r0, symbol@GOT
3472 -> sethi $ta, hi20(symbol@GOT)
3473 ori $ta, $ta, lo12(symbol@GOT)
3474 lw $r0, [$ta + $gp]
3475 */
3476 rtx
3477 nds32_legitimize_pic_address (rtx x)
3478 {
3479 rtx addr = x;
3480 rtx reg = gen_reg_rtx (Pmode);
3481 rtx pat;
3482
3483 if (GET_CODE (x) == LABEL_REF
3484 || (GET_CODE (x) == SYMBOL_REF
3485 && (CONSTANT_POOL_ADDRESS_P (x)
3486 || SYMBOL_REF_LOCAL_P (x))))
3487 {
3488 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_GOTOFF);
3489 addr = gen_rtx_CONST (SImode, addr);
3490 emit_insn (gen_sethi (reg, addr));
3491 emit_insn (gen_lo_sum (reg, reg, addr));
3492 x = gen_rtx_PLUS (Pmode, reg, pic_offset_table_rtx);
3493 }
3494 else if (GET_CODE (x) == SYMBOL_REF)
3495 {
3496 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_GOT);
3497 addr = gen_rtx_CONST (SImode, addr);
3498 emit_insn (gen_sethi (reg, addr));
3499 emit_insn (gen_lo_sum (reg, reg, addr));
3500
3501 x = gen_const_mem (SImode, gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
3502 reg));
3503 }
3504 else if (GET_CODE (x) == CONST)
3505 {
3506 /* We don't split constant in expand_pic_move because GOTOFF can combine
3507 the addend with the symbol. */
3508 addr = XEXP (x, 0);
3509 gcc_assert (GET_CODE (addr) == PLUS);
3510
3511 rtx op0 = XEXP (addr, 0);
3512 rtx op1 = XEXP (addr, 1);
3513
3514 if ((GET_CODE (op0) == LABEL_REF
3515 || (GET_CODE (op0) == SYMBOL_REF
3516 && (CONSTANT_POOL_ADDRESS_P (op0)
3517 || SYMBOL_REF_LOCAL_P (op0))))
3518 && GET_CODE (op1) == CONST_INT)
3519 {
3520 pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), UNSPEC_GOTOFF);
3521 pat = gen_rtx_PLUS (Pmode, pat, op1);
3522 pat = gen_rtx_CONST (Pmode, pat);
3523 emit_insn (gen_sethi (reg, pat));
3524 emit_insn (gen_lo_sum (reg, reg, pat));
3525 x = gen_rtx_PLUS (Pmode, reg, pic_offset_table_rtx);
3526 }
3527 else if (GET_CODE (op0) == SYMBOL_REF
3528 && GET_CODE (op1) == CONST_INT)
3529 {
3530 /* This is a constant offset from a @GOT symbol reference. */
3531 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, op0), UNSPEC_GOT);
3532 addr = gen_rtx_CONST (SImode, addr);
3533 emit_insn (gen_sethi (reg, addr));
3534 emit_insn (gen_lo_sum (reg, reg, addr));
3535 addr = gen_const_mem (SImode, gen_rtx_PLUS (Pmode,
3536 pic_offset_table_rtx,
3537 reg));
3538 emit_move_insn (reg, addr);
3539 if (satisfies_constraint_Is15 (op1))
3540 x = gen_rtx_PLUS (Pmode, reg, op1);
3541 else
3542 {
3543 rtx tmp_reg = gen_reg_rtx (SImode);
3544 emit_insn (gen_movsi (tmp_reg, op1));
3545 x = gen_rtx_PLUS (Pmode, reg, tmp_reg);
3546 }
3547 }
3548 else
3549 {
3550 /* Don't handle this pattern. */
3551 debug_rtx (x);
3552 gcc_unreachable ();
3553 }
3554 }
3555 return x;
3556 }
3557
3558 void
3559 nds32_expand_pic_move (rtx *operands)
3560 {
3561 rtx src;
3562
3563 src = nds32_legitimize_pic_address (operands[1]);
3564 emit_move_insn (operands[0], src);
3565 }
3566
3567 /* Expand ICT symbol.
3568 Example for @ICT and ICT model=large:
3569
3570 la $r0, symbol@ICT
3571 -> sethi $rt, hi20(symbol@ICT)
3572 lwi $r0, [$rt + lo12(symbol@ICT)]
3573
3574 */
3575 rtx
3576 nds32_legitimize_ict_address (rtx x)
3577 {
3578 rtx symbol = x;
3579 rtx addr = x;
3580 rtx reg = gen_reg_rtx (Pmode);
3581 gcc_assert (GET_CODE (x) == SYMBOL_REF
3582 && nds32_indirect_call_referenced_p (x));
3583
3584 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, symbol), UNSPEC_ICT);
3585 addr = gen_rtx_CONST (SImode, addr);
3586 emit_insn (gen_sethi (reg, addr));
3587
3588 x = gen_const_mem (SImode, gen_rtx_LO_SUM (Pmode, reg, addr));
3589
3590 return x;
3591 }
3592
3593 void
3594 nds32_expand_ict_move (rtx *operands)
3595 {
3596 rtx src = operands[1];
3597
3598 src = nds32_legitimize_ict_address (src);
3599
3600 emit_move_insn (operands[0], src);
3601 }
3602
3603 /* Return true X is a indirect call symbol. */
3604 bool
3605 nds32_indirect_call_referenced_p (rtx x)
3606 {
3607 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_ICT)
3608 x = XVECEXP (x, 0, 0);
3609
3610 if (GET_CODE (x) == SYMBOL_REF)
3611 {
3612 tree decl = SYMBOL_REF_DECL (x);
3613
3614 return decl
3615 && (lookup_attribute("indirect_call",
3616 DECL_ATTRIBUTES(decl))
3617 != NULL);
3618 }
3619
3620 return false;
3621 }
3622
3623 /* Return true X is need use long call. */
3624 bool
3625 nds32_long_call_p (rtx symbol)
3626 {
3627 if (nds32_indirect_call_referenced_p (symbol))
3628 return TARGET_ICT_MODEL_LARGE;
3629 else
3630 return TARGET_CMODEL_LARGE;
3631 }
3632
3633 /* Return true if X contains a thread-local symbol. */
3634 bool
3635 nds32_tls_referenced_p (rtx x)
3636 {
3637 if (!targetm.have_tls)
3638 return false;
3639
3640 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
3641 x = XEXP (XEXP (x, 0), 0);
3642
3643 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
3644 return true;
3645
3646 return false;
3647 }
3648
3649 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
3650 this (thread-local) address. */
3651 rtx
3652 nds32_legitimize_tls_address (rtx x)
3653 {
3654 rtx tmp_reg;
3655 rtx tp_reg = gen_rtx_REG (Pmode, TP_REGNUM);
3656 rtx pat, insns, reg0;
3657
3658 if (GET_CODE (x) == SYMBOL_REF)
3659 switch (SYMBOL_REF_TLS_MODEL (x))
3660 {
3661 case TLS_MODEL_GLOBAL_DYNAMIC:
3662 case TLS_MODEL_LOCAL_DYNAMIC:
3663 /* Emit UNSPEC_TLS_DESC rather than expand rtl directly because spill
3664 may destroy the define-use chain anylysis to insert relax_hint. */
3665 if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_GLOBAL_DYNAMIC)
3666 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSGD);
3667 else
3668 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSLD);
3669
3670 pat = gen_rtx_CONST (SImode, pat);
3671 reg0 = gen_rtx_REG (Pmode, 0);
3672 /* If we can confirm all clobber reigsters, it doesn't have to use call
3673 instruction. */
3674 insns = emit_call_insn (gen_tls_desc (pat, GEN_INT (0)));
3675 use_reg (&CALL_INSN_FUNCTION_USAGE (insns), pic_offset_table_rtx);
3676 RTL_CONST_CALL_P (insns) = 1;
3677 tmp_reg = gen_reg_rtx (SImode);
3678 emit_move_insn (tmp_reg, reg0);
3679 x = tmp_reg;
3680 break;
3681
3682 case TLS_MODEL_INITIAL_EXEC:
3683 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSIE);
3684 tmp_reg = gen_reg_rtx (SImode);
3685 pat = gen_rtx_CONST (SImode, pat);
3686 emit_insn (gen_tls_ie (tmp_reg, pat, GEN_INT (0)));
3687 if (flag_pic)
3688 emit_use (pic_offset_table_rtx);
3689 x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg);
3690 break;
3691
3692 case TLS_MODEL_LOCAL_EXEC:
3693 /* Expand symbol_ref@TPOFF':
3694 sethi $ta, hi20(symbol_ref@TPOFF)
3695 ori $ta, $ta, lo12(symbol_ref@TPOFF)
3696 add $r0, $ta, $tp */
3697 tmp_reg = gen_reg_rtx (SImode);
3698 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSLE);
3699 pat = gen_rtx_CONST (SImode, pat);
3700 emit_insn (gen_sethi (tmp_reg, pat));
3701 emit_insn (gen_lo_sum (tmp_reg, tmp_reg, pat));
3702 x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg);
3703 break;
3704
3705 default:
3706 gcc_unreachable ();
3707 }
3708 else if (GET_CODE (x) == CONST)
3709 {
3710 rtx base, addend;
3711 split_const (x, &base, &addend);
3712
3713 if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC)
3714 {
3715 /* Expand symbol_ref@TPOFF':
3716 sethi $ta, hi20(symbol_ref@TPOFF + addend)
3717 ori $ta, $ta, lo12(symbol_ref@TPOFF + addend)
3718 add $r0, $ta, $tp */
3719 tmp_reg = gen_reg_rtx (SImode);
3720 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, base), UNSPEC_TLSLE);
3721 pat = gen_rtx_PLUS (SImode, pat, addend);
3722 pat = gen_rtx_CONST (SImode, pat);
3723 emit_insn (gen_sethi (tmp_reg, pat));
3724 emit_insn (gen_lo_sum (tmp_reg, tmp_reg, pat));
3725 x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg);
3726 }
3727 }
3728
3729 return x;
3730 }
3731
3732 void
3733 nds32_expand_tls_move (rtx *operands)
3734 {
3735 rtx src = operands[1];
3736 rtx base, addend;
3737
3738 if (CONSTANT_P (src))
3739 split_const (src, &base, &addend);
3740
3741 if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC)
3742 src = nds32_legitimize_tls_address (src);
3743 else
3744 {
3745 src = nds32_legitimize_tls_address (base);
3746 if (addend != const0_rtx)
3747 {
3748 src = gen_rtx_PLUS (SImode, src, addend);
3749 src = force_operand (src, operands[0]);
3750 }
3751 }
3752
3753 emit_move_insn (operands[0], src);
3754 }
3755
3756 void
3757 nds32_expand_constant (machine_mode mode, HOST_WIDE_INT val,
3758 rtx target, rtx source)
3759 {
3760 rtx temp = gen_reg_rtx (mode);
3761 int clear_sign_bit_copies = 0;
3762 int clear_zero_bit_copies = 0;
3763 unsigned HOST_WIDE_INT remainder = val & 0xffffffffUL;
3764
3765 /* Count number of leading zeros. */
3766 clear_sign_bit_copies = __builtin_clz (remainder);
3767 /* Count number of trailing zeros. */
3768 clear_zero_bit_copies = __builtin_ctz (remainder);
3769
3770 HOST_WIDE_INT sign_shift_mask = ((0xffffffffUL
3771 << (32 - clear_sign_bit_copies))
3772 & 0xffffffffUL);
3773 HOST_WIDE_INT zero_shift_mask = (1 << clear_zero_bit_copies) - 1;
3774
3775 if (clear_sign_bit_copies > 0 && clear_sign_bit_copies < 17
3776 && (remainder | sign_shift_mask) == 0xffffffffUL)
3777 {
3778 /* Transfer AND to two shifts, example:
3779 a = b & 0x7fffffff => (b << 1) >> 1 */
3780 rtx shift = GEN_INT (clear_sign_bit_copies);
3781
3782 emit_insn (gen_ashlsi3 (temp, source, shift));
3783 emit_insn (gen_lshrsi3 (target, temp, shift));
3784 }
3785 else if (clear_zero_bit_copies > 0 && clear_sign_bit_copies < 17
3786 && (remainder | zero_shift_mask) == 0xffffffffUL)
3787 {
3788 /* Transfer AND to two shifts, example:
3789 a = b & 0xfff00000 => (b >> 20) << 20 */
3790 rtx shift = GEN_INT (clear_zero_bit_copies);
3791
3792 emit_insn (gen_lshrsi3 (temp, source, shift));
3793 emit_insn (gen_ashlsi3 (target, temp, shift));
3794 }
3795 else
3796 {
3797 emit_move_insn (temp, GEN_INT (val));
3798 emit_move_insn (target, gen_rtx_fmt_ee (AND, mode, source, temp));
3799 }
3800 }
3801
3802 /* Auxiliary functions for lwm/smw. */
3803 bool
3804 nds32_valid_smw_lwm_base_p (rtx op)
3805 {
3806 rtx base_addr;
3807
3808 if (!MEM_P (op))
3809 return false;
3810
3811 base_addr = XEXP (op, 0);
3812
3813 if (REG_P (base_addr))
3814 return true;
3815 else
3816 {
3817 if (GET_CODE (base_addr) == POST_INC
3818 && REG_P (XEXP (base_addr, 0)))
3819 return true;
3820 }
3821
3822 return false;
3823 }
3824
3825 /* Auxiliary functions for manipulation DI mode. */
3826 rtx nds32_di_high_part_subreg(rtx reg)
3827 {
3828 unsigned high_part_offset = subreg_highpart_offset (SImode, DImode);
3829
3830 return simplify_gen_subreg (
3831 SImode, reg,
3832 DImode, high_part_offset);
3833 }
3834
3835 rtx nds32_di_low_part_subreg(rtx reg)
3836 {
3837 unsigned low_part_offset = subreg_lowpart_offset (SImode, DImode);
3838
3839 return simplify_gen_subreg (
3840 SImode, reg,
3841 DImode, low_part_offset);
848 } 3842 }
849 3843
850 /* ------------------------------------------------------------------------ */ 3844 /* ------------------------------------------------------------------------ */
3845
3846 /* Auxiliary function for output TLS patterns. */
3847
3848 const char *
3849 nds32_output_tls_desc (rtx *operands)
3850 {
3851 char pattern[1000];
3852
3853 if (TARGET_RELAX_HINT)
3854 snprintf (pattern, sizeof (pattern),
3855 ".relax_hint %%1\n\tsethi $r0, hi20(%%0)\n\t"
3856 ".relax_hint %%1\n\tori $r0, $r0, lo12(%%0)\n\t"
3857 ".relax_hint %%1\n\tlw $r15, [$r0 + $gp]\n\t"
3858 ".relax_hint %%1\n\tadd $r0, $r0, $gp\n\t"
3859 ".relax_hint %%1\n\tjral $r15");
3860 else
3861 snprintf (pattern, sizeof (pattern),
3862 "sethi $r0, hi20(%%0)\n\t"
3863 "ori $r0, $r0, lo12(%%0)\n\t"
3864 "lw $r15, [$r0 + $gp]\n\t"
3865 "add $r0, $r0, $gp\n\t"
3866 "jral $r15");
3867 output_asm_insn (pattern, operands);
3868 return "";
3869 }
3870
3871 const char *
3872 nds32_output_tls_ie (rtx *operands)
3873 {
3874 char pattern[1000];
3875
3876 if (flag_pic)
3877 {
3878 if (TARGET_RELAX_HINT)
3879 snprintf (pattern, sizeof (pattern),
3880 ".relax_hint %%2\n\tsethi %%0, hi20(%%1)\n\t"
3881 ".relax_hint %%2\n\tori %%0, %%0, lo12(%%1)\n\t"
3882 ".relax_hint %%2\n\tlw %%0, [%%0 + $gp]");
3883 else
3884 snprintf (pattern, sizeof (pattern),
3885 "sethi %%0, hi20(%%1)\n\t"
3886 "ori %%0, %%0, lo12(%%1)\n\t"
3887 "lw %%0, [%%0 + $gp]");
3888 }
3889 else
3890 {
3891 if (TARGET_RELAX_HINT)
3892 snprintf (pattern, sizeof (pattern),
3893 ".relax_hint %%2\n\tsethi %%0, hi20(%%1)\n\t"
3894 ".relax_hint %%2\n\tlwi %%0, [%%0 + lo12(%%1)]");
3895 else
3896 snprintf (pattern, sizeof (pattern),
3897 "sethi %%0, hi20(%%1)\n\t"
3898 "lwi %%0, [%%0 + lo12(%%1)]");
3899 }
3900 output_asm_insn (pattern, operands);
3901 return "";
3902 }