1 /* Auxiliary functions for output asm template or expand rtl
2 pattern of Andes NDS32 cpu for GNU compiler
3 Copyright (C) 2012-2018 Free Software Foundation, Inc.
4 Contributed by Andes Technology Corporation.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 /* ------------------------------------------------------------------------ */
23
24 #define IN_TARGET_CODE 1
25
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "backend.h"
30 #include "target.h"
31 #include "rtl.h"
32 #include "tree.h"
33 #include "memmodel.h"
34 #include "tm_p.h"
35 #include "optabs.h" /* For GEN_FCN. */
36 #include "recog.h"
37 #include "output.h"
38 #include "tm-constrs.h"
39 #include "expr.h"
40 #include "emit-rtl.h"
41 #include "explow.h"
42
43 /* ------------------------------------------------------------------------ */
44
45 static int
nds32_regno_to_enable4(unsigned regno)46 nds32_regno_to_enable4 (unsigned regno)
47 {
48 switch (regno)
49 {
50 case 28: /* $r28/fp */
51 return 0x8;
52 case 29: /* $r29/gp */
53 return 0x4;
54 case 30: /* $r30/lp */
55 return 0x2;
56 case 31: /* $r31/sp */
57 return 0x1;
58 default:
59 gcc_unreachable ();
60 }
61 }
62
63 /* A helper function to return character based on byte size. */
64 static char
nds32_byte_to_size(int byte)65 nds32_byte_to_size (int byte)
66 {
67 switch (byte)
68 {
69 case 4:
70 return 'w';
71 case 2:
72 return 'h';
73 case 1:
74 return 'b';
75 default:
76 /* Normally it should not be here. */
77 gcc_unreachable ();
78 }
79 }
80
81 static int
nds32_inverse_cond_code(int code)82 nds32_inverse_cond_code (int code)
83 {
84 switch (code)
85 {
86 case NE:
87 return EQ;
88 case EQ:
89 return NE;
90 case GT:
91 return LE;
92 case LE:
93 return GT;
94 case GE:
95 return LT;
96 case LT:
97 return GE;
98 default:
99 gcc_unreachable ();
100 }
101 }
102
103 static const char *
nds32_cond_code_str(int code)104 nds32_cond_code_str (int code)
105 {
106 switch (code)
107 {
108 case NE:
109 return "ne";
110 case EQ:
111 return "eq";
112 case GT:
113 return "gt";
114 case LE:
115 return "le";
116 case GE:
117 return "ge";
118 case LT:
119 return "lt";
120 default:
121 gcc_unreachable ();
122 }
123 }
124
125 static void
output_cond_branch(int code,const char * suffix,bool r5_p,bool long_jump_p,rtx * operands)126 output_cond_branch (int code, const char *suffix, bool r5_p,
127 bool long_jump_p, rtx *operands)
128 {
129 char pattern[256];
130 const char *cond_code;
131 bool align_p = NDS32_ALIGN_P ();
132 const char *align = align_p ? "\t.align\t2\n" : "";
133
134 if (r5_p && REGNO (operands[2]) == 5 && TARGET_16_BIT)
135 {
136 /* This is special case for beqs38 and bnes38,
137 second operand 2 can't be $r5 and it's almost meanless,
138 however it may occur after copy propgation. */
139 if (code == EQ)
140 {
141 /* $r5 == $r5 always taken! */
142 if (long_jump_p)
143 snprintf (pattern, sizeof (pattern),
144 "j\t%%3");
145 else
146 snprintf (pattern, sizeof (pattern),
147 "j8\t%%3");
148 }
149 else
150 /* Don't output anything since $r5 != $r5 never taken! */
151 pattern[0] = '\0';
152 }
153 else if (long_jump_p)
154 {
155 int inverse_code = nds32_inverse_cond_code (code);
156 cond_code = nds32_cond_code_str (inverse_code);
157
158 /* b<cond><suffix> $r0, $r1, .L0
159 =>
160 b<inverse_cond><suffix> $r0, $r1, .LCB0
161 j .L0
162 .LCB0:
163
164 or
165
166 b<cond><suffix> $r0, $r1, .L0
167 =>
168 b<inverse_cond><suffix> $r0, $r1, .LCB0
169 j .L0
170 .LCB0:
171 */
172 if (r5_p && TARGET_16_BIT)
173 {
174 snprintf (pattern, sizeof (pattern),
175 "b%ss38\t %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:",
176 cond_code, align);
177 }
178 else
179 {
180 snprintf (pattern, sizeof (pattern),
181 "b%s%s\t%%1, %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:",
182 cond_code, suffix, align);
183 }
184 }
185 else
186 {
187 cond_code = nds32_cond_code_str (code);
188 if (r5_p && TARGET_16_BIT)
189 {
190 /* b<cond>s38 $r1, .L0 */
191 snprintf (pattern, sizeof (pattern),
192 "b%ss38\t %%2, %%3", cond_code);
193 }
194 else
195 {
196 /* b<cond><suffix> $r0, $r1, .L0 */
197 snprintf (pattern, sizeof (pattern),
198 "b%s%s\t%%1, %%2, %%3", cond_code, suffix);
199 }
200 }
201
202 output_asm_insn (pattern, operands);
203 }
204
205 static void
output_cond_branch_compare_zero(int code,const char * suffix,bool long_jump_p,rtx * operands,bool ta_implied_p)206 output_cond_branch_compare_zero (int code, const char *suffix,
207 bool long_jump_p, rtx *operands,
208 bool ta_implied_p)
209 {
210 char pattern[256];
211 const char *cond_code;
212 bool align_p = NDS32_ALIGN_P ();
213 const char *align = align_p ? "\t.align\t2\n" : "";
214 if (long_jump_p)
215 {
216 int inverse_code = nds32_inverse_cond_code (code);
217 cond_code = nds32_cond_code_str (inverse_code);
218
219 if (ta_implied_p && TARGET_16_BIT)
220 {
221 /* b<cond>z<suffix> .L0
222 =>
223 b<inverse_cond>z<suffix> .LCB0
224 j .L0
225 .LCB0:
226 */
227 snprintf (pattern, sizeof (pattern),
228 "b%sz%s\t.LCB%%=\n\tj\t%%2\n%s.LCB%%=:",
229 cond_code, suffix, align);
230 }
231 else
232 {
233 /* b<cond>z<suffix> $r0, .L0
234 =>
235 b<inverse_cond>z<suffix> $r0, .LCB0
236 j .L0
237 .LCB0:
238 */
239 snprintf (pattern, sizeof (pattern),
240 "b%sz%s\t%%1, .LCB%%=\n\tj\t%%2\n%s.LCB%%=:",
241 cond_code, suffix, align);
242 }
243 }
244 else
245 {
246 cond_code = nds32_cond_code_str (code);
247 if (ta_implied_p && TARGET_16_BIT)
248 {
249 /* b<cond>z<suffix> .L0 */
250 snprintf (pattern, sizeof (pattern),
251 "b%sz%s\t%%2", cond_code, suffix);
252 }
253 else
254 {
255 /* b<cond>z<suffix> $r0, .L0 */
256 snprintf (pattern, sizeof (pattern),
257 "b%sz%s\t%%1, %%2", cond_code, suffix);
258 }
259 }
260
261 output_asm_insn (pattern, operands);
262 }
263
264 /* ------------------------------------------------------------------------ */
265
266 /* Auxiliary function for expand RTL pattern. */
267
268 enum nds32_expand_result_type
nds32_expand_cbranch(rtx * operands)269 nds32_expand_cbranch (rtx *operands)
270 {
271 rtx tmp_reg;
272 enum rtx_code code;
273
274 code = GET_CODE (operands[0]);
275
276 /* If operands[2] is (const_int 0),
277 we can use beqz,bnez,bgtz,bgez,bltz,or blez instructions.
278 So we have gcc generate original template rtx. */
279 if (GET_CODE (operands[2]) == CONST_INT)
280 if (INTVAL (operands[2]) == 0)
281 if ((code != GTU)
282 && (code != GEU)
283 && (code != LTU)
284 && (code != LEU))
285 return EXPAND_CREATE_TEMPLATE;
286
287 /* For other comparison, NDS32 ISA only has slt (Set-on-Less-Than)
288 behavior for the comparison, we might need to generate other
289 rtx patterns to achieve same semantic. */
290 switch (code)
291 {
292 case GT:
293 case GTU:
294 if (GET_CODE (operands[2]) == CONST_INT)
295 {
296 /* GT reg_A, const_int => !(LT reg_A, const_int + 1) */
297 if (optimize_size || optimize == 0)
298 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
299 else
300 tmp_reg = gen_reg_rtx (SImode);
301
302 /* We want to plus 1 into the integer value
303 of operands[2] to create 'slt' instruction.
304 This caculation is performed on the host machine,
305 which may be 64-bit integer.
306 So the meaning of caculation result may be
307 different from the 32-bit nds32 target.
308
309 For example:
310 0x7fffffff + 0x1 -> 0x80000000,
311 this value is POSITIVE on 64-bit machine,
312 but the expected value on 32-bit nds32 target
313 should be NEGATIVE value.
314
315 Hence, instead of using GEN_INT(), we use gen_int_mode() to
316 explicitly create SImode constant rtx. */
317 enum rtx_code cmp_code;
318
319 rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
320 if (satisfies_constraint_Is15 (plus1))
321 {
322 operands[2] = plus1;
323 cmp_code = EQ;
324 if (code == GT)
325 {
326 /* GT, use slts instruction */
327 emit_insn (
328 gen_slts_compare (tmp_reg, operands[1], operands[2]));
329 }
330 else
331 {
332 /* GTU, use slt instruction */
333 emit_insn (
334 gen_slt_compare (tmp_reg, operands[1], operands[2]));
335 }
336 }
337 else
338 {
339 cmp_code = NE;
340 if (code == GT)
341 {
342 /* GT, use slts instruction */
343 emit_insn (
344 gen_slts_compare (tmp_reg, operands[2], operands[1]));
345 }
346 else
347 {
348 /* GTU, use slt instruction */
349 emit_insn (
350 gen_slt_compare (tmp_reg, operands[2], operands[1]));
351 }
352 }
353
354 PUT_CODE (operands[0], cmp_code);
355 operands[1] = tmp_reg;
356 operands[2] = const0_rtx;
357 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
358 operands[2], operands[3]));
359
360 return EXPAND_DONE;
361 }
362 else
363 {
364 /* GT reg_A, reg_B => LT reg_B, reg_A */
365 if (optimize_size || optimize == 0)
366 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
367 else
368 tmp_reg = gen_reg_rtx (SImode);
369
370 if (code == GT)
371 {
372 /* GT, use slts instruction */
373 emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
374 }
375 else
376 {
377 /* GTU, use slt instruction */
378 emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
379 }
380
381 PUT_CODE (operands[0], NE);
382 operands[1] = tmp_reg;
383 operands[2] = const0_rtx;
384 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
385 operands[2], operands[3]));
386
387 return EXPAND_DONE;
388 }
389
390 case GE:
391 case GEU:
392 /* GE reg_A, reg_B => !(LT reg_A, reg_B) */
393 /* GE reg_A, const_int => !(LT reg_A, const_int) */
394 if (optimize_size || optimize == 0)
395 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
396 else
397 tmp_reg = gen_reg_rtx (SImode);
398
399 if (code == GE)
400 {
401 /* GE, use slts instruction */
402 emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
403 }
404 else
405 {
406 /* GEU, use slt instruction */
407 emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
408 }
409
410 PUT_CODE (operands[0], EQ);
411 operands[1] = tmp_reg;
412 operands[2] = const0_rtx;
413 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
414 operands[2], operands[3]));
415
416 return EXPAND_DONE;
417
418 case LT:
419 case LTU:
420 /* LT reg_A, reg_B => LT reg_A, reg_B */
421 /* LT reg_A, const_int => LT reg_A, const_int */
422 if (optimize_size || optimize == 0)
423 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
424 else
425 tmp_reg = gen_reg_rtx (SImode);
426
427 if (code == LT)
428 {
429 /* LT, use slts instruction */
430 emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
431 }
432 else
433 {
434 /* LTU, use slt instruction */
435 emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
436 }
437
438 PUT_CODE (operands[0], NE);
439 operands[1] = tmp_reg;
440 operands[2] = const0_rtx;
441 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
442 operands[2], operands[3]));
443
444 return EXPAND_DONE;
445
446 case LE:
447 case LEU:
448 if (GET_CODE (operands[2]) == CONST_INT)
449 {
450 /* LE reg_A, const_int => LT reg_A, const_int + 1 */
451 if (optimize_size || optimize == 0)
452 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
453 else
454 tmp_reg = gen_reg_rtx (SImode);
455
456 enum rtx_code cmp_code;
457 /* Note that (le:SI X INT_MAX) is not the same as (lt:SI X INT_MIN).
458 We better have an assert here in case GCC does not properly
459 optimize it away. The INT_MAX here is 0x7fffffff for target. */
460 rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
461 if (satisfies_constraint_Is15 (plus1))
462 {
463 operands[2] = plus1;
464 cmp_code = NE;
465 if (code == LE)
466 {
467 /* LE, use slts instruction */
468 emit_insn (
469 gen_slts_compare (tmp_reg, operands[1], operands[2]));
470 }
471 else
472 {
473 /* LEU, use slt instruction */
474 emit_insn (
475 gen_slt_compare (tmp_reg, operands[1], operands[2]));
476 }
477 }
478 else
479 {
480 cmp_code = EQ;
481 if (code == LE)
482 {
483 /* LE, use slts instruction */
484 emit_insn (
485 gen_slts_compare (tmp_reg, operands[2], operands[1]));
486 }
487 else
488 {
489 /* LEU, use slt instruction */
490 emit_insn (
491 gen_slt_compare (tmp_reg, operands[2], operands[1]));
492 }
493 }
494
495 PUT_CODE (operands[0], cmp_code);
496 operands[1] = tmp_reg;
497 operands[2] = const0_rtx;
498 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
499 operands[2], operands[3]));
500
501 return EXPAND_DONE;
502 }
503 else
504 {
505 /* LE reg_A, reg_B => !(LT reg_B, reg_A) */
506 if (optimize_size || optimize == 0)
507 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
508 else
509 tmp_reg = gen_reg_rtx (SImode);
510
511 if (code == LE)
512 {
513 /* LE, use slts instruction */
514 emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
515 }
516 else
517 {
518 /* LEU, use slt instruction */
519 emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
520 }
521
522 PUT_CODE (operands[0], EQ);
523 operands[1] = tmp_reg;
524 operands[2] = const0_rtx;
525 emit_insn (gen_cbranchsi4 (operands[0], operands[1],
526 operands[2], operands[3]));
527
528 return EXPAND_DONE;
529 }
530
531 case EQ:
532 case NE:
533 /* NDS32 ISA has various form for eq/ne behavior no matter
534 what kind of the operand is.
535 So just generate original template rtx. */
536
537 /* Put operands[2] into register if operands[2] is a large
538 const_int or ISAv2. */
539 if (GET_CODE (operands[2]) == CONST_INT
540 && (!satisfies_constraint_Is11 (operands[2])
541 || TARGET_ISA_V2))
542 operands[2] = force_reg (SImode, operands[2]);
543
544 return EXPAND_CREATE_TEMPLATE;
545
546 default:
547 return EXPAND_FAIL;
548 }
549 }
550
551 enum nds32_expand_result_type
nds32_expand_cstore(rtx * operands)552 nds32_expand_cstore (rtx *operands)
553 {
554 rtx tmp_reg;
555 enum rtx_code code;
556
557 code = GET_CODE (operands[1]);
558
559 switch (code)
560 {
561 case EQ:
562 case NE:
563 if (GET_CODE (operands[3]) == CONST_INT)
564 {
565 /* reg_R = (reg_A == const_int_B)
566 --> xori reg_C, reg_A, const_int_B
567 slti reg_R, reg_C, const_int_1
568 reg_R = (reg_A != const_int_B)
569 --> xori reg_C, reg_A, const_int_B
570 slti reg_R, const_int0, reg_C */
571 tmp_reg = gen_reg_rtx (SImode);
572
573 /* If the integer value is not in the range of imm15s,
574 we need to force register first because our addsi3 pattern
575 only accept nds32_rimm15s_operand predicate. */
576 rtx new_imm = gen_int_mode (-INTVAL (operands[3]), SImode);
577 if (satisfies_constraint_Is15 (new_imm))
578 emit_insn (gen_addsi3 (tmp_reg, operands[2], new_imm));
579 else
580 {
581 if (!(satisfies_constraint_Iu15 (operands[3])
582 || (TARGET_EXT_PERF
583 && satisfies_constraint_It15 (operands[3]))))
584 operands[3] = force_reg (SImode, operands[3]);
585 emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
586 }
587
588 if (code == EQ)
589 emit_insn (gen_slt_eq0 (operands[0], tmp_reg));
590 else
591 emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
592
593 return EXPAND_DONE;
594 }
595 else
596 {
597 /* reg_R = (reg_A == reg_B)
598 --> xor reg_C, reg_A, reg_B
599 slti reg_R, reg_C, const_int_1
600 reg_R = (reg_A != reg_B)
601 --> xor reg_C, reg_A, reg_B
602 slti reg_R, const_int0, reg_C */
603 tmp_reg = gen_reg_rtx (SImode);
604 emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
605 if (code == EQ)
606 emit_insn (gen_slt_eq0 (operands[0], tmp_reg));
607 else
608 emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
609
610 return EXPAND_DONE;
611 }
612 case GT:
613 case GTU:
614 /* reg_R = (reg_A > reg_B) --> slt reg_R, reg_B, reg_A */
615 /* reg_R = (reg_A > const_int_B) --> slt reg_R, const_int_B, reg_A */
616 if (code == GT)
617 {
618 /* GT, use slts instruction */
619 emit_insn (gen_slts_compare (operands[0], operands[3], operands[2]));
620 }
621 else
622 {
623 /* GTU, use slt instruction */
624 emit_insn (gen_slt_compare (operands[0], operands[3], operands[2]));
625 }
626
627 return EXPAND_DONE;
628
629 case GE:
630 case GEU:
631 if (GET_CODE (operands[3]) == CONST_INT)
632 {
633 /* reg_R = (reg_A >= const_int_B)
634 --> movi reg_C, const_int_B - 1
635 slt reg_R, reg_C, reg_A */
636 tmp_reg = gen_reg_rtx (SImode);
637
638 emit_insn (gen_movsi (tmp_reg,
639 gen_int_mode (INTVAL (operands[3]) - 1,
640 SImode)));
641 if (code == GE)
642 {
643 /* GE, use slts instruction */
644 emit_insn (gen_slts_compare (operands[0], tmp_reg, operands[2]));
645 }
646 else
647 {
648 /* GEU, use slt instruction */
649 emit_insn (gen_slt_compare (operands[0], tmp_reg, operands[2]));
650 }
651
652 return EXPAND_DONE;
653 }
654 else
655 {
656 /* reg_R = (reg_A >= reg_B)
657 --> slt reg_R, reg_A, reg_B
658 xori reg_R, reg_R, const_int_1 */
659 if (code == GE)
660 {
661 /* GE, use slts instruction */
662 emit_insn (gen_slts_compare (operands[0],
663 operands[2], operands[3]));
664 }
665 else
666 {
667 /* GEU, use slt instruction */
668 emit_insn (gen_slt_compare (operands[0],
669 operands[2], operands[3]));
670 }
671
672 /* perform 'not' behavior */
673 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
674
675 return EXPAND_DONE;
676 }
677
678 case LT:
679 case LTU:
680 /* reg_R = (reg_A < reg_B) --> slt reg_R, reg_A, reg_B */
681 /* reg_R = (reg_A < const_int_B) --> slt reg_R, reg_A, const_int_B */
682 if (code == LT)
683 {
684 /* LT, use slts instruction */
685 emit_insn (gen_slts_compare (operands[0], operands[2], operands[3]));
686 }
687 else
688 {
689 /* LTU, use slt instruction */
690 emit_insn (gen_slt_compare (operands[0], operands[2], operands[3]));
691 }
692
693 return EXPAND_DONE;
694
695 case LE:
696 case LEU:
697 if (GET_CODE (operands[3]) == CONST_INT)
698 {
699 /* reg_R = (reg_A <= const_int_B)
700 --> movi reg_C, const_int_B + 1
701 slt reg_R, reg_A, reg_C */
702 tmp_reg = gen_reg_rtx (SImode);
703
704 emit_insn (gen_movsi (tmp_reg,
705 gen_int_mode (INTVAL (operands[3]) + 1,
706 SImode)));
707 if (code == LE)
708 {
709 /* LE, use slts instruction */
710 emit_insn (gen_slts_compare (operands[0], operands[2], tmp_reg));
711 }
712 else
713 {
714 /* LEU, use slt instruction */
715 emit_insn (gen_slt_compare (operands[0], operands[2], tmp_reg));
716 }
717
718 return EXPAND_DONE;
719 }
720 else
721 {
722 /* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A
723 xori reg_R, reg_R, const_int_1 */
724 if (code == LE)
725 {
726 /* LE, use slts instruction */
727 emit_insn (gen_slts_compare (operands[0],
728 operands[3], operands[2]));
729 }
730 else
731 {
732 /* LEU, use slt instruction */
733 emit_insn (gen_slt_compare (operands[0],
734 operands[3], operands[2]));
735 }
736
737 /* perform 'not' behavior */
738 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
739
740 return EXPAND_DONE;
741 }
742
743
744 default:
745 gcc_unreachable ();
746 }
747 }
748
749 void
nds32_expand_float_cbranch(rtx * operands)750 nds32_expand_float_cbranch (rtx *operands)
751 {
752 enum rtx_code code = GET_CODE (operands[0]);
753 enum rtx_code new_code = code;
754 rtx cmp_op0 = operands[1];
755 rtx cmp_op1 = operands[2];
756 rtx tmp_reg;
757 rtx tmp;
758
759 int reverse = 0;
760
761 /* Main Goal: Use compare instruction + branch instruction.
762
763 For example:
764 GT, GE: swap condition and swap operands and generate
765 compare instruction(LT, LE) + branch not equal instruction.
766
767 UNORDERED, LT, LE, EQ: no need to change and generate
768 compare instruction(UNORDERED, LT, LE, EQ) + branch not equal instruction.
769
770 ORDERED, NE: reverse condition and generate
771 compare instruction(EQ) + branch equal instruction. */
772
773 switch (code)
774 {
775 case GT:
776 case GE:
777 tmp = cmp_op0;
778 cmp_op0 = cmp_op1;
779 cmp_op1 = tmp;
780 new_code = swap_condition (new_code);
781 break;
782 case UNORDERED:
783 case LT:
784 case LE:
785 case EQ:
786 break;
787 case ORDERED:
788 case NE:
789 new_code = reverse_condition (new_code);
790 reverse = 1;
791 break;
792 case UNGT:
793 case UNGE:
794 new_code = reverse_condition_maybe_unordered (new_code);
795 reverse = 1;
796 break;
797 case UNLT:
798 case UNLE:
799 new_code = reverse_condition_maybe_unordered (new_code);
800 tmp = cmp_op0;
801 cmp_op0 = cmp_op1;
802 cmp_op1 = tmp;
803 new_code = swap_condition (new_code);
804 reverse = 1;
805 break;
806 default:
807 return;
808 }
809
810 tmp_reg = gen_reg_rtx (SImode);
811 emit_insn (gen_rtx_SET (tmp_reg,
812 gen_rtx_fmt_ee (new_code, SImode,
813 cmp_op0, cmp_op1)));
814
815 PUT_CODE (operands[0], reverse ? EQ : NE);
816 emit_insn (gen_cbranchsi4 (operands[0], tmp_reg,
817 const0_rtx, operands[3]));
818 }
819
820 void
nds32_expand_float_cstore(rtx * operands)821 nds32_expand_float_cstore (rtx *operands)
822 {
823 enum rtx_code code = GET_CODE (operands[1]);
824 enum rtx_code new_code = code;
825 machine_mode mode = GET_MODE (operands[2]);
826
827 rtx cmp_op0 = operands[2];
828 rtx cmp_op1 = operands[3];
829 rtx tmp;
830
831 /* Main Goal: Use compare instruction to store value.
832
833 For example:
834 GT, GE: swap condition and swap operands.
835 reg_R = (reg_A > reg_B) --> fcmplt reg_R, reg_B, reg_A
836 reg_R = (reg_A >= reg_B) --> fcmple reg_R, reg_B, reg_A
837
838 LT, LE, EQ: no need to change, it is already LT, LE, EQ.
839 reg_R = (reg_A < reg_B) --> fcmplt reg_R, reg_A, reg_B
840 reg_R = (reg_A <= reg_B) --> fcmple reg_R, reg_A, reg_B
841 reg_R = (reg_A == reg_B) --> fcmpeq reg_R, reg_A, reg_B
842
843 ORDERED: reverse condition and using xor insturction to achieve 'ORDERED'.
844 reg_R = (reg_A != reg_B) --> fcmpun reg_R, reg_A, reg_B
845 xor reg_R, reg_R, const1_rtx
846
847 NE: reverse condition and using xor insturction to achieve 'NE'.
848 reg_R = (reg_A != reg_B) --> fcmpeq reg_R, reg_A, reg_B
849 xor reg_R, reg_R, const1_rtx */
850 switch (code)
851 {
852 case GT:
853 case GE:
854 tmp = cmp_op0;
855 cmp_op0 = cmp_op1;
856 cmp_op1 =tmp;
857 new_code = swap_condition (new_code);
858 break;
859 case UNORDERED:
860 case LT:
861 case LE:
862 case EQ:
863 break;
864 case ORDERED:
865 if (mode == SFmode)
866 emit_insn (gen_cmpsf_un (operands[0], cmp_op0, cmp_op1));
867 else
868 emit_insn (gen_cmpdf_un (operands[0], cmp_op0, cmp_op1));
869
870 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
871 return;
872 case NE:
873 if (mode == SFmode)
874 emit_insn (gen_cmpsf_eq (operands[0], cmp_op0, cmp_op1));
875 else
876 emit_insn (gen_cmpdf_eq (operands[0], cmp_op0, cmp_op1));
877
878 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
879 return;
880 default:
881 return;
882 }
883
884 emit_insn (gen_rtx_SET (operands[0],
885 gen_rtx_fmt_ee (new_code, SImode,
886 cmp_op0, cmp_op1)));
887 }
888
889 enum nds32_expand_result_type
nds32_expand_movcc(rtx * operands)890 nds32_expand_movcc (rtx *operands)
891 {
892 enum rtx_code code = GET_CODE (operands[1]);
893 enum rtx_code new_code = code;
894 machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0));
895 rtx cmp_op0 = XEXP (operands[1], 0);
896 rtx cmp_op1 = XEXP (operands[1], 1);
897 rtx tmp;
898
899 if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)
900 && XEXP (operands[1], 1) == const0_rtx)
901 {
902 /* If the operands[1] rtx is already (eq X 0) or (ne X 0),
903 we have gcc generate original template rtx. */
904 return EXPAND_CREATE_TEMPLATE;
905 }
906 else if ((TARGET_FPU_SINGLE && cmp0_mode == SFmode)
907 || (TARGET_FPU_DOUBLE && cmp0_mode == DFmode))
908 {
909 nds32_expand_float_movcc (operands);
910 }
911 else
912 {
913 /* Since there is only 'slt'(Set when Less Than) instruction for
914 comparison in Andes ISA, the major strategy we use here is to
915 convert conditional move into 'LT + EQ' or 'LT + NE' rtx combination.
916 We design constraints properly so that the reload phase will assist
917 to make one source operand to use same register as result operand.
918 Then we can use cmovz/cmovn to catch the other source operand
919 which has different register. */
920 int reverse = 0;
921
922 /* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part
923 Strategy : Reverse condition and swap comparison operands
924
925 For example:
926
927 a <= b ? P : Q (LE or LEU)
928 --> a > b ? Q : P (reverse condition)
929 --> b < a ? Q : P (swap comparison operands to achieve 'LT/LTU')
930
931 a >= b ? P : Q (GE or GEU)
932 --> a < b ? Q : P (reverse condition to achieve 'LT/LTU')
933
934 a < b ? P : Q (LT or LTU)
935 --> (NO NEED TO CHANGE, it is already 'LT/LTU')
936
937 a > b ? P : Q (GT or GTU)
938 --> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */
939 switch (code)
940 {
941 case GE: case GEU: case LE: case LEU:
942 new_code = reverse_condition (code);
943 reverse = 1;
944 break;
945 case EQ:
946 case NE:
947 /* no need to reverse condition */
948 break;
949 default:
950 return EXPAND_FAIL;
951 }
952
953 /* For '>' comparison operator, we swap operands
954 so that we can have 'LT/LTU' operator. */
955 if (new_code == GT || new_code == GTU)
956 {
957 tmp = cmp_op0;
958 cmp_op0 = cmp_op1;
959 cmp_op1 = tmp;
960
961 new_code = swap_condition (new_code);
962 }
963
964 /* Use a temporary register to store slt/slts result. */
965 tmp = gen_reg_rtx (SImode);
966
967 if (new_code == EQ || new_code == NE)
968 {
969 emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1));
970 /* tmp == 0 if cmp_op0 == cmp_op1. */
971 operands[1] = gen_rtx_fmt_ee (new_code, VOIDmode, tmp, const0_rtx);
972 }
973 else
974 {
975 /* This emit_insn will create corresponding 'slt/slts'
976 insturction. */
977 if (new_code == LT)
978 emit_insn (gen_slts_compare (tmp, cmp_op0, cmp_op1));
979 else if (new_code == LTU)
980 emit_insn (gen_slt_compare (tmp, cmp_op0, cmp_op1));
981 else
982 gcc_unreachable ();
983
984 /* Change comparison semantic into (eq X 0) or (ne X 0) behavior
985 so that cmovz or cmovn will be matched later.
986
987 For reverse condition cases, we want to create a semantic that:
988 (eq X 0) --> pick up "else" part
989 For normal cases, we want to create a semantic that:
990 (ne X 0) --> pick up "then" part
991
992 Later we will have cmovz/cmovn instruction pattern to
993 match corresponding behavior and output instruction. */
994 operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE,
995 VOIDmode, tmp, const0_rtx);
996 }
997 }
998 return EXPAND_CREATE_TEMPLATE;
999 }
1000
1001 void
nds32_expand_float_movcc(rtx * operands)1002 nds32_expand_float_movcc (rtx *operands)
1003 {
1004 if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)
1005 && GET_MODE (XEXP (operands[1], 0)) == SImode
1006 && XEXP (operands[1], 1) == const0_rtx)
1007 {
1008 /* If the operands[1] rtx is already (eq X 0) or (ne X 0),
1009 we have gcc generate original template rtx. */
1010 return;
1011 }
1012 else
1013 {
1014 enum rtx_code code = GET_CODE (operands[1]);
1015 enum rtx_code new_code = code;
1016 machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0));
1017 machine_mode cmp1_mode = GET_MODE (XEXP (operands[1], 1));
1018 rtx cmp_op0 = XEXP (operands[1], 0);
1019 rtx cmp_op1 = XEXP (operands[1], 1);
1020 rtx tmp;
1021
1022 /* Compare instruction Operations: (cmp_op0 condition cmp_op1) ? 1 : 0,
1023 when result is 1, and 'reverse' be set 1 for fcmovzs instructuin. */
1024 int reverse = 0;
1025
1026 /* Main Goal: Use cmpare instruction + conditional move instruction.
1027 Strategy : swap condition and swap comparison operands.
1028
1029 For example:
1030 a > b ? P : Q (GT)
1031 --> a < b ? Q : P (swap condition)
1032 --> b < a ? Q : P (swap comparison operands to achieve 'GT')
1033
1034 a >= b ? P : Q (GE)
1035 --> a <= b ? Q : P (swap condition)
1036 --> b <= a ? Q : P (swap comparison operands to achieve 'GE')
1037
1038 a < b ? P : Q (LT)
1039 --> (NO NEED TO CHANGE, it is already 'LT')
1040
1041 a >= b ? P : Q (LE)
1042 --> (NO NEED TO CHANGE, it is already 'LE')
1043
1044 a == b ? P : Q (EQ)
1045 --> (NO NEED TO CHANGE, it is already 'EQ') */
1046
1047 switch (code)
1048 {
1049 case GT:
1050 case GE:
1051 tmp = cmp_op0;
1052 cmp_op0 = cmp_op1;
1053 cmp_op1 =tmp;
1054 new_code = swap_condition (new_code);
1055 break;
1056 case UNORDERED:
1057 case LT:
1058 case LE:
1059 case EQ:
1060 break;
1061 case ORDERED:
1062 case NE:
1063 reverse = 1;
1064 new_code = reverse_condition (new_code);
1065 break;
1066 case UNGT:
1067 case UNGE:
1068 new_code = reverse_condition_maybe_unordered (new_code);
1069 reverse = 1;
1070 break;
1071 case UNLT:
1072 case UNLE:
1073 new_code = reverse_condition_maybe_unordered (new_code);
1074 tmp = cmp_op0;
1075 cmp_op0 = cmp_op1;
1076 cmp_op1 = tmp;
1077 new_code = swap_condition (new_code);
1078 reverse = 1;
1079 break;
1080 default:
1081 return;
1082 }
1083
1084 /* Use a temporary register to store fcmpxxs result. */
1085 tmp = gen_reg_rtx (SImode);
1086
1087 /* Create float compare instruction for SFmode and DFmode,
1088 other MODE using cstoresi create compare instruction. */
1089 if ((cmp0_mode == DFmode || cmp0_mode == SFmode)
1090 && (cmp1_mode == DFmode || cmp1_mode == SFmode))
1091 {
1092 /* This emit_insn create corresponding float compare instruction */
1093 emit_insn (gen_rtx_SET (tmp,
1094 gen_rtx_fmt_ee (new_code, SImode,
1095 cmp_op0, cmp_op1)));
1096 }
1097 else
1098 {
1099 /* This emit_insn using cstoresi create corresponding
1100 compare instruction */
1101 PUT_CODE (operands[1], new_code);
1102 emit_insn (gen_cstoresi4 (tmp, operands[1],
1103 cmp_op0, cmp_op1));
1104 }
1105 /* operands[1] crete corresponding condition move instruction
1106 for fcmovzs and fcmovns. */
1107 operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE,
1108 VOIDmode, tmp, const0_rtx);
1109 }
1110 }
1111
1112 void
nds32_emit_push_fpr_callee_saved(int base_offset)1113 nds32_emit_push_fpr_callee_saved (int base_offset)
1114 {
1115 rtx fpu_insn;
1116 rtx reg, mem;
1117 unsigned int regno = cfun->machine->callee_saved_first_fpr_regno;
1118 unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno;
1119
1120 while (regno <= last_fpr)
1121 {
1122 /* Handling two registers, using fsdi instruction. */
1123 reg = gen_rtx_REG (DFmode, regno);
1124 mem = gen_frame_mem (DFmode, plus_constant (Pmode,
1125 stack_pointer_rtx,
1126 base_offset));
1127 base_offset += 8;
1128 regno += 2;
1129 fpu_insn = emit_move_insn (mem, reg);
1130 RTX_FRAME_RELATED_P (fpu_insn) = 1;
1131 }
1132 }
1133
1134 void
nds32_emit_pop_fpr_callee_saved(int gpr_padding_size)1135 nds32_emit_pop_fpr_callee_saved (int gpr_padding_size)
1136 {
1137 rtx fpu_insn;
1138 rtx reg, mem, addr;
1139 rtx dwarf, adjust_sp_rtx;
1140 unsigned int regno = cfun->machine->callee_saved_first_fpr_regno;
1141 unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno;
1142 int padding = 0;
1143
1144 while (regno <= last_fpr)
1145 {
1146 /* Handling two registers, using fldi.bi instruction. */
1147 if ((regno + 1) >= last_fpr)
1148 padding = gpr_padding_size;
1149
1150 reg = gen_rtx_REG (DFmode, (regno));
1151 addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
1152 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1153 GEN_INT (8 + padding)));
1154 mem = gen_frame_mem (DFmode, addr);
1155 regno += 2;
1156 fpu_insn = emit_move_insn (reg, mem);
1157
1158 adjust_sp_rtx =
1159 gen_rtx_SET (stack_pointer_rtx,
1160 plus_constant (Pmode, stack_pointer_rtx,
1161 8 + padding));
1162
1163 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX);
1164 /* Tell gcc we adjust SP in this insn. */
1165 dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx),
1166 dwarf);
1167 RTX_FRAME_RELATED_P (fpu_insn) = 1;
1168 REG_NOTES (fpu_insn) = dwarf;
1169 }
1170 }
1171
1172 void
nds32_emit_v3pop_fpr_callee_saved(int base)1173 nds32_emit_v3pop_fpr_callee_saved (int base)
1174 {
1175 int fpu_base_addr = base;
1176 int regno;
1177 rtx fpu_insn;
1178 rtx reg, mem;
1179 rtx dwarf;
1180
1181 regno = cfun->machine->callee_saved_first_fpr_regno;
1182 while (regno <= cfun->machine->callee_saved_last_fpr_regno)
1183 {
1184 /* Handling two registers, using fldi instruction. */
1185 reg = gen_rtx_REG (DFmode, regno);
1186 mem = gen_frame_mem (DFmode, plus_constant (Pmode,
1187 stack_pointer_rtx,
1188 fpu_base_addr));
1189 fpu_base_addr += 8;
1190 regno += 2;
1191 fpu_insn = emit_move_insn (reg, mem);
1192 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX);
1193 RTX_FRAME_RELATED_P (fpu_insn) = 1;
1194 REG_NOTES (fpu_insn) = dwarf;
1195 }
1196 }
1197
1198 /* ------------------------------------------------------------------------ */
1199
1200 /* Function to return memory format. */
1201 enum nds32_16bit_address_type
nds32_mem_format(rtx op)1202 nds32_mem_format (rtx op)
1203 {
1204 machine_mode mode_test;
1205 int val;
1206 int regno;
1207
1208 if (!TARGET_16_BIT)
1209 return ADDRESS_NOT_16BIT_FORMAT;
1210
1211 mode_test = GET_MODE (op);
1212
1213 op = XEXP (op, 0);
1214
1215 /* 45 format. */
1216 if (GET_CODE (op) == REG
1217 && ((mode_test == SImode) || (mode_test == SFmode)))
1218 return ADDRESS_REG;
1219
1220 /* 333 format for QI/HImode. */
1221 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
1222 return ADDRESS_LO_REG_IMM3U;
1223
1224 /* post_inc 333 format. */
1225 if ((GET_CODE (op) == POST_INC)
1226 && ((mode_test == SImode) || (mode_test == SFmode)))
1227 {
1228 regno = REGNO(XEXP (op, 0));
1229
1230 if (regno < 8)
1231 return ADDRESS_POST_INC_LO_REG_IMM3U;
1232 }
1233
1234 /* post_inc 333 format. */
1235 if ((GET_CODE (op) == POST_MODIFY)
1236 && ((mode_test == SImode) || (mode_test == SFmode))
1237 && (REG_P (XEXP (XEXP (op, 1), 0)))
1238 && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
1239 {
1240 regno = REGNO (XEXP (XEXP (op, 1), 0));
1241 val = INTVAL (XEXP (XEXP (op, 1), 1));
1242 if (regno < 8 && val > 0 && val < 32)
1243 return ADDRESS_POST_MODIFY_LO_REG_IMM3U;
1244 }
1245
1246 if ((GET_CODE (op) == PLUS)
1247 && (GET_CODE (XEXP (op, 0)) == REG)
1248 && (GET_CODE (XEXP (op, 1)) == CONST_INT))
1249 {
1250 val = INTVAL (XEXP (op, 1));
1251
1252 regno = REGNO(XEXP (op, 0));
1253
1254 if (regno > 8
1255 && regno != SP_REGNUM
1256 && regno != FP_REGNUM)
1257 return ADDRESS_NOT_16BIT_FORMAT;
1258
1259 switch (mode_test)
1260 {
1261 case E_QImode:
1262 /* 333 format. */
1263 if (val >= 0 && val < 8 && regno < 8)
1264 return ADDRESS_LO_REG_IMM3U;
1265 break;
1266
1267 case E_HImode:
1268 /* 333 format. */
1269 if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
1270 return ADDRESS_LO_REG_IMM3U;
1271 break;
1272
1273 case E_SImode:
1274 case E_SFmode:
1275 case E_DFmode:
1276 /* r8 imply fe format. */
1277 if ((regno == 8) &&
1278 (val >= -128 && val <= -4 && (val % 4 == 0)))
1279 return ADDRESS_R8_IMM7U;
1280 /* fp imply 37 format. */
1281 if ((regno == FP_REGNUM) &&
1282 (val >= 0 && val < 512 && (val % 4 == 0)))
1283 return ADDRESS_FP_IMM7U;
1284 /* sp imply 37 format. */
1285 else if ((regno == SP_REGNUM) &&
1286 (val >= 0 && val < 512 && (val % 4 == 0)))
1287 return ADDRESS_SP_IMM7U;
1288 /* 333 format. */
1289 else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
1290 return ADDRESS_LO_REG_IMM3U;
1291 break;
1292
1293 default:
1294 break;
1295 }
1296 }
1297
1298 return ADDRESS_NOT_16BIT_FORMAT;
1299 }
1300
1301 /* Output 16-bit store. */
1302 const char *
nds32_output_16bit_store(rtx * operands,int byte)1303 nds32_output_16bit_store (rtx *operands, int byte)
1304 {
1305 char pattern[100];
1306 char size;
1307 rtx code = XEXP (operands[0], 0);
1308
1309 size = nds32_byte_to_size (byte);
1310
1311 switch (nds32_mem_format (operands[0]))
1312 {
1313 case ADDRESS_REG:
1314 operands[0] = code;
1315 output_asm_insn ("swi450\t%1, [%0]", operands);
1316 break;
1317 case ADDRESS_LO_REG_IMM3U:
1318 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
1319 output_asm_insn (pattern, operands);
1320 break;
1321 case ADDRESS_POST_INC_LO_REG_IMM3U:
1322 snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0, 4");
1323 output_asm_insn (pattern, operands);
1324 break;
1325 case ADDRESS_POST_MODIFY_LO_REG_IMM3U:
1326 snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0");
1327 output_asm_insn (pattern, operands);
1328 break;
1329 case ADDRESS_FP_IMM7U:
1330 output_asm_insn ("swi37\t%1, %0", operands);
1331 break;
1332 case ADDRESS_SP_IMM7U:
1333 /* Get immediate value and set back to operands[1]. */
1334 operands[0] = XEXP (code, 1);
1335 output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
1336 break;
1337 default:
1338 break;
1339 }
1340
1341 return "";
1342 }
1343
1344 /* Output 16-bit load. */
1345 const char *
nds32_output_16bit_load(rtx * operands,int byte)1346 nds32_output_16bit_load (rtx *operands, int byte)
1347 {
1348 char pattern[100];
1349 unsigned char size;
1350 rtx code = XEXP (operands[1], 0);
1351
1352 size = nds32_byte_to_size (byte);
1353
1354 switch (nds32_mem_format (operands[1]))
1355 {
1356 case ADDRESS_REG:
1357 operands[1] = code;
1358 output_asm_insn ("lwi450\t%0, [%1]", operands);
1359 break;
1360 case ADDRESS_LO_REG_IMM3U:
1361 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
1362 output_asm_insn (pattern, operands);
1363 break;
1364 case ADDRESS_POST_INC_LO_REG_IMM3U:
1365 snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1, 4");
1366 output_asm_insn (pattern, operands);
1367 break;
1368 case ADDRESS_POST_MODIFY_LO_REG_IMM3U:
1369 snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1");
1370 output_asm_insn (pattern, operands);
1371 break;
1372 case ADDRESS_R8_IMM7U:
1373 output_asm_insn ("lwi45.fe\t%0, %e1", operands);
1374 break;
1375 case ADDRESS_FP_IMM7U:
1376 output_asm_insn ("lwi37\t%0, %1", operands);
1377 break;
1378 case ADDRESS_SP_IMM7U:
1379 /* Get immediate value and set back to operands[0]. */
1380 operands[1] = XEXP (code, 1);
1381 output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
1382 break;
1383 default:
1384 break;
1385 }
1386
1387 return "";
1388 }
1389
1390 /* Output 32-bit store. */
1391 const char *
nds32_output_32bit_store(rtx * operands,int byte)1392 nds32_output_32bit_store (rtx *operands, int byte)
1393 {
1394 char pattern[100];
1395 unsigned char size;
1396 rtx code = XEXP (operands[0], 0);
1397
1398 size = nds32_byte_to_size (byte);
1399
1400 switch (GET_CODE (code))
1401 {
1402 case REG:
1403 /* (mem (reg X))
1404 => access location by using register,
1405 use "sbi / shi / swi" */
1406 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
1407 break;
1408
1409 case SYMBOL_REF:
1410 case CONST:
1411 /* (mem (symbol_ref X))
1412 (mem (const (...)))
1413 => access global variables,
1414 use "sbi.gp / shi.gp / swi.gp" */
1415 operands[0] = XEXP (operands[0], 0);
1416 snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
1417 break;
1418
1419 case POST_INC:
1420 /* (mem (post_inc reg))
1421 => access location by using register which will be post increment,
1422 use "sbi.bi / shi.bi / swi.bi" */
1423 snprintf (pattern, sizeof (pattern),
1424 "s%ci.bi\t%%1, %%0, %d", size, byte);
1425 break;
1426
1427 case POST_DEC:
1428 /* (mem (post_dec reg))
1429 => access location by using register which will be post decrement,
1430 use "sbi.bi / shi.bi / swi.bi" */
1431 snprintf (pattern, sizeof (pattern),
1432 "s%ci.bi\t%%1, %%0, -%d", size, byte);
1433 break;
1434
1435 case POST_MODIFY:
1436 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
1437 {
1438 case REG:
1439 case SUBREG:
1440 /* (mem (post_modify (reg) (plus (reg) (reg))))
1441 => access location by using register which will be
1442 post modified with reg,
1443 use "sb.bi/ sh.bi / sw.bi" */
1444 snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
1445 break;
1446 case CONST_INT:
1447 /* (mem (post_modify (reg) (plus (reg) (const_int))))
1448 => access location by using register which will be
1449 post modified with const_int,
1450 use "sbi.bi/ shi.bi / swi.bi" */
1451 snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
1452 break;
1453 default:
1454 abort ();
1455 }
1456 break;
1457
1458 case PLUS:
1459 switch (GET_CODE (XEXP (code, 1)))
1460 {
1461 case REG:
1462 case SUBREG:
1463 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
1464 => access location by adding two registers,
1465 use "sb / sh / sw" */
1466 snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
1467 break;
1468 case CONST_INT:
1469 /* (mem (plus reg const_int))
1470 => access location by adding one register with const_int,
1471 use "sbi / shi / swi" */
1472 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
1473 break;
1474 default:
1475 abort ();
1476 }
1477 break;
1478
1479 case LO_SUM:
1480 operands[2] = XEXP (code, 1);
1481 operands[0] = XEXP (code, 0);
1482 snprintf (pattern, sizeof (pattern),
1483 "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
1484 break;
1485
1486 default:
1487 abort ();
1488 }
1489
1490 output_asm_insn (pattern, operands);
1491 return "";
1492 }
1493
1494 /* Output 32-bit load. */
1495 const char *
nds32_output_32bit_load(rtx * operands,int byte)1496 nds32_output_32bit_load (rtx *operands, int byte)
1497 {
1498 char pattern[100];
1499 unsigned char size;
1500 rtx code;
1501
1502 code = XEXP (operands[1], 0);
1503
1504 size = nds32_byte_to_size (byte);
1505
1506 switch (GET_CODE (code))
1507 {
1508 case REG:
1509 /* (mem (reg X))
1510 => access location by using register,
1511 use "lbi / lhi / lwi" */
1512 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
1513 break;
1514
1515 case SYMBOL_REF:
1516 case CONST:
1517 /* (mem (symbol_ref X))
1518 (mem (const (...)))
1519 => access global variables,
1520 use "lbi.gp / lhi.gp / lwi.gp" */
1521 operands[1] = XEXP (operands[1], 0);
1522 snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
1523 break;
1524
1525 case POST_INC:
1526 /* (mem (post_inc reg))
1527 => access location by using register which will be post increment,
1528 use "lbi.bi / lhi.bi / lwi.bi" */
1529 snprintf (pattern, sizeof (pattern),
1530 "l%ci.bi\t%%0, %%1, %d", size, byte);
1531 break;
1532
1533 case POST_DEC:
1534 /* (mem (post_dec reg))
1535 => access location by using register which will be post decrement,
1536 use "lbi.bi / lhi.bi / lwi.bi" */
1537 snprintf (pattern, sizeof (pattern),
1538 "l%ci.bi\t%%0, %%1, -%d", size, byte);
1539 break;
1540
1541 case POST_MODIFY:
1542 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
1543 {
1544 case REG:
1545 case SUBREG:
1546 /* (mem (post_modify (reg) (plus (reg) (reg))))
1547 => access location by using register which will be
1548 post modified with reg,
1549 use "lb.bi/ lh.bi / lw.bi" */
1550 snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
1551 break;
1552 case CONST_INT:
1553 /* (mem (post_modify (reg) (plus (reg) (const_int))))
1554 => access location by using register which will be
1555 post modified with const_int,
1556 use "lbi.bi/ lhi.bi / lwi.bi" */
1557 snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
1558 break;
1559 default:
1560 abort ();
1561 }
1562 break;
1563
1564 case PLUS:
1565 switch (GET_CODE (XEXP (code, 1)))
1566 {
1567 case REG:
1568 case SUBREG:
1569 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
1570 use "lb / lh / lw" */
1571 snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
1572 break;
1573 case CONST_INT:
1574 /* (mem (plus reg const_int))
1575 => access location by adding one register with const_int,
1576 use "lbi / lhi / lwi" */
1577 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
1578 break;
1579 default:
1580 abort ();
1581 }
1582 break;
1583
1584 case LO_SUM:
1585 operands[2] = XEXP (code, 1);
1586 operands[1] = XEXP (code, 0);
1587 snprintf (pattern, sizeof (pattern),
1588 "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
1589 break;
1590
1591 default:
1592 abort ();
1593 }
1594
1595 output_asm_insn (pattern, operands);
1596 return "";
1597 }
1598
1599 /* Output 32-bit load with signed extension. */
1600 const char *
nds32_output_32bit_load_s(rtx * operands,int byte)1601 nds32_output_32bit_load_s (rtx *operands, int byte)
1602 {
1603 char pattern[100];
1604 unsigned char size;
1605 rtx code;
1606
1607 code = XEXP (operands[1], 0);
1608
1609 size = nds32_byte_to_size (byte);
1610
1611 switch (GET_CODE (code))
1612 {
1613 case REG:
1614 /* (mem (reg X))
1615 => access location by using register,
1616 use "lbsi / lhsi" */
1617 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
1618 break;
1619
1620 case SYMBOL_REF:
1621 case CONST:
1622 /* (mem (symbol_ref X))
1623 (mem (const (...)))
1624 => access global variables,
1625 use "lbsi.gp / lhsi.gp" */
1626 operands[1] = XEXP (operands[1], 0);
1627 snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
1628 break;
1629
1630 case POST_INC:
1631 /* (mem (post_inc reg))
1632 => access location by using register which will be post increment,
1633 use "lbsi.bi / lhsi.bi" */
1634 snprintf (pattern, sizeof (pattern),
1635 "l%csi.bi\t%%0, %%1, %d", size, byte);
1636 break;
1637
1638 case POST_DEC:
1639 /* (mem (post_dec reg))
1640 => access location by using register which will be post decrement,
1641 use "lbsi.bi / lhsi.bi" */
1642 snprintf (pattern, sizeof (pattern),
1643 "l%csi.bi\t%%0, %%1, -%d", size, byte);
1644 break;
1645
1646 case POST_MODIFY:
1647 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
1648 {
1649 case REG:
1650 case SUBREG:
1651 /* (mem (post_modify (reg) (plus (reg) (reg))))
1652 => access location by using register which will be
1653 post modified with reg,
1654 use "lbs.bi/ lhs.bi" */
1655 snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
1656 break;
1657 case CONST_INT:
1658 /* (mem (post_modify (reg) (plus (reg) (const_int))))
1659 => access location by using register which will be
1660 post modified with const_int,
1661 use "lbsi.bi/ lhsi.bi" */
1662 snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
1663 break;
1664 default:
1665 abort ();
1666 }
1667 break;
1668
1669 case PLUS:
1670 switch (GET_CODE (XEXP (code, 1)))
1671 {
1672 case REG:
1673 case SUBREG:
1674 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
1675 use "lbs / lhs" */
1676 snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
1677 break;
1678 case CONST_INT:
1679 /* (mem (plus reg const_int))
1680 => access location by adding one register with const_int,
1681 use "lbsi / lhsi" */
1682 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
1683 break;
1684 default:
1685 abort ();
1686 }
1687 break;
1688
1689 case LO_SUM:
1690 operands[2] = XEXP (code, 1);
1691 operands[1] = XEXP (code, 0);
1692 snprintf (pattern, sizeof (pattern),
1693 "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
1694 break;
1695
1696 default:
1697 abort ();
1698 }
1699
1700 output_asm_insn (pattern, operands);
1701 return "";
1702 }
1703
1704 /* Function to output stack push operation.
1705 We need to deal with normal stack push multiple or stack v3push. */
1706 const char *
nds32_output_stack_push(rtx par_rtx)1707 nds32_output_stack_push (rtx par_rtx)
1708 {
1709 /* A string pattern for output_asm_insn(). */
1710 char pattern[100];
1711 /* The operands array which will be used in output_asm_insn(). */
1712 rtx operands[3];
1713 /* Pick up varargs first regno and last regno for further use. */
1714 int rb_va_args = cfun->machine->va_args_first_regno;
1715 int re_va_args = cfun->machine->va_args_last_regno;
1716 int last_argument_regno = NDS32_FIRST_GPR_REGNUM
1717 + NDS32_MAX_GPR_REGS_FOR_ARGS
1718 - 1;
1719 /* Pick up first and last eh data regno for further use. */
1720 int rb_eh_data = cfun->machine->eh_return_data_first_regno;
1721 int re_eh_data = cfun->machine->eh_return_data_last_regno;
1722 int first_eh_data_regno = EH_RETURN_DATA_REGNO (0);
1723 /* Pick up callee-saved first regno and last regno for further use. */
1724 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
1725 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
1726
1727 /* First we need to check if we are pushing argument registers not used
1728 for the named arguments. If so, we have to create 'smw.adm' (push.s)
1729 instruction. */
1730 if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx))
1731 {
1732 /* Set operands[0] and operands[1]. */
1733 operands[0] = gen_rtx_REG (SImode, rb_va_args);
1734 operands[1] = gen_rtx_REG (SImode, re_va_args);
1735 /* Create assembly code pattern: "Rb, Re, { }". */
1736 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
1737 /* We use output_asm_insn() to output assembly code by ourself. */
1738 output_asm_insn (pattern, operands);
1739 return "";
1740 }
1741
1742 /* If last_argument_regno is not mentioned in par_rtx, we can confirm that
1743 we do not need to push argument registers for variadic function.
1744 But we still need to check if we need to push exception handling
1745 data registers. */
1746 if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx))
1747 {
1748 /* Set operands[0] and operands[1]. */
1749 operands[0] = gen_rtx_REG (SImode, rb_eh_data);
1750 operands[1] = gen_rtx_REG (SImode, re_eh_data);
1751 /* Create assembly code pattern: "Rb, Re, { }". */
1752 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
1753 /* We use output_asm_insn() to output assembly code by ourself. */
1754 output_asm_insn (pattern, operands);
1755 return "";
1756 }
1757
1758 /* If we step here, we are going to do v3push or multiple push operation. */
1759
1760 /* The v3push/v3pop instruction should only be applied on
1761 none-isr and none-variadic function. */
1762 if (TARGET_V3PUSH
1763 && !nds32_isr_function_p (current_function_decl)
1764 && (cfun->machine->va_args_size == 0))
1765 {
1766 /* For stack v3push:
1767 operands[0]: Re
1768 operands[1]: imm8u */
1769
1770 /* This variable is to check if 'push25 Re,imm8u' is available. */
1771 int sp_adjust;
1772
1773 /* Set operands[0]. */
1774 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
1775
1776 /* Check if we can generate 'push25 Re,imm8u',
1777 otherwise, generate 'push25 Re,0'. */
1778 sp_adjust = cfun->machine->local_size
1779 + cfun->machine->out_args_size
1780 + cfun->machine->callee_saved_area_gpr_padding_bytes
1781 + cfun->machine->callee_saved_fpr_regs_size;
1782 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
1783 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
1784 operands[1] = GEN_INT (sp_adjust);
1785 else
1786 {
1787 /* Allocate callee saved fpr space. */
1788 if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM)
1789 {
1790 sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes
1791 + cfun->machine->callee_saved_fpr_regs_size;
1792 operands[1] = GEN_INT (sp_adjust);
1793 }
1794 else
1795 {
1796 operands[1] = GEN_INT (0);
1797 }
1798 }
1799
1800 /* Create assembly code pattern. */
1801 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
1802 }
1803 else
1804 {
1805 /* For normal stack push multiple:
1806 operands[0]: Rb
1807 operands[1]: Re
1808 operands[2]: En4 */
1809
1810 /* This variable is used to check if we only need to generate En4 field.
1811 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
1812 int push_en4_only_p = 0;
1813
1814 /* Set operands[0] and operands[1]. */
1815 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
1816 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
1817
1818 /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */
1819 if (!cfun->machine->fp_size
1820 && !cfun->machine->gp_size
1821 && !cfun->machine->lp_size
1822 && REGNO (operands[0]) == SP_REGNUM
1823 && REGNO (operands[1]) == SP_REGNUM)
1824 {
1825 /* No need to generate instruction. */
1826 return "";
1827 }
1828 else
1829 {
1830 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
1831 if (REGNO (operands[0]) == SP_REGNUM
1832 && REGNO (operands[1]) == SP_REGNUM)
1833 push_en4_only_p = 1;
1834
1835 /* Create assembly code pattern.
1836 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
1837 snprintf (pattern, sizeof (pattern),
1838 "push.s\t%s{%s%s%s }",
1839 push_en4_only_p ? "" : "%0, %1, ",
1840 cfun->machine->fp_size ? " $fp" : "",
1841 cfun->machine->gp_size ? " $gp" : "",
1842 cfun->machine->lp_size ? " $lp" : "");
1843 }
1844 }
1845
1846 /* We use output_asm_insn() to output assembly code by ourself. */
1847 output_asm_insn (pattern, operands);
1848 return "";
1849 }
1850
1851 /* Function to output stack pop operation.
1852 We need to deal with normal stack pop multiple or stack v3pop. */
1853 const char *
nds32_output_stack_pop(rtx par_rtx ATTRIBUTE_UNUSED)1854 nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
1855 {
1856 /* A string pattern for output_asm_insn(). */
1857 char pattern[100];
1858 /* The operands array which will be used in output_asm_insn(). */
1859 rtx operands[3];
1860 /* Pick up first and last eh data regno for further use. */
1861 int rb_eh_data = cfun->machine->eh_return_data_first_regno;
1862 int re_eh_data = cfun->machine->eh_return_data_last_regno;
1863 int first_eh_data_regno = EH_RETURN_DATA_REGNO (0);
1864 /* Pick up callee-saved first regno and last regno for further use. */
1865 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
1866 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
1867
1868 /* We need to check if we need to push exception handling
1869 data registers. */
1870 if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx))
1871 {
1872 /* Set operands[0] and operands[1]. */
1873 operands[0] = gen_rtx_REG (SImode, rb_eh_data);
1874 operands[1] = gen_rtx_REG (SImode, re_eh_data);
1875 /* Create assembly code pattern: "Rb, Re, { }". */
1876 snprintf (pattern, sizeof (pattern), "pop.s\t%s", "%0, %1, { }");
1877 /* We use output_asm_insn() to output assembly code by ourself. */
1878 output_asm_insn (pattern, operands);
1879 return "";
1880 }
1881
1882 /* If we step here, we are going to do v3pop or multiple pop operation. */
1883
1884 /* The v3push/v3pop instruction should only be applied on
1885 none-isr and none-variadic function. */
1886 if (TARGET_V3PUSH
1887 && !nds32_isr_function_p (current_function_decl)
1888 && (cfun->machine->va_args_size == 0))
1889 {
1890 /* For stack v3pop:
1891 operands[0]: Re
1892 operands[1]: imm8u */
1893
1894 /* This variable is to check if 'pop25 Re,imm8u' is available. */
1895 int sp_adjust;
1896
1897 /* Set operands[0]. */
1898 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
1899
1900 /* Check if we can generate 'pop25 Re,imm8u',
1901 otherwise, generate 'pop25 Re,0'.
1902 We have to consider alloca issue as well.
1903 If the function does call alloca(), the stack pointer is not fixed.
1904 In that case, we cannot use 'pop25 Re,imm8u' directly.
1905 We have to caculate stack pointer from frame pointer
1906 and then use 'pop25 Re,0'. */
1907 sp_adjust = cfun->machine->local_size
1908 + cfun->machine->out_args_size
1909 + cfun->machine->callee_saved_area_gpr_padding_bytes
1910 + cfun->machine->callee_saved_fpr_regs_size;
1911 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
1912 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
1913 && !cfun->calls_alloca)
1914 operands[1] = GEN_INT (sp_adjust);
1915 else
1916 {
1917 if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM)
1918 {
1919 /* If has fpr need to restore, the $sp on callee saved fpr
1920 position, so we need to consider gpr pading bytes and
1921 callee saved fpr size. */
1922 sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes
1923 + cfun->machine->callee_saved_fpr_regs_size;
1924 operands[1] = GEN_INT (sp_adjust);
1925 }
1926 else
1927 {
1928 operands[1] = GEN_INT (0);
1929 }
1930 }
1931
1932 /* Create assembly code pattern. */
1933 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
1934 }
1935 else
1936 {
1937 /* For normal stack pop multiple:
1938 operands[0]: Rb
1939 operands[1]: Re
1940 operands[2]: En4 */
1941
1942 /* This variable is used to check if we only need to generate En4 field.
1943 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
1944 int pop_en4_only_p = 0;
1945
1946 /* Set operands[0] and operands[1]. */
1947 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
1948 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
1949
1950 /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */
1951 if (!cfun->machine->fp_size
1952 && !cfun->machine->gp_size
1953 && !cfun->machine->lp_size
1954 && REGNO (operands[0]) == SP_REGNUM
1955 && REGNO (operands[1]) == SP_REGNUM)
1956 {
1957 /* No need to generate instruction. */
1958 return "";
1959 }
1960 else
1961 {
1962 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
1963 if (REGNO (operands[0]) == SP_REGNUM
1964 && REGNO (operands[1]) == SP_REGNUM)
1965 pop_en4_only_p = 1;
1966
1967 /* Create assembly code pattern.
1968 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
1969 snprintf (pattern, sizeof (pattern),
1970 "pop.s\t%s{%s%s%s }",
1971 pop_en4_only_p ? "" : "%0, %1, ",
1972 cfun->machine->fp_size ? " $fp" : "",
1973 cfun->machine->gp_size ? " $gp" : "",
1974 cfun->machine->lp_size ? " $lp" : "");
1975 }
1976 }
1977
1978 /* We use output_asm_insn() to output assembly code by ourself. */
1979 output_asm_insn (pattern, operands);
1980 return "";
1981 }
1982
1983 /* Function to output return operation. */
1984 const char *
nds32_output_return(void)1985 nds32_output_return (void)
1986 {
1987 /* A string pattern for output_asm_insn(). */
1988 char pattern[100];
1989 /* The operands array which will be used in output_asm_insn(). */
1990 rtx operands[2];
1991 /* For stack v3pop:
1992 operands[0]: Re
1993 operands[1]: imm8u */
1994 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
1995 int sp_adjust;
1996
1997 /* Set operands[0]. */
1998 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
1999
2000 /* Check if we can generate 'pop25 Re,imm8u',
2001 otherwise, generate 'pop25 Re,0'.
2002 We have to consider alloca issue as well.
2003 If the function does call alloca(), the stack pointer is not fixed.
2004 In that case, we cannot use 'pop25 Re,imm8u' directly.
2005 We have to caculate stack pointer from frame pointer
2006 and then use 'pop25 Re,0'. */
2007 sp_adjust = cfun->machine->local_size
2008 + cfun->machine->out_args_size
2009 + cfun->machine->callee_saved_area_gpr_padding_bytes
2010 + cfun->machine->callee_saved_fpr_regs_size;
2011 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
2012 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
2013 && !cfun->calls_alloca)
2014 operands[1] = GEN_INT (sp_adjust);
2015 else
2016 operands[1] = GEN_INT (0);
2017
2018 /* Create assembly code pattern. */
2019 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
2020 /* We use output_asm_insn() to output assembly code by ourself. */
2021 output_asm_insn (pattern, operands);
2022 return "";
2023 }
2024
2025 /* Function to generate PC relative jump table.
2026 Refer to nds32.md for more details.
2027
2028 The following is the sample for the case that diff value
2029 can be presented in '.short' size.
2030
2031 addi $r1, $r1, -(case_lower_bound)
2032 slti $ta, $r1, (case_number)
2033 beqz $ta, .L_skip_label
2034
2035 la $ta, .L35 ! get jump table address
2036 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
2037 addi $ta, $r1, $ta
2038 jr5 $ta
2039
2040 ! jump table entry
2041 L35:
2042 .short .L25-.L35
2043 .short .L26-.L35
2044 .short .L27-.L35
2045 .short .L28-.L35
2046 .short .L29-.L35
2047 .short .L30-.L35
2048 .short .L31-.L35
2049 .short .L32-.L35
2050 .short .L33-.L35
2051 .short .L34-.L35 */
2052 const char *
nds32_output_casesi_pc_relative(rtx * operands)2053 nds32_output_casesi_pc_relative (rtx *operands)
2054 {
2055 machine_mode mode;
2056 rtx diff_vec;
2057
2058 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])));
2059
2060 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
2061
2062 /* Step C: "t <-- operands[1]". */
2063 output_asm_insn ("la\t$ta, %l1", operands);
2064
2065 /* Get the mode of each element in the difference vector. */
2066 mode = GET_MODE (diff_vec);
2067
2068 /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
2069 where m is 0, 1, or 2 to load address-diff value from table. */
2070 switch (mode)
2071 {
2072 case E_QImode:
2073 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
2074 break;
2075 case E_HImode:
2076 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
2077 break;
2078 case E_SImode:
2079 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
2080 break;
2081 default:
2082 gcc_unreachable ();
2083 }
2084
2085 /* Step E: "t <-- z + t".
2086 Add table label_ref with address-diff value to
2087 obtain target case address. */
2088 output_asm_insn ("add\t$ta, %2, $ta", operands);
2089
2090 /* Step F: jump to target with register t. */
2091 if (TARGET_16_BIT)
2092 return "jr5\t$ta";
2093 else
2094 return "jr\t$ta";
2095 }
2096
2097 /* output a float load instruction */
2098 const char *
nds32_output_float_load(rtx * operands)2099 nds32_output_float_load (rtx *operands)
2100 {
2101 char buff[100];
2102 const char *pattern;
2103 rtx addr, addr_op0, addr_op1;
2104 int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8;
2105 addr = XEXP (operands[1], 0);
2106 switch (GET_CODE (addr))
2107 {
2108 case REG:
2109 pattern = "fl%ci\t%%0, %%1";
2110 break;
2111
2112 case PLUS:
2113 addr_op0 = XEXP (addr, 0);
2114 addr_op1 = XEXP (addr, 1);
2115
2116 if (REG_P (addr_op0) && REG_P (addr_op1))
2117 pattern = "fl%c\t%%0, %%1";
2118 else if (REG_P (addr_op0) && CONST_INT_P (addr_op1))
2119 pattern = "fl%ci\t%%0, %%1";
2120 else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1)
2121 && REG_P (XEXP (addr_op0, 0))
2122 && CONST_INT_P (XEXP (addr_op0, 1)))
2123 pattern = "fl%c\t%%0, %%1";
2124 else
2125 gcc_unreachable ();
2126 break;
2127
2128 case POST_MODIFY:
2129 addr_op0 = XEXP (addr, 0);
2130 addr_op1 = XEXP (addr, 1);
2131
2132 if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2133 && REG_P (XEXP (addr_op1, 1)))
2134 pattern = "fl%c.bi\t%%0, %%1";
2135 else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2136 && CONST_INT_P (XEXP (addr_op1, 1)))
2137 pattern = "fl%ci.bi\t%%0, %%1";
2138 else
2139 gcc_unreachable ();
2140 break;
2141
2142 case POST_INC:
2143 if (REG_P (XEXP (addr, 0)))
2144 {
2145 if (dp)
2146 pattern = "fl%ci.bi\t%%0, %%1, 8";
2147 else
2148 pattern = "fl%ci.bi\t%%0, %%1, 4";
2149 }
2150 else
2151 gcc_unreachable ();
2152 break;
2153
2154 case POST_DEC:
2155 if (REG_P (XEXP (addr, 0)))
2156 {
2157 if (dp)
2158 pattern = "fl%ci.bi\t%%0, %%1, -8";
2159 else
2160 pattern = "fl%ci.bi\t%%0, %%1, -4";
2161 }
2162 else
2163 gcc_unreachable ();
2164 break;
2165
2166 default:
2167 gcc_unreachable ();
2168 }
2169
2170 sprintf (buff, pattern, dp ? 'd' : 's');
2171 output_asm_insn (buff, operands);
2172 return "";
2173 }
2174
2175 /* output a float store instruction */
2176 const char *
nds32_output_float_store(rtx * operands)2177 nds32_output_float_store (rtx *operands)
2178 {
2179 char buff[100];
2180 const char *pattern;
2181 rtx addr, addr_op0, addr_op1;
2182 int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8;
2183 addr = XEXP (operands[0], 0);
2184 switch (GET_CODE (addr))
2185 {
2186 case REG:
2187 pattern = "fs%ci\t%%1, %%0";
2188 break;
2189
2190 case PLUS:
2191 addr_op0 = XEXP (addr, 0);
2192 addr_op1 = XEXP (addr, 1);
2193
2194 if (REG_P (addr_op0) && REG_P (addr_op1))
2195 pattern = "fs%c\t%%1, %%0";
2196 else if (REG_P (addr_op0) && CONST_INT_P (addr_op1))
2197 pattern = "fs%ci\t%%1, %%0";
2198 else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1)
2199 && REG_P (XEXP (addr_op0, 0))
2200 && CONST_INT_P (XEXP (addr_op0, 1)))
2201 pattern = "fs%c\t%%1, %%0";
2202 else
2203 gcc_unreachable ();
2204 break;
2205
2206 case POST_MODIFY:
2207 addr_op0 = XEXP (addr, 0);
2208 addr_op1 = XEXP (addr, 1);
2209
2210 if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2211 && REG_P (XEXP (addr_op1, 1)))
2212 pattern = "fs%c.bi\t%%1, %%0";
2213 else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS
2214 && CONST_INT_P (XEXP (addr_op1, 1)))
2215 pattern = "fs%ci.bi\t%%1, %%0";
2216 else
2217 gcc_unreachable ();
2218 break;
2219
2220 case POST_INC:
2221 if (REG_P (XEXP (addr, 0)))
2222 {
2223 if (dp)
2224 pattern = "fs%ci.bi\t%%1, %%0, 8";
2225 else
2226 pattern = "fs%ci.bi\t%%1, %%0, 4";
2227 }
2228 else
2229 gcc_unreachable ();
2230 break;
2231
2232 case POST_DEC:
2233 if (REG_P (XEXP (addr, 0)))
2234 {
2235 if (dp)
2236 pattern = "fs%ci.bi\t%%1, %%0, -8";
2237 else
2238 pattern = "fs%ci.bi\t%%1, %%0, -4";
2239 }
2240 else
2241 gcc_unreachable ();
2242 break;
2243
2244 default:
2245 gcc_unreachable ();
2246 }
2247
2248 sprintf (buff, pattern, dp ? 'd' : 's');
2249 output_asm_insn (buff, operands);
2250 return "";
2251 }
2252
2253 /* Function to generate normal jump table. */
2254 const char *
nds32_output_casesi(rtx * operands)2255 nds32_output_casesi (rtx *operands)
2256 {
2257 /* Step C: "t <-- operands[1]". */
2258 output_asm_insn ("la\t$ta, %l1", operands);
2259
2260 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
2261 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
2262
2263 /* No need to perform Step E, which is only used for
2264 pc relative jump table. */
2265
2266 /* Step F: jump to target with register z. */
2267 if (TARGET_16_BIT)
2268 return "jr5\t%2";
2269 else
2270 return "jr\t%2";
2271 }
2272
2273 /* Auxiliary functions for lwm/smw. */
2274 bool
nds32_valid_smw_lwm_base_p(rtx op)2275 nds32_valid_smw_lwm_base_p (rtx op)
2276 {
2277 rtx base_addr;
2278
2279 if (!MEM_P (op))
2280 return false;
2281
2282 base_addr = XEXP (op, 0);
2283
2284 if (REG_P (base_addr))
2285 return true;
2286 else
2287 {
2288 if (GET_CODE (base_addr) == POST_INC
2289 && REG_P (XEXP (base_addr, 0)))
2290 return true;
2291 }
2292
2293 return false;
2294 }
2295
2296 /* ------------------------------------------------------------------------ */
2297 const char *
nds32_output_smw_single_word(rtx * operands)2298 nds32_output_smw_single_word (rtx *operands)
2299 {
2300 char buff[100];
2301 unsigned regno;
2302 int enable4;
2303 bool update_base_p;
2304 rtx base_addr = operands[0];
2305 rtx base_reg;
2306 rtx otherops[2];
2307
2308 if (REG_P (XEXP (base_addr, 0)))
2309 {
2310 update_base_p = false;
2311 base_reg = XEXP (base_addr, 0);
2312 }
2313 else
2314 {
2315 update_base_p = true;
2316 base_reg = XEXP (XEXP (base_addr, 0), 0);
2317 }
2318
2319 const char *update_base = update_base_p ? "m" : "";
2320
2321 regno = REGNO (operands[1]);
2322
2323 otherops[0] = base_reg;
2324 otherops[1] = operands[1];
2325
2326 if (regno >= 28)
2327 {
2328 enable4 = nds32_regno_to_enable4 (regno);
2329 sprintf (buff, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base, enable4);
2330 }
2331 else
2332 {
2333 sprintf (buff, "smw.bi%s\t%%1, [%%0], %%1", update_base);
2334 }
2335 output_asm_insn (buff, otherops);
2336 return "";
2337 }
2338
2339 const char *
nds32_output_lmw_single_word(rtx * operands)2340 nds32_output_lmw_single_word (rtx *operands)
2341 {
2342 char buff[100];
2343 unsigned regno;
2344 bool update_base_p;
2345 int enable4;
2346 rtx base_addr = operands[1];
2347 rtx base_reg;
2348 rtx otherops[2];
2349
2350 if (REG_P (XEXP (base_addr, 0)))
2351 {
2352 update_base_p = false;
2353 base_reg = XEXP (base_addr, 0);
2354 }
2355 else
2356 {
2357 update_base_p = true;
2358 base_reg = XEXP (XEXP (base_addr, 0), 0);
2359 }
2360
2361 const char *update_base = update_base_p ? "m" : "";
2362
2363 regno = REGNO (operands[0]);
2364
2365 otherops[0] = operands[0];
2366 otherops[1] = base_reg;
2367
2368 if (regno >= 28)
2369 {
2370 enable4 = nds32_regno_to_enable4 (regno);
2371 sprintf (buff, "lmw.bi%s\t$sp, [%%1], $sp, %x", update_base, enable4);
2372 }
2373 else
2374 {
2375 sprintf (buff, "lmw.bi%s\t%%0, [%%1], %%0", update_base);
2376 }
2377 output_asm_insn (buff, otherops);
2378 return "";
2379 }
2380
2381 void
nds32_expand_unaligned_load(rtx * operands,enum machine_mode mode)2382 nds32_expand_unaligned_load (rtx *operands, enum machine_mode mode)
2383 {
2384 /* Initial memory offset. */
2385 int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0;
2386 int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1;
2387 /* Initial register shift byte. */
2388 int shift = 0;
2389 /* The first load byte instruction is not the same. */
2390 int width = GET_MODE_SIZE (mode) - 1;
2391 rtx mem[2];
2392 rtx reg[2];
2393 rtx sub_reg;
2394 rtx temp_reg, temp_sub_reg;
2395 int num_reg;
2396
2397 /* Generating a series of load byte instructions.
2398 The first load byte instructions and other
2399 load byte instructions are not the same. like:
2400 First:
2401 lbi reg0, [mem]
2402 zeh reg0, reg0
2403 Second:
2404 lbi temp_reg, [mem + offset]
2405 sll temp_reg, (8 * shift)
2406 ior reg0, temp_reg
2407
2408 lbi temp_reg, [mem + (offset + 1)]
2409 sll temp_reg, (8 * (shift + 1))
2410 ior reg0, temp_reg */
2411
2412 temp_reg = gen_reg_rtx (SImode);
2413 temp_sub_reg = gen_lowpart (QImode, temp_reg);
2414
2415 if (mode == DImode)
2416 {
2417 /* Load doubleword, we need two registers to access. */
2418 reg[0] = simplify_gen_subreg (SImode, operands[0],
2419 GET_MODE (operands[0]), 0);
2420 reg[1] = simplify_gen_subreg (SImode, operands[0],
2421 GET_MODE (operands[0]), 4);
2422 /* A register only store 4 byte. */
2423 width = GET_MODE_SIZE (SImode) - 1;
2424 }
2425 else
2426 {
2427 reg[0] = operands[0];
2428 }
2429
2430 for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--)
2431 {
2432 sub_reg = gen_lowpart (QImode, reg[0]);
2433 mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[1], offset));
2434
2435 /* Generating the first part instructions.
2436 lbi reg0, [mem]
2437 zeh reg0, reg0 */
2438 emit_move_insn (sub_reg, mem[0]);
2439 emit_insn (gen_zero_extendqisi2 (reg[0], sub_reg));
2440
2441 while (width > 0)
2442 {
2443 offset = offset + offset_adj;
2444 shift++;
2445 width--;
2446
2447 mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode,
2448 operands[1],
2449 offset));
2450 /* Generating the second part instructions.
2451 lbi temp_reg, [mem + offset]
2452 sll temp_reg, (8 * shift)
2453 ior reg0, temp_reg */
2454 emit_move_insn (temp_sub_reg, mem[1]);
2455 emit_insn (gen_ashlsi3 (temp_reg, temp_reg,
2456 GEN_INT (shift * 8)));
2457 emit_insn (gen_iorsi3 (reg[0], reg[0], temp_reg));
2458 }
2459
2460 if (mode == DImode)
2461 {
2462 /* Using the second register to load memory information. */
2463 reg[0] = reg[1];
2464 shift = 0;
2465 width = GET_MODE_SIZE (SImode) - 1;
2466 offset = offset + offset_adj;
2467 }
2468 }
2469 }
2470
2471 void
nds32_expand_unaligned_store(rtx * operands,enum machine_mode mode)2472 nds32_expand_unaligned_store (rtx *operands, enum machine_mode mode)
2473 {
2474 /* Initial memory offset. */
2475 int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0;
2476 int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1;
2477 /* Initial register shift byte. */
2478 int shift = 0;
2479 /* The first load byte instruction is not the same. */
2480 int width = GET_MODE_SIZE (mode) - 1;
2481 rtx mem[2];
2482 rtx reg[2];
2483 rtx sub_reg;
2484 rtx temp_reg, temp_sub_reg;
2485 int num_reg;
2486
2487 /* Generating a series of store byte instructions.
2488 The first store byte instructions and other
2489 load byte instructions are not the same. like:
2490 First:
2491 sbi reg0, [mem + 0]
2492 Second:
2493 srli temp_reg, reg0, (8 * shift)
2494 sbi temp_reg, [mem + offset] */
2495
2496 temp_reg = gen_reg_rtx (SImode);
2497 temp_sub_reg = gen_lowpart (QImode, temp_reg);
2498
2499 if (mode == DImode)
2500 {
2501 /* Load doubleword, we need two registers to access. */
2502 reg[0] = simplify_gen_subreg (SImode, operands[1],
2503 GET_MODE (operands[1]), 0);
2504 reg[1] = simplify_gen_subreg (SImode, operands[1],
2505 GET_MODE (operands[1]), 4);
2506 /* A register only store 4 byte. */
2507 width = GET_MODE_SIZE (SImode) - 1;
2508 }
2509 else
2510 {
2511 reg[0] = operands[1];
2512 }
2513
2514 for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--)
2515 {
2516 sub_reg = gen_lowpart (QImode, reg[0]);
2517 mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[0], offset));
2518
2519 /* Generating the first part instructions.
2520 sbi reg0, [mem + 0] */
2521 emit_move_insn (mem[0], sub_reg);
2522
2523 while (width > 0)
2524 {
2525 offset = offset + offset_adj;
2526 shift++;
2527 width--;
2528
2529 mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode,
2530 operands[0],
2531 offset));
2532 /* Generating the second part instructions.
2533 srli temp_reg, reg0, (8 * shift)
2534 sbi temp_reg, [mem + offset] */
2535 emit_insn (gen_lshrsi3 (temp_reg, reg[0],
2536 GEN_INT (shift * 8)));
2537 emit_move_insn (mem[1], temp_sub_reg);
2538 }
2539
2540 if (mode == DImode)
2541 {
2542 /* Using the second register to load memory information. */
2543 reg[0] = reg[1];
2544 shift = 0;
2545 width = GET_MODE_SIZE (SImode) - 1;
2546 offset = offset + offset_adj;
2547 }
2548 }
2549 }
2550
2551 /* Using multiple load/store instruction to output doubleword instruction. */
2552 const char *
nds32_output_double(rtx * operands,bool load_p)2553 nds32_output_double (rtx *operands, bool load_p)
2554 {
2555 char pattern[100];
2556 int reg = load_p ? 0 : 1;
2557 int mem = load_p ? 1 : 0;
2558 rtx otherops[3];
2559 rtx addr = XEXP (operands[mem], 0);
2560
2561 otherops[0] = gen_rtx_REG (SImode, REGNO (operands[reg]));
2562 otherops[1] = gen_rtx_REG (SImode, REGNO (operands[reg]) + 1);
2563
2564 if (GET_CODE (addr) == POST_INC)
2565 {
2566 /* (mem (post_inc (reg))) */
2567 otherops[2] = XEXP (addr, 0);
2568 snprintf (pattern, sizeof (pattern),
2569 "%cmw.bim\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's');
2570 }
2571 else
2572 {
2573 /* (mem (reg)) */
2574 otherops[2] = addr;
2575 snprintf (pattern, sizeof (pattern),
2576 "%cmw.bi\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's');
2577
2578 }
2579
2580 output_asm_insn (pattern, otherops);
2581 return "";
2582 }
2583
2584 const char *
nds32_output_cbranchsi4_equality_zero(rtx_insn * insn,rtx * operands)2585 nds32_output_cbranchsi4_equality_zero (rtx_insn *insn, rtx *operands)
2586 {
2587 enum rtx_code code;
2588 bool long_jump_p = false;
2589
2590 code = GET_CODE (operands[0]);
2591
2592 /* This zero-comparison conditional branch has two forms:
2593 32-bit instruction => beqz/bnez imm16s << 1
2594 16-bit instruction => beqzs8/bnezs8/beqz38/bnez38 imm8s << 1
2595
2596 For 32-bit case,
2597 we assume it is always reachable. (but check range -65500 ~ 65500)
2598
2599 For 16-bit case,
2600 it must satisfy { 255 >= (label - pc) >= -256 } condition.
2601 However, since the $pc for nds32 is at the beginning of the instruction,
2602 we should leave some length space for current insn.
2603 So we use range -250 ~ 250. */
2604
2605 switch (get_attr_length (insn))
2606 {
2607 case 8:
2608 long_jump_p = true;
2609 /* fall through */
2610 case 2:
2611 if (which_alternative == 0)
2612 {
2613 /* constraint: t */
2614 /* b<cond>zs8 .L0
2615 or
2616 b<inverse_cond>zs8 .LCB0
2617 j .L0
2618 .LCB0:
2619 */
2620 output_cond_branch_compare_zero (code, "s8", long_jump_p,
2621 operands, true);
2622 return "";
2623 }
2624 else if (which_alternative == 1)
2625 {
2626 /* constraint: l */
2627 /* b<cond>z38 $r0, .L0
2628 or
2629 b<inverse_cond>z38 $r0, .LCB0
2630 j .L0
2631 .LCB0:
2632 */
2633 output_cond_branch_compare_zero (code, "38", long_jump_p,
2634 operands, false);
2635 return "";
2636 }
2637 else
2638 {
2639 /* constraint: r */
2640 /* For which_alternative==2, it should not be here. */
2641 gcc_unreachable ();
2642 }
2643 case 10:
2644 /* including constraints: t, l, and r */
2645 long_jump_p = true;
2646 /* fall through */
2647 case 4:
2648 /* including constraints: t, l, and r */
2649 output_cond_branch_compare_zero (code, "", long_jump_p, operands, false);
2650 return "";
2651
2652 default:
2653 gcc_unreachable ();
2654 }
2655 }
2656
2657 const char *
nds32_output_cbranchsi4_equality_reg(rtx_insn * insn,rtx * operands)2658 nds32_output_cbranchsi4_equality_reg (rtx_insn *insn, rtx *operands)
2659 {
2660 enum rtx_code code;
2661 bool long_jump_p, r5_p;
2662 int insn_length;
2663
2664 insn_length = get_attr_length (insn);
2665
2666 long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false;
2667 r5_p = (insn_length == 2 || insn_length == 8) ? true : false;
2668
2669 code = GET_CODE (operands[0]);
2670
2671 /* This register-comparison conditional branch has one form:
2672 32-bit instruction => beq/bne imm14s << 1
2673
2674 For 32-bit case,
2675 we assume it is always reachable. (but check range -16350 ~ 16350). */
2676
2677 switch (code)
2678 {
2679 case EQ:
2680 case NE:
2681 output_cond_branch (code, "", r5_p, long_jump_p, operands);
2682 return "";
2683
2684 default:
2685 gcc_unreachable ();
2686 }
2687 }
2688
2689 const char *
nds32_output_cbranchsi4_equality_reg_or_const_int(rtx_insn * insn,rtx * operands)2690 nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *insn,
2691 rtx *operands)
2692 {
2693 enum rtx_code code;
2694 bool long_jump_p, r5_p;
2695 int insn_length;
2696
2697 insn_length = get_attr_length (insn);
2698
2699 long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false;
2700 r5_p = (insn_length == 2 || insn_length == 8) ? true : false;
2701
2702 code = GET_CODE (operands[0]);
2703
2704 /* This register-comparison conditional branch has one form:
2705 32-bit instruction => beq/bne imm14s << 1
2706 32-bit instruction => beqc/bnec imm8s << 1
2707
2708 For 32-bit case, we assume it is always reachable.
2709 (but check range -16350 ~ 16350 and -250 ~ 250). */
2710
2711 switch (code)
2712 {
2713 case EQ:
2714 case NE:
2715 if (which_alternative == 2)
2716 {
2717 /* r, Is11 */
2718 /* b<cond>c */
2719 output_cond_branch (code, "c", r5_p, long_jump_p, operands);
2720 }
2721 else
2722 {
2723 /* r, r */
2724 /* v, r */
2725 output_cond_branch (code, "", r5_p, long_jump_p, operands);
2726 }
2727 return "";
2728 default:
2729 gcc_unreachable ();
2730 }
2731 }
2732
2733 const char *
nds32_output_cbranchsi4_greater_less_zero(rtx_insn * insn,rtx * operands)2734 nds32_output_cbranchsi4_greater_less_zero (rtx_insn *insn, rtx *operands)
2735 {
2736 enum rtx_code code;
2737 bool long_jump_p;
2738 int insn_length;
2739
2740 insn_length = get_attr_length (insn);
2741
2742 gcc_assert (insn_length == 4 || insn_length == 10);
2743
2744 long_jump_p = (insn_length == 10) ? true : false;
2745
2746 code = GET_CODE (operands[0]);
2747
2748 /* This zero-greater-less-comparison conditional branch has one form:
2749 32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1
2750
2751 For 32-bit case, we assume it is always reachable.
2752 (but check range -65500 ~ 65500). */
2753
2754 switch (code)
2755 {
2756 case GT:
2757 case GE:
2758 case LT:
2759 case LE:
2760 output_cond_branch_compare_zero (code, "", long_jump_p, operands, false);
2761 break;
2762 default:
2763 gcc_unreachable ();
2764 }
2765 return "";
2766 }
2767
2768 /* Return true if SYMBOL_REF X binds locally. */
2769
2770 static bool
nds32_symbol_binds_local_p(const_rtx x)2771 nds32_symbol_binds_local_p (const_rtx x)
2772 {
2773 return (SYMBOL_REF_DECL (x)
2774 ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
2775 : SYMBOL_REF_LOCAL_P (x));
2776 }
2777
2778 const char *
nds32_output_call(rtx insn,rtx * operands,rtx symbol,const char * long_call,const char * call,bool align_p)2779 nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call,
2780 const char *call, bool align_p)
2781 {
2782 char pattern[100];
2783 bool noreturn_p;
2784
2785 if (GET_CODE (symbol) == CONST)
2786 {
2787 symbol= XEXP (symbol, 0);
2788
2789 if (GET_CODE (symbol) == PLUS)
2790 symbol = XEXP (symbol, 0);
2791 }
2792
2793 gcc_assert (GET_CODE (symbol) == SYMBOL_REF
2794 || REG_P (symbol));
2795
2796 if (nds32_long_call_p (symbol))
2797 strcpy (pattern, long_call);
2798 else
2799 strcpy (pattern, call);
2800
2801 if (align_p)
2802 strcat (pattern, "\n\t.align 2");
2803
2804 noreturn_p = find_reg_note (insn, REG_NORETURN, NULL_RTX) != NULL_RTX;
2805
2806 if (noreturn_p)
2807 {
2808 if (TARGET_16_BIT)
2809 strcat (pattern, "\n\tnop16");
2810 else
2811 strcat (pattern, "\n\tnop");
2812 }
2813
2814 output_asm_insn (pattern, operands);
2815 return "";
2816 }
2817
2818 /* Spilt a doubleword instrucion to two single word instructions. */
2819 void
nds32_spilt_doubleword(rtx * operands,bool load_p)2820 nds32_spilt_doubleword (rtx *operands, bool load_p)
2821 {
2822 int reg = load_p ? 0 : 1;
2823 int mem = load_p ? 1 : 0;
2824 rtx reg_rtx = load_p ? operands[0] : operands[1];
2825 rtx mem_rtx = load_p ? operands[1] : operands[0];
2826 rtx low_part[2], high_part[2];
2827 rtx sub_mem = XEXP (mem_rtx, 0);
2828
2829 /* Generate low_part and high_part register pattern.
2830 i.e. register pattern like:
2831 (reg:DI) -> (subreg:SI (reg:DI))
2832 (subreg:SI (reg:DI)) */
2833 low_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 0);
2834 high_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 4);
2835
2836 /* Generate low_part and high_part memory pattern.
2837 Memory format is (post_dec) will generate:
2838 low_part: lwi.bi reg, [mem], 4
2839 high_part: lwi.bi reg, [mem], -12 */
2840 if (GET_CODE (sub_mem) == POST_DEC)
2841 {
2842 /* memory format is (post_dec (reg)),
2843 so that extract (reg) from the (post_dec (reg)) pattern. */
2844 sub_mem = XEXP (sub_mem, 0);
2845
2846 /* generate low_part and high_part memory format:
2847 low_part: (post_modify ((reg) (plus (reg) (const 4)))
2848 high_part: (post_modify ((reg) (plus (reg) (const -12))) */
2849 low_part[mem] = gen_frame_mem (SImode,
2850 gen_rtx_POST_MODIFY (Pmode, sub_mem,
2851 gen_rtx_PLUS (Pmode,
2852 sub_mem,
2853 GEN_INT (4))));
2854 high_part[mem] = gen_frame_mem (SImode,
2855 gen_rtx_POST_MODIFY (Pmode, sub_mem,
2856 gen_rtx_PLUS (Pmode,
2857 sub_mem,
2858 GEN_INT (-12))));
2859 }
2860 else if (GET_CODE (sub_mem) == POST_MODIFY)
2861 {
2862 /* Memory format is (post_modify (reg) (plus (reg) (const))),
2863 so that extract (reg) from the post_modify pattern. */
2864 rtx post_mem = XEXP (sub_mem, 0);
2865
2866 /* Extract (const) from the (post_modify (reg) (plus (reg) (const)))
2867 pattern. */
2868
2869 rtx plus_op = XEXP (sub_mem, 1);
2870 rtx post_val = XEXP (plus_op, 1);
2871
2872 /* Generate low_part and high_part memory format:
2873 low_part: (post_modify ((reg) (plus (reg) (const)))
2874 high_part: ((plus (reg) (const 4))) */
2875 low_part[mem] = gen_frame_mem (SImode,
2876 gen_rtx_POST_MODIFY (Pmode, post_mem,
2877 gen_rtx_PLUS (Pmode,
2878 post_mem,
2879 post_val)));
2880 high_part[mem] = gen_frame_mem (SImode, plus_constant (Pmode,
2881 post_mem,
2882 4));
2883 }
2884 else
2885 {
2886 /* memory format: (symbol_ref), (const), (reg + const_int). */
2887 low_part[mem] = adjust_address (mem_rtx, SImode, 0);
2888 high_part[mem] = adjust_address (mem_rtx, SImode, 4);
2889 }
2890
2891 /* After reload completed, we have dependent issue by low part register and
2892 higt part memory. i.e. we cannot split a sequence
2893 like:
2894 load $r0, [%r1]
2895 spilt to
2896 lw $r0, [%r0]
2897 lwi $r1, [%r0 + 4]
2898 swap position
2899 lwi $r1, [%r0 + 4]
2900 lw $r0, [%r0]
2901 For store instruction we don't have a problem.
2902
2903 When memory format is [post_modify], we need to emit high part instruction,
2904 before low part instruction.
2905 expamle:
2906 load $r0, [%r2], post_val
2907 spilt to
2908 load $r1, [%r2 + 4]
2909 load $r0, [$r2], post_val. */
2910 if ((load_p && reg_overlap_mentioned_p (low_part[0], high_part[1]))
2911 || GET_CODE (sub_mem) == POST_MODIFY)
2912 {
2913 operands[2] = high_part[0];
2914 operands[3] = high_part[1];
2915 operands[4] = low_part[0];
2916 operands[5] = low_part[1];
2917 }
2918 else
2919 {
2920 operands[2] = low_part[0];
2921 operands[3] = low_part[1];
2922 operands[4] = high_part[0];
2923 operands[5] = high_part[1];
2924 }
2925 }
2926
2927 /* Return true X is need use long call. */
2928 bool
nds32_long_call_p(rtx symbol)2929 nds32_long_call_p (rtx symbol)
2930 {
2931 return TARGET_CMODEL_LARGE;
2932 }
2933
2934 void
nds32_expand_constant(machine_mode mode,HOST_WIDE_INT val,rtx target,rtx source)2935 nds32_expand_constant (machine_mode mode, HOST_WIDE_INT val,
2936 rtx target, rtx source)
2937 {
2938 rtx temp = gen_reg_rtx (mode);
2939 int clear_sign_bit_copies = 0;
2940 int clear_zero_bit_copies = 0;
2941 unsigned HOST_WIDE_INT remainder = val & 0xffffffffUL;
2942
2943 /* Count number of leading zeros. */
2944 clear_sign_bit_copies = __builtin_clz (remainder);
2945 /* Count number of trailing zeros. */
2946 clear_zero_bit_copies = __builtin_ctz (remainder);
2947
2948 HOST_WIDE_INT sign_shift_mask = ((0xffffffffUL
2949 << (32 - clear_sign_bit_copies))
2950 & 0xffffffffUL);
2951 HOST_WIDE_INT zero_shift_mask = (1 << clear_zero_bit_copies) - 1;
2952
2953 if (clear_sign_bit_copies > 0 && clear_sign_bit_copies < 17
2954 && (remainder | sign_shift_mask) == 0xffffffffUL)
2955 {
2956 /* Transfer AND to two shifts, example:
2957 a = b & 0x7fffffff => (b << 1) >> 1 */
2958 rtx shift = GEN_INT (clear_sign_bit_copies);
2959
2960 emit_insn (gen_ashlsi3 (temp, source, shift));
2961 emit_insn (gen_lshrsi3 (target, temp, shift));
2962 }
2963 else if (clear_zero_bit_copies > 0 && clear_sign_bit_copies < 17
2964 && (remainder | zero_shift_mask) == 0xffffffffUL)
2965 {
2966 /* Transfer AND to two shifts, example:
2967 a = b & 0xfff00000 => (b >> 20) << 20 */
2968 rtx shift = GEN_INT (clear_zero_bit_copies);
2969
2970 emit_insn (gen_lshrsi3 (temp, source, shift));
2971 emit_insn (gen_ashlsi3 (target, temp, shift));
2972 }
2973 else
2974 {
2975 emit_move_insn (temp, GEN_INT (val));
2976 emit_move_insn (target, gen_rtx_fmt_ee (AND, mode, source, temp));
2977 }
2978 }
2979