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