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.
6 This file is part of GCC.
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.
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.
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/>. */
22 /* ------------------------------------------------------------------------ */
24 #define IN_TARGET_CODE 1
28 #include "coretypes.h"
35 #include "optabs.h" /* For GEN_FCN. */
38 #include "tm-constrs.h"
43 /* ------------------------------------------------------------------------ */
46 nds32_regno_to_enable4 (unsigned regno
)
50 case 28: /* $r28/fp */
52 case 29: /* $r29/gp */
54 case 30: /* $r30/lp */
56 case 31: /* $r31/sp */
63 /* A helper function to return character based on byte size. */
65 nds32_byte_to_size (int byte
)
76 /* Normally it should not be here. */
82 nds32_inverse_cond_code (int code
)
104 nds32_cond_code_str (int code
)
126 output_cond_branch (int code
, const char *suffix
, bool r5_p
,
127 bool long_jump_p
, rtx
*operands
)
130 const char *cond_code
;
131 bool align_p
= NDS32_ALIGN_P ();
132 const char *align
= align_p
? "\t.align\t2\n" : "";
134 if (r5_p
&& REGNO (operands
[2]) == 5 && TARGET_16_BIT
)
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. */
141 /* $r5 == $r5 always taken! */
143 snprintf (pattern
, sizeof (pattern
),
146 snprintf (pattern
, sizeof (pattern
),
150 /* Don't output anything since $r5 != $r5 never taken! */
153 else if (long_jump_p
)
155 int inverse_code
= nds32_inverse_cond_code (code
);
156 cond_code
= nds32_cond_code_str (inverse_code
);
158 /* b<cond><suffix> $r0, $r1, .L0
160 b<inverse_cond><suffix> $r0, $r1, .LCB0
166 b<cond><suffix> $r0, $r1, .L0
168 b<inverse_cond><suffix> $r0, $r1, .LCB0
172 if (r5_p
&& TARGET_16_BIT
)
174 snprintf (pattern
, sizeof (pattern
),
175 "b%ss38\t %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:",
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
);
187 cond_code
= nds32_cond_code_str (code
);
188 if (r5_p
&& TARGET_16_BIT
)
190 /* b<cond>s38 $r1, .L0 */
191 snprintf (pattern
, sizeof (pattern
),
192 "b%ss38\t %%2, %%3", cond_code
);
196 /* b<cond><suffix> $r0, $r1, .L0 */
197 snprintf (pattern
, sizeof (pattern
),
198 "b%s%s\t%%1, %%2, %%3", cond_code
, suffix
);
202 output_asm_insn (pattern
, operands
);
206 output_cond_branch_compare_zero (int code
, const char *suffix
,
207 bool long_jump_p
, rtx
*operands
,
211 const char *cond_code
;
212 bool align_p
= NDS32_ALIGN_P ();
213 const char *align
= align_p
? "\t.align\t2\n" : "";
216 int inverse_code
= nds32_inverse_cond_code (code
);
217 cond_code
= nds32_cond_code_str (inverse_code
);
219 if (ta_implied_p
&& TARGET_16_BIT
)
221 /* b<cond>z<suffix> .L0
223 b<inverse_cond>z<suffix> .LCB0
227 snprintf (pattern
, sizeof (pattern
),
228 "b%sz%s\t.LCB%%=\n\tj\t%%2\n%s.LCB%%=:",
229 cond_code
, suffix
, align
);
233 /* b<cond>z<suffix> $r0, .L0
235 b<inverse_cond>z<suffix> $r0, .LCB0
239 snprintf (pattern
, sizeof (pattern
),
240 "b%sz%s\t%%1, .LCB%%=\n\tj\t%%2\n%s.LCB%%=:",
241 cond_code
, suffix
, align
);
246 cond_code
= nds32_cond_code_str (code
);
247 if (ta_implied_p
&& TARGET_16_BIT
)
249 /* b<cond>z<suffix> .L0 */
250 snprintf (pattern
, sizeof (pattern
),
251 "b%sz%s\t%%2", cond_code
, suffix
);
255 /* b<cond>z<suffix> $r0, .L0 */
256 snprintf (pattern
, sizeof (pattern
),
257 "b%sz%s\t%%1, %%2", cond_code
, suffix
);
261 output_asm_insn (pattern
, operands
);
264 /* ------------------------------------------------------------------------ */
266 /* Auxiliary function for expand RTL pattern. */
268 enum nds32_expand_result_type
269 nds32_expand_cbranch (rtx
*operands
)
274 code
= GET_CODE (operands
[0]);
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)
285 return EXPAND_CREATE_TEMPLATE
;
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. */
294 if (GET_CODE (operands
[2]) == CONST_INT
)
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
);
300 tmp_reg
= gen_reg_rtx (SImode
);
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.
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.
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
;
319 rtx plus1
= gen_int_mode (INTVAL (operands
[2]) + 1, SImode
);
320 if (satisfies_constraint_Is15 (plus1
))
326 /* GT, use slts instruction */
328 gen_slts_compare (tmp_reg
, operands
[1], operands
[2]));
332 /* GTU, use slt instruction */
334 gen_slt_compare (tmp_reg
, operands
[1], operands
[2]));
342 /* GT, use slts instruction */
344 gen_slts_compare (tmp_reg
, operands
[2], operands
[1]));
348 /* GTU, use slt instruction */
350 gen_slt_compare (tmp_reg
, operands
[2], operands
[1]));
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]));
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
);
368 tmp_reg
= gen_reg_rtx (SImode
);
372 /* GT, use slts instruction */
373 emit_insn (gen_slts_compare (tmp_reg
, operands
[2], operands
[1]));
377 /* GTU, use slt instruction */
378 emit_insn (gen_slt_compare (tmp_reg
, operands
[2], operands
[1]));
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]));
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
);
397 tmp_reg
= gen_reg_rtx (SImode
);
401 /* GE, use slts instruction */
402 emit_insn (gen_slts_compare (tmp_reg
, operands
[1], operands
[2]));
406 /* GEU, use slt instruction */
407 emit_insn (gen_slt_compare (tmp_reg
, operands
[1], operands
[2]));
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]));
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
);
425 tmp_reg
= gen_reg_rtx (SImode
);
429 /* LT, use slts instruction */
430 emit_insn (gen_slts_compare (tmp_reg
, operands
[1], operands
[2]));
434 /* LTU, use slt instruction */
435 emit_insn (gen_slt_compare (tmp_reg
, operands
[1], operands
[2]));
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]));
448 if (GET_CODE (operands
[2]) == CONST_INT
)
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
);
454 tmp_reg
= gen_reg_rtx (SImode
);
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
))
467 /* LE, use slts instruction */
469 gen_slts_compare (tmp_reg
, operands
[1], operands
[2]));
473 /* LEU, use slt instruction */
475 gen_slt_compare (tmp_reg
, operands
[1], operands
[2]));
483 /* LE, use slts instruction */
485 gen_slts_compare (tmp_reg
, operands
[2], operands
[1]));
489 /* LEU, use slt instruction */
491 gen_slt_compare (tmp_reg
, operands
[2], operands
[1]));
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]));
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
);
509 tmp_reg
= gen_reg_rtx (SImode
);
513 /* LE, use slts instruction */
514 emit_insn (gen_slts_compare (tmp_reg
, operands
[2], operands
[1]));
518 /* LEU, use slt instruction */
519 emit_insn (gen_slt_compare (tmp_reg
, operands
[2], operands
[1]));
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]));
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. */
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])
542 operands
[2] = force_reg (SImode
, operands
[2]);
544 return EXPAND_CREATE_TEMPLATE
;
551 enum nds32_expand_result_type
552 nds32_expand_cstore (rtx
*operands
)
557 code
= GET_CODE (operands
[1]);
563 if (GET_CODE (operands
[3]) == CONST_INT
)
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
);
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
));
581 if (!(satisfies_constraint_Iu15 (operands
[3])
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]));
589 emit_insn (gen_slt_eq0 (operands
[0], tmp_reg
));
591 emit_insn (gen_slt_compare (operands
[0], const0_rtx
, tmp_reg
));
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]));
606 emit_insn (gen_slt_eq0 (operands
[0], tmp_reg
));
608 emit_insn (gen_slt_compare (operands
[0], const0_rtx
, tmp_reg
));
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 */
618 /* GT, use slts instruction */
619 emit_insn (gen_slts_compare (operands
[0], operands
[3], operands
[2]));
623 /* GTU, use slt instruction */
624 emit_insn (gen_slt_compare (operands
[0], operands
[3], operands
[2]));
631 if (GET_CODE (operands
[3]) == CONST_INT
)
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
);
638 emit_insn (gen_movsi (tmp_reg
,
639 gen_int_mode (INTVAL (operands
[3]) - 1,
643 /* GE, use slts instruction */
644 emit_insn (gen_slts_compare (operands
[0], tmp_reg
, operands
[2]));
648 /* GEU, use slt instruction */
649 emit_insn (gen_slt_compare (operands
[0], tmp_reg
, operands
[2]));
656 /* reg_R = (reg_A >= reg_B)
657 --> slt reg_R, reg_A, reg_B
658 xori reg_R, reg_R, const_int_1 */
661 /* GE, use slts instruction */
662 emit_insn (gen_slts_compare (operands
[0],
663 operands
[2], operands
[3]));
667 /* GEU, use slt instruction */
668 emit_insn (gen_slt_compare (operands
[0],
669 operands
[2], operands
[3]));
672 /* perform 'not' behavior */
673 emit_insn (gen_xorsi3 (operands
[0], operands
[0], const1_rtx
));
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 */
684 /* LT, use slts instruction */
685 emit_insn (gen_slts_compare (operands
[0], operands
[2], operands
[3]));
689 /* LTU, use slt instruction */
690 emit_insn (gen_slt_compare (operands
[0], operands
[2], operands
[3]));
697 if (GET_CODE (operands
[3]) == CONST_INT
)
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
);
704 emit_insn (gen_movsi (tmp_reg
,
705 gen_int_mode (INTVAL (operands
[3]) + 1,
709 /* LE, use slts instruction */
710 emit_insn (gen_slts_compare (operands
[0], operands
[2], tmp_reg
));
714 /* LEU, use slt instruction */
715 emit_insn (gen_slt_compare (operands
[0], operands
[2], tmp_reg
));
722 /* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A
723 xori reg_R, reg_R, const_int_1 */
726 /* LE, use slts instruction */
727 emit_insn (gen_slts_compare (operands
[0],
728 operands
[3], operands
[2]));
732 /* LEU, use slt instruction */
733 emit_insn (gen_slt_compare (operands
[0],
734 operands
[3], operands
[2]));
737 /* perform 'not' behavior */
738 emit_insn (gen_xorsi3 (operands
[0], operands
[0], const1_rtx
));
750 nds32_expand_float_cbranch (rtx
*operands
)
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];
761 /* Main Goal: Use compare instruction + branch instruction.
764 GT, GE: swap condition and swap operands and generate
765 compare instruction(LT, LE) + branch not equal instruction.
767 UNORDERED, LT, LE, EQ: no need to change and generate
768 compare instruction(UNORDERED, LT, LE, EQ) + branch not equal instruction.
770 ORDERED, NE: reverse condition and generate
771 compare instruction(EQ) + branch equal instruction. */
780 new_code
= swap_condition (new_code
);
789 new_code
= reverse_condition (new_code
);
794 new_code
= reverse_condition_maybe_unordered (new_code
);
799 new_code
= reverse_condition_maybe_unordered (new_code
);
803 new_code
= swap_condition (new_code
);
810 tmp_reg
= gen_reg_rtx (SImode
);
811 emit_insn (gen_rtx_SET (tmp_reg
,
812 gen_rtx_fmt_ee (new_code
, SImode
,
815 PUT_CODE (operands
[0], reverse
? EQ
: NE
);
816 emit_insn (gen_cbranchsi4 (operands
[0], tmp_reg
,
817 const0_rtx
, operands
[3]));
821 nds32_expand_float_cstore (rtx
*operands
)
823 enum rtx_code code
= GET_CODE (operands
[1]);
824 enum rtx_code new_code
= code
;
825 machine_mode mode
= GET_MODE (operands
[2]);
827 rtx cmp_op0
= operands
[2];
828 rtx cmp_op1
= operands
[3];
831 /* Main Goal: Use compare instruction to store value.
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
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
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
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 */
857 new_code
= swap_condition (new_code
);
866 emit_insn (gen_cmpsf_un (operands
[0], cmp_op0
, cmp_op1
));
868 emit_insn (gen_cmpdf_un (operands
[0], cmp_op0
, cmp_op1
));
870 emit_insn (gen_xorsi3 (operands
[0], operands
[0], const1_rtx
));
874 emit_insn (gen_cmpsf_eq (operands
[0], cmp_op0
, cmp_op1
));
876 emit_insn (gen_cmpdf_eq (operands
[0], cmp_op0
, cmp_op1
));
878 emit_insn (gen_xorsi3 (operands
[0], operands
[0], const1_rtx
));
884 emit_insn (gen_rtx_SET (operands
[0],
885 gen_rtx_fmt_ee (new_code
, SImode
,
889 enum nds32_expand_result_type
890 nds32_expand_movcc (rtx
*operands
)
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);
899 if ((GET_CODE (operands
[1]) == EQ
|| GET_CODE (operands
[1]) == NE
)
900 && XEXP (operands
[1], 1) == const0_rtx
)
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
;
906 else if ((TARGET_FPU_SINGLE
&& cmp0_mode
== SFmode
)
907 || (TARGET_FPU_DOUBLE
&& cmp0_mode
== DFmode
))
909 nds32_expand_float_movcc (operands
);
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. */
922 /* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part
923 Strategy : Reverse condition and swap comparison operands
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')
931 a >= b ? P : Q (GE or GEU)
932 --> a < b ? Q : P (reverse condition to achieve 'LT/LTU')
934 a < b ? P : Q (LT or LTU)
935 --> (NO NEED TO CHANGE, it is already 'LT/LTU')
937 a > b ? P : Q (GT or GTU)
938 --> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */
941 case GE
: case GEU
: case LE
: case LEU
:
942 new_code
= reverse_condition (code
);
947 /* no need to reverse condition */
953 /* For '>' comparison operator, we swap operands
954 so that we can have 'LT/LTU' operator. */
955 if (new_code
== GT
|| new_code
== GTU
)
961 new_code
= swap_condition (new_code
);
964 /* Use a temporary register to store slt/slts result. */
965 tmp
= gen_reg_rtx (SImode
);
967 if (new_code
== EQ
|| new_code
== NE
)
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
);
975 /* This emit_insn will create corresponding 'slt/slts'
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
));
984 /* Change comparison semantic into (eq X 0) or (ne X 0) behavior
985 so that cmovz or cmovn will be matched later.
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
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
);
998 return EXPAND_CREATE_TEMPLATE
;
1002 nds32_expand_float_movcc (rtx
*operands
)
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
)
1008 /* If the operands[1] rtx is already (eq X 0) or (ne X 0),
1009 we have gcc generate original template rtx. */
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);
1022 /* Compare instruction Operations: (cmp_op0 condition cmp_op1) ? 1 : 0,
1023 when result is 1, and 'reverse' be set 1 for fcmovzs instructuin. */
1026 /* Main Goal: Use cmpare instruction + conditional move instruction.
1027 Strategy : swap condition and swap comparison operands.
1031 --> a < b ? Q : P (swap condition)
1032 --> b < a ? Q : P (swap comparison operands to achieve 'GT')
1035 --> a <= b ? Q : P (swap condition)
1036 --> b <= a ? Q : P (swap comparison operands to achieve 'GE')
1039 --> (NO NEED TO CHANGE, it is already 'LT')
1042 --> (NO NEED TO CHANGE, it is already 'LE')
1045 --> (NO NEED TO CHANGE, it is already 'EQ') */
1054 new_code
= swap_condition (new_code
);
1064 new_code
= reverse_condition (new_code
);
1068 new_code
= reverse_condition_maybe_unordered (new_code
);
1073 new_code
= reverse_condition_maybe_unordered (new_code
);
1077 new_code
= swap_condition (new_code
);
1084 /* Use a temporary register to store fcmpxxs result. */
1085 tmp
= gen_reg_rtx (SImode
);
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
))
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
)));
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],
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
);
1113 nds32_emit_push_fpr_callee_saved (int base_offset
)
1117 unsigned int regno
= cfun
->machine
->callee_saved_first_fpr_regno
;
1118 unsigned int last_fpr
= cfun
->machine
->callee_saved_last_fpr_regno
;
1120 while (regno
<= last_fpr
)
1122 /* Handling two registers, using fsdi instruction. */
1123 reg
= gen_rtx_REG (DFmode
, regno
);
1124 mem
= gen_frame_mem (DFmode
, plus_constant (Pmode
,
1129 fpu_insn
= emit_move_insn (mem
, reg
);
1130 RTX_FRAME_RELATED_P (fpu_insn
) = 1;
1135 nds32_emit_pop_fpr_callee_saved (int gpr_padding_size
)
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
;
1144 while (regno
<= last_fpr
)
1146 /* Handling two registers, using fldi.bi instruction. */
1147 if ((regno
+ 1) >= last_fpr
)
1148 padding
= gpr_padding_size
;
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
);
1156 fpu_insn
= emit_move_insn (reg
, mem
);
1159 gen_rtx_SET (stack_pointer_rtx
,
1160 plus_constant (Pmode
, stack_pointer_rtx
,
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
),
1167 RTX_FRAME_RELATED_P (fpu_insn
) = 1;
1168 REG_NOTES (fpu_insn
) = dwarf
;
1173 nds32_emit_v3pop_fpr_callee_saved (int base
)
1175 int fpu_base_addr
= base
;
1181 regno
= cfun
->machine
->callee_saved_first_fpr_regno
;
1182 while (regno
<= cfun
->machine
->callee_saved_last_fpr_regno
)
1184 /* Handling two registers, using fldi instruction. */
1185 reg
= gen_rtx_REG (DFmode
, regno
);
1186 mem
= gen_frame_mem (DFmode
, plus_constant (Pmode
,
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
;
1198 /* ------------------------------------------------------------------------ */
1200 /* Function to return memory format. */
1201 enum nds32_16bit_address_type
1202 nds32_mem_format (rtx op
)
1204 machine_mode mode_test
;
1209 return ADDRESS_NOT_16BIT_FORMAT
;
1211 mode_test
= GET_MODE (op
);
1216 if (GET_CODE (op
) == REG
1217 && ((mode_test
== SImode
) || (mode_test
== SFmode
)))
1220 /* 333 format for QI/HImode. */
1221 if (GET_CODE (op
) == REG
&& (REGNO (op
) < R8_REGNUM
))
1222 return ADDRESS_LO_REG_IMM3U
;
1224 /* post_inc 333 format. */
1225 if ((GET_CODE (op
) == POST_INC
)
1226 && ((mode_test
== SImode
) || (mode_test
== SFmode
)))
1228 regno
= REGNO(XEXP (op
, 0));
1231 return ADDRESS_POST_INC_LO_REG_IMM3U
;
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))))
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
;
1246 if ((GET_CODE (op
) == PLUS
)
1247 && (GET_CODE (XEXP (op
, 0)) == REG
)
1248 && (GET_CODE (XEXP (op
, 1)) == CONST_INT
))
1250 val
= INTVAL (XEXP (op
, 1));
1252 regno
= REGNO(XEXP (op
, 0));
1255 && regno
!= SP_REGNUM
1256 && regno
!= FP_REGNUM
)
1257 return ADDRESS_NOT_16BIT_FORMAT
;
1263 if (val
>= 0 && val
< 8 && regno
< 8)
1264 return ADDRESS_LO_REG_IMM3U
;
1269 if (val
>= 0 && val
< 16 && (val
% 2 == 0) && regno
< 8)
1270 return ADDRESS_LO_REG_IMM3U
;
1276 /* r8 imply fe format. */
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
;
1289 else if (val
>= 0 && val
< 32 && (val
% 4 == 0) && regno
< 8)
1290 return ADDRESS_LO_REG_IMM3U
;
1298 return ADDRESS_NOT_16BIT_FORMAT
;
1301 /* Output 16-bit store. */
1303 nds32_output_16bit_store (rtx
*operands
, int byte
)
1307 rtx code
= XEXP (operands
[0], 0);
1309 size
= nds32_byte_to_size (byte
);
1311 switch (nds32_mem_format (operands
[0]))
1315 output_asm_insn ("swi450\t%1, [%0]", operands
);
1317 case ADDRESS_LO_REG_IMM3U
:
1318 snprintf (pattern
, sizeof (pattern
), "s%ci333\t%%1, %%0", size
);
1319 output_asm_insn (pattern
, operands
);
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
);
1325 case ADDRESS_POST_MODIFY_LO_REG_IMM3U
:
1326 snprintf (pattern
, sizeof (pattern
), "swi333.bi\t%%1, %%0");
1327 output_asm_insn (pattern
, operands
);
1329 case ADDRESS_FP_IMM7U
:
1330 output_asm_insn ("swi37\t%1, %0", operands
);
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
);
1344 /* Output 16-bit load. */
1346 nds32_output_16bit_load (rtx
*operands
, int byte
)
1350 rtx code
= XEXP (operands
[1], 0);
1352 size
= nds32_byte_to_size (byte
);
1354 switch (nds32_mem_format (operands
[1]))
1358 output_asm_insn ("lwi450\t%0, [%1]", operands
);
1360 case ADDRESS_LO_REG_IMM3U
:
1361 snprintf (pattern
, sizeof (pattern
), "l%ci333\t%%0, %%1", size
);
1362 output_asm_insn (pattern
, operands
);
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
);
1368 case ADDRESS_POST_MODIFY_LO_REG_IMM3U
:
1369 snprintf (pattern
, sizeof (pattern
), "lwi333.bi\t%%0, %%1");
1370 output_asm_insn (pattern
, operands
);
1372 case ADDRESS_R8_IMM7U
:
1373 output_asm_insn ("lwi45.fe\t%0, %e1", operands
);
1375 case ADDRESS_FP_IMM7U
:
1376 output_asm_insn ("lwi37\t%0, %1", operands
);
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
);
1390 /* Output 32-bit store. */
1392 nds32_output_32bit_store (rtx
*operands
, int byte
)
1396 rtx code
= XEXP (operands
[0], 0);
1398 size
= nds32_byte_to_size (byte
);
1400 switch (GET_CODE (code
))
1404 => access location by using register,
1405 use "sbi / shi / swi" */
1406 snprintf (pattern
, sizeof (pattern
), "s%ci\t%%1, %%0", size
);
1411 /* (mem (symbol_ref X))
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
);
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
);
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
);
1436 switch (GET_CODE (XEXP (XEXP (code
, 1), 1)))
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
);
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
);
1459 switch (GET_CODE (XEXP (code
, 1)))
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
);
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
);
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
);
1490 output_asm_insn (pattern
, operands
);
1494 /* Output 32-bit load. */
1496 nds32_output_32bit_load (rtx
*operands
, int byte
)
1502 code
= XEXP (operands
[1], 0);
1504 size
= nds32_byte_to_size (byte
);
1506 switch (GET_CODE (code
))
1510 => access location by using register,
1511 use "lbi / lhi / lwi" */
1512 snprintf (pattern
, sizeof (pattern
), "l%ci\t%%0, %%1", size
);
1517 /* (mem (symbol_ref X))
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
);
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
);
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
);
1542 switch (GET_CODE (XEXP (XEXP (code
, 1), 1)))
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
);
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
);
1565 switch (GET_CODE (XEXP (code
, 1)))
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
);
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
);
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
);
1595 output_asm_insn (pattern
, operands
);
1599 /* Output 32-bit load with signed extension. */
1601 nds32_output_32bit_load_s (rtx
*operands
, int byte
)
1607 code
= XEXP (operands
[1], 0);
1609 size
= nds32_byte_to_size (byte
);
1611 switch (GET_CODE (code
))
1615 => access location by using register,
1616 use "lbsi / lhsi" */
1617 snprintf (pattern
, sizeof (pattern
), "l%csi\t%%0, %%1", size
);
1622 /* (mem (symbol_ref X))
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
);
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
);
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
);
1647 switch (GET_CODE (XEXP (XEXP (code
, 1), 1)))
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
);
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
);
1670 switch (GET_CODE (XEXP (code
, 1)))
1674 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
1676 snprintf (pattern
, sizeof (pattern
), "l%cs\t%%0, %%1", size
);
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
);
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
);
1700 output_asm_insn (pattern
, operands
);
1704 /* Function to output stack push operation.
1705 We need to deal with normal stack push multiple or stack v3push. */
1707 nds32_output_stack_push (rtx par_rtx
)
1709 /* A string pattern for output_asm_insn(). */
1711 /* The operands array which will be used in output_asm_insn(). */
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
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
;
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)
1730 if (reg_mentioned_p (gen_rtx_REG (SImode
, last_argument_regno
), par_rtx
))
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
);
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
1746 if (reg_mentioned_p (gen_rtx_REG (SImode
, first_eh_data_regno
), par_rtx
))
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
);
1758 /* If we step here, we are going to do v3push or multiple push operation. */
1760 /* The v3push/v3pop instruction should only be applied on
1761 none-isr and none-variadic function. */
1763 && !nds32_isr_function_p (current_function_decl
)
1764 && (cfun
->machine
->va_args_size
== 0))
1766 /* For stack v3push:
1768 operands[1]: imm8u */
1770 /* This variable is to check if 'push25 Re,imm8u' is available. */
1773 /* Set operands[0]. */
1774 operands
[0] = gen_rtx_REG (SImode
, re_callee_saved
);
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
);
1787 /* Allocate callee saved fpr space. */
1788 if (cfun
->machine
->callee_saved_first_fpr_regno
!= SP_REGNUM
)
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
);
1796 operands
[1] = GEN_INT (0);
1800 /* Create assembly code pattern. */
1801 snprintf (pattern
, sizeof (pattern
), "push25\t%%0, %%1");
1805 /* For normal stack push multiple:
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;
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
);
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
)
1825 /* No need to generate instruction. */
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;
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" : "");
1846 /* We use output_asm_insn() to output assembly code by ourself. */
1847 output_asm_insn (pattern
, operands
);
1851 /* Function to output stack pop operation.
1852 We need to deal with normal stack pop multiple or stack v3pop. */
1854 nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED
)
1856 /* A string pattern for output_asm_insn(). */
1858 /* The operands array which will be used in output_asm_insn(). */
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
;
1868 /* We need to check if we need to push exception handling
1870 if (reg_mentioned_p (gen_rtx_REG (SImode
, first_eh_data_regno
), par_rtx
))
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
);
1882 /* If we step here, we are going to do v3pop or multiple pop operation. */
1884 /* The v3push/v3pop instruction should only be applied on
1885 none-isr and none-variadic function. */
1887 && !nds32_isr_function_p (current_function_decl
)
1888 && (cfun
->machine
->va_args_size
== 0))
1892 operands[1]: imm8u */
1894 /* This variable is to check if 'pop25 Re,imm8u' is available. */
1897 /* Set operands[0]. */
1898 operands
[0] = gen_rtx_REG (SImode
, re_callee_saved
);
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
);
1917 if (cfun
->machine
->callee_saved_first_fpr_regno
!= SP_REGNUM
)
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
);
1928 operands
[1] = GEN_INT (0);
1932 /* Create assembly code pattern. */
1933 snprintf (pattern
, sizeof (pattern
), "pop25\t%%0, %%1");
1937 /* For normal stack pop multiple:
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;
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
);
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
)
1957 /* No need to generate instruction. */
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
)
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" : "");
1978 /* We use output_asm_insn() to output assembly code by ourself. */
1979 output_asm_insn (pattern
, operands
);
1983 /* Function to output return operation. */
1985 nds32_output_return (void)
1987 /* A string pattern for output_asm_insn(). */
1989 /* The operands array which will be used in output_asm_insn(). */
1993 operands[1]: imm8u */
1994 int re_callee_saved
= cfun
->machine
->callee_saved_last_gpr_regno
;
1997 /* Set operands[0]. */
1998 operands
[0] = gen_rtx_REG (SImode
, re_callee_saved
);
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
);
2016 operands
[1] = GEN_INT (0);
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
);
2025 /* Function to generate PC relative jump table.
2026 Refer to nds32.md for more details.
2028 The following is the sample for the case that diff value
2029 can be presented in '.short' size.
2031 addi $r1, $r1, -(case_lower_bound)
2032 slti $ta, $r1, (case_number)
2033 beqz $ta, .L_skip_label
2035 la $ta, .L35 ! get jump table address
2036 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
2053 nds32_output_casesi_pc_relative (rtx
*operands
)
2058 diff_vec
= PATTERN (NEXT_INSN (as_a
<rtx_insn
*> (operands
[1])));
2060 gcc_assert (GET_CODE (diff_vec
) == ADDR_DIFF_VEC
);
2062 /* Step C: "t <-- operands[1]". */
2063 output_asm_insn ("la\t$ta, %l1", operands
);
2065 /* Get the mode of each element in the difference vector. */
2066 mode
= GET_MODE (diff_vec
);
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. */
2073 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands
);
2076 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands
);
2079 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands
);
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
);
2090 /* Step F: jump to target with register t. */
2097 /* output a float load instruction */
2099 nds32_output_float_load (rtx
*operands
)
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
))
2109 pattern
= "fl%ci\t%%0, %%1";
2113 addr_op0
= XEXP (addr
, 0);
2114 addr_op1
= XEXP (addr
, 1);
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";
2129 addr_op0
= XEXP (addr
, 0);
2130 addr_op1
= XEXP (addr
, 1);
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";
2143 if (REG_P (XEXP (addr
, 0)))
2146 pattern
= "fl%ci.bi\t%%0, %%1, 8";
2148 pattern
= "fl%ci.bi\t%%0, %%1, 4";
2155 if (REG_P (XEXP (addr
, 0)))
2158 pattern
= "fl%ci.bi\t%%0, %%1, -8";
2160 pattern
= "fl%ci.bi\t%%0, %%1, -4";
2170 sprintf (buff
, pattern
, dp
? 'd' : 's');
2171 output_asm_insn (buff
, operands
);
2175 /* output a float store instruction */
2177 nds32_output_float_store (rtx
*operands
)
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
))
2187 pattern
= "fs%ci\t%%1, %%0";
2191 addr_op0
= XEXP (addr
, 0);
2192 addr_op1
= XEXP (addr
, 1);
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";
2207 addr_op0
= XEXP (addr
, 0);
2208 addr_op1
= XEXP (addr
, 1);
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";
2221 if (REG_P (XEXP (addr
, 0)))
2224 pattern
= "fs%ci.bi\t%%1, %%0, 8";
2226 pattern
= "fs%ci.bi\t%%1, %%0, 4";
2233 if (REG_P (XEXP (addr
, 0)))
2236 pattern
= "fs%ci.bi\t%%1, %%0, -8";
2238 pattern
= "fs%ci.bi\t%%1, %%0, -4";
2248 sprintf (buff
, pattern
, dp
? 'd' : 's');
2249 output_asm_insn (buff
, operands
);
2253 /* Function to generate normal jump table. */
2255 nds32_output_casesi (rtx
*operands
)
2257 /* Step C: "t <-- operands[1]". */
2258 output_asm_insn ("la\t$ta, %l1", operands
);
2260 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
2261 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands
);
2263 /* No need to perform Step E, which is only used for
2264 pc relative jump table. */
2266 /* Step F: jump to target with register z. */
2273 /* Auxiliary functions for lwm/smw. */
2275 nds32_valid_smw_lwm_base_p (rtx op
)
2282 base_addr
= XEXP (op
, 0);
2284 if (REG_P (base_addr
))
2288 if (GET_CODE (base_addr
) == POST_INC
2289 && REG_P (XEXP (base_addr
, 0)))
2296 /* ------------------------------------------------------------------------ */
2298 nds32_output_smw_single_word (rtx
*operands
)
2304 rtx base_addr
= operands
[0];
2308 if (REG_P (XEXP (base_addr
, 0)))
2310 update_base_p
= false;
2311 base_reg
= XEXP (base_addr
, 0);
2315 update_base_p
= true;
2316 base_reg
= XEXP (XEXP (base_addr
, 0), 0);
2319 const char *update_base
= update_base_p
? "m" : "";
2321 regno
= REGNO (operands
[1]);
2323 otherops
[0] = base_reg
;
2324 otherops
[1] = operands
[1];
2328 enable4
= nds32_regno_to_enable4 (regno
);
2329 sprintf (buff
, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base
, enable4
);
2333 sprintf (buff
, "smw.bi%s\t%%1, [%%0], %%1", update_base
);
2335 output_asm_insn (buff
, otherops
);
2340 nds32_output_lmw_single_word (rtx
*operands
)
2346 rtx base_addr
= operands
[1];
2350 if (REG_P (XEXP (base_addr
, 0)))
2352 update_base_p
= false;
2353 base_reg
= XEXP (base_addr
, 0);
2357 update_base_p
= true;
2358 base_reg
= XEXP (XEXP (base_addr
, 0), 0);
2361 const char *update_base
= update_base_p
? "m" : "";
2363 regno
= REGNO (operands
[0]);
2365 otherops
[0] = operands
[0];
2366 otherops
[1] = base_reg
;
2370 enable4
= nds32_regno_to_enable4 (regno
);
2371 sprintf (buff
, "lmw.bi%s\t$sp, [%%1], $sp, %x", update_base
, enable4
);
2375 sprintf (buff
, "lmw.bi%s\t%%0, [%%1], %%0", update_base
);
2377 output_asm_insn (buff
, otherops
);
2382 nds32_expand_unaligned_load (rtx
*operands
, enum machine_mode mode
)
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. */
2389 /* The first load byte instruction is not the same. */
2390 int width
= GET_MODE_SIZE (mode
) - 1;
2394 rtx temp_reg
, temp_sub_reg
;
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:
2404 lbi temp_reg, [mem + offset]
2405 sll temp_reg, (8 * shift)
2408 lbi temp_reg, [mem + (offset + 1)]
2409 sll temp_reg, (8 * (shift + 1))
2410 ior reg0, temp_reg */
2412 temp_reg
= gen_reg_rtx (SImode
);
2413 temp_sub_reg
= gen_lowpart (QImode
, temp_reg
);
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;
2427 reg
[0] = operands
[0];
2430 for (num_reg
= (mode
== DImode
) ? 2 : 1; num_reg
> 0; num_reg
--)
2432 sub_reg
= gen_lowpart (QImode
, reg
[0]);
2433 mem
[0] = gen_rtx_MEM (QImode
, plus_constant (Pmode
, operands
[1], offset
));
2435 /* Generating the first part instructions.
2438 emit_move_insn (sub_reg
, mem
[0]);
2439 emit_insn (gen_zero_extendqisi2 (reg
[0], sub_reg
));
2443 offset
= offset
+ offset_adj
;
2447 mem
[1] = gen_rtx_MEM (QImode
, plus_constant (Pmode
,
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
));
2462 /* Using the second register to load memory information. */
2465 width
= GET_MODE_SIZE (SImode
) - 1;
2466 offset
= offset
+ offset_adj
;
2472 nds32_expand_unaligned_store (rtx
*operands
, enum machine_mode mode
)
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. */
2479 /* The first load byte instruction is not the same. */
2480 int width
= GET_MODE_SIZE (mode
) - 1;
2484 rtx temp_reg
, temp_sub_reg
;
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:
2493 srli temp_reg, reg0, (8 * shift)
2494 sbi temp_reg, [mem + offset] */
2496 temp_reg
= gen_reg_rtx (SImode
);
2497 temp_sub_reg
= gen_lowpart (QImode
, temp_reg
);
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;
2511 reg
[0] = operands
[1];
2514 for (num_reg
= (mode
== DImode
) ? 2 : 1; num_reg
> 0; num_reg
--)
2516 sub_reg
= gen_lowpart (QImode
, reg
[0]);
2517 mem
[0] = gen_rtx_MEM (QImode
, plus_constant (Pmode
, operands
[0], offset
));
2519 /* Generating the first part instructions.
2520 sbi reg0, [mem + 0] */
2521 emit_move_insn (mem
[0], sub_reg
);
2525 offset
= offset
+ offset_adj
;
2529 mem
[1] = gen_rtx_MEM (QImode
, plus_constant (Pmode
,
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
);
2542 /* Using the second register to load memory information. */
2545 width
= GET_MODE_SIZE (SImode
) - 1;
2546 offset
= offset
+ offset_adj
;
2551 /* Using multiple load/store instruction to output doubleword instruction. */
2553 nds32_output_double (rtx
*operands
, bool load_p
)
2556 int reg
= load_p
? 0 : 1;
2557 int mem
= load_p
? 1 : 0;
2559 rtx addr
= XEXP (operands
[mem
], 0);
2561 otherops
[0] = gen_rtx_REG (SImode
, REGNO (operands
[reg
]));
2562 otherops
[1] = gen_rtx_REG (SImode
, REGNO (operands
[reg
]) + 1);
2564 if (GET_CODE (addr
) == POST_INC
)
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');
2575 snprintf (pattern
, sizeof (pattern
),
2576 "%cmw.bi\t%%0, [%%2], %%1, 0", load_p
? 'l' : 's');
2580 output_asm_insn (pattern
, otherops
);
2585 nds32_output_cbranchsi4_equality_zero (rtx_insn
*insn
, rtx
*operands
)
2588 bool long_jump_p
= false;
2590 code
= GET_CODE (operands
[0]);
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
2597 we assume it is always reachable. (but check range -65500 ~ 65500)
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. */
2605 switch (get_attr_length (insn
))
2611 if (which_alternative
== 0)
2616 b<inverse_cond>zs8 .LCB0
2620 output_cond_branch_compare_zero (code
, "s8", long_jump_p
,
2624 else if (which_alternative
== 1)
2627 /* b<cond>z38 $r0, .L0
2629 b<inverse_cond>z38 $r0, .LCB0
2633 output_cond_branch_compare_zero (code
, "38", long_jump_p
,
2640 /* For which_alternative==2, it should not be here. */
2644 /* including constraints: t, l, and r */
2648 /* including constraints: t, l, and r */
2649 output_cond_branch_compare_zero (code
, "", long_jump_p
, operands
, false);
2658 nds32_output_cbranchsi4_equality_reg (rtx_insn
*insn
, rtx
*operands
)
2661 bool long_jump_p
, r5_p
;
2664 insn_length
= get_attr_length (insn
);
2666 long_jump_p
= (insn_length
== 10 || insn_length
== 8) ? true : false;
2667 r5_p
= (insn_length
== 2 || insn_length
== 8) ? true : false;
2669 code
= GET_CODE (operands
[0]);
2671 /* This register-comparison conditional branch has one form:
2672 32-bit instruction => beq/bne imm14s << 1
2675 we assume it is always reachable. (but check range -16350 ~ 16350). */
2681 output_cond_branch (code
, "", r5_p
, long_jump_p
, operands
);
2690 nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn
*insn
,
2694 bool long_jump_p
, r5_p
;
2697 insn_length
= get_attr_length (insn
);
2699 long_jump_p
= (insn_length
== 10 || insn_length
== 8) ? true : false;
2700 r5_p
= (insn_length
== 2 || insn_length
== 8) ? true : false;
2702 code
= GET_CODE (operands
[0]);
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
2708 For 32-bit case, we assume it is always reachable.
2709 (but check range -16350 ~ 16350 and -250 ~ 250). */
2715 if (which_alternative
== 2)
2719 output_cond_branch (code
, "c", r5_p
, long_jump_p
, operands
);
2725 output_cond_branch (code
, "", r5_p
, long_jump_p
, operands
);
2734 nds32_output_cbranchsi4_greater_less_zero (rtx_insn
*insn
, rtx
*operands
)
2740 insn_length
= get_attr_length (insn
);
2742 gcc_assert (insn_length
== 4 || insn_length
== 10);
2744 long_jump_p
= (insn_length
== 10) ? true : false;
2746 code
= GET_CODE (operands
[0]);
2748 /* This zero-greater-less-comparison conditional branch has one form:
2749 32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1
2751 For 32-bit case, we assume it is always reachable.
2752 (but check range -65500 ~ 65500). */
2760 output_cond_branch_compare_zero (code
, "", long_jump_p
, operands
, false);
2768 /* Return true if SYMBOL_REF X binds locally. */
2771 nds32_symbol_binds_local_p (const_rtx x
)
2773 return (SYMBOL_REF_DECL (x
)
2774 ? targetm
.binds_local_p (SYMBOL_REF_DECL (x
))
2775 : SYMBOL_REF_LOCAL_P (x
));
2779 nds32_output_call (rtx insn
, rtx
*operands
, rtx symbol
, const char *long_call
,
2780 const char *call
, bool align_p
)
2785 if (GET_CODE (symbol
) == CONST
)
2787 symbol
= XEXP (symbol
, 0);
2789 if (GET_CODE (symbol
) == PLUS
)
2790 symbol
= XEXP (symbol
, 0);
2793 gcc_assert (GET_CODE (symbol
) == SYMBOL_REF
2796 if (nds32_long_call_p (symbol
))
2797 strcpy (pattern
, long_call
);
2799 strcpy (pattern
, call
);
2802 strcat (pattern
, "\n\t.align 2");
2804 noreturn_p
= find_reg_note (insn
, REG_NORETURN
, NULL_RTX
) != NULL_RTX
;
2809 strcat (pattern
, "\n\tnop16");
2811 strcat (pattern
, "\n\tnop");
2814 output_asm_insn (pattern
, operands
);
2818 /* Spilt a doubleword instrucion to two single word instructions. */
2820 nds32_spilt_doubleword (rtx
*operands
, bool load_p
)
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);
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);
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
)
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);
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
,
2854 high_part
[mem
] = gen_frame_mem (SImode
,
2855 gen_rtx_POST_MODIFY (Pmode
, sub_mem
,
2856 gen_rtx_PLUS (Pmode
,
2860 else if (GET_CODE (sub_mem
) == POST_MODIFY
)
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);
2866 /* Extract (const) from the (post_modify (reg) (plus (reg) (const)))
2869 rtx plus_op
= XEXP (sub_mem
, 1);
2870 rtx post_val
= XEXP (plus_op
, 1);
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
,
2880 high_part
[mem
] = gen_frame_mem (SImode
, plus_constant (Pmode
,
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);
2891 /* After reload completed, we have dependent issue by low part register and
2892 higt part memory. i.e. we cannot split a sequence
2901 For store instruction we don't have a problem.
2903 When memory format is [post_modify], we need to emit high part instruction,
2904 before low part instruction.
2906 load $r0, [%r2], post_val
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
)
2913 operands
[2] = high_part
[0];
2914 operands
[3] = high_part
[1];
2915 operands
[4] = low_part
[0];
2916 operands
[5] = low_part
[1];
2920 operands
[2] = low_part
[0];
2921 operands
[3] = low_part
[1];
2922 operands
[4] = high_part
[0];
2923 operands
[5] = high_part
[1];
2927 /* Return true X is need use long call. */
2929 nds32_long_call_p (rtx symbol
)
2931 return TARGET_CMODEL_LARGE
;
2935 nds32_expand_constant (machine_mode mode
, HOST_WIDE_INT val
,
2936 rtx target
, rtx source
)
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
;
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
);
2948 HOST_WIDE_INT sign_shift_mask
= ((0xffffffffUL
2949 << (32 - clear_sign_bit_copies
))
2951 HOST_WIDE_INT zero_shift_mask
= (1 << clear_zero_bit_copies
) - 1;
2953 if (clear_sign_bit_copies
> 0 && clear_sign_bit_copies
< 17
2954 && (remainder
| sign_shift_mask
) == 0xffffffffUL
)
2956 /* Transfer AND to two shifts, example:
2957 a = b & 0x7fffffff => (b << 1) >> 1 */
2958 rtx shift
= GEN_INT (clear_sign_bit_copies
);
2960 emit_insn (gen_ashlsi3 (temp
, source
, shift
));
2961 emit_insn (gen_lshrsi3 (target
, temp
, shift
));
2963 else if (clear_zero_bit_copies
> 0 && clear_sign_bit_copies
< 17
2964 && (remainder
| zero_shift_mask
) == 0xffffffffUL
)
2966 /* Transfer AND to two shifts, example:
2967 a = b & 0xfff00000 => (b >> 20) << 20 */
2968 rtx shift
= GEN_INT (clear_zero_bit_copies
);
2970 emit_insn (gen_lshrsi3 (temp
, source
, shift
));
2971 emit_insn (gen_ashlsi3 (target
, temp
, shift
));
2975 emit_move_insn (temp
, GEN_INT (val
));
2976 emit_move_insn (target
, gen_rtx_fmt_ee (AND
, mode
, source
, temp
));