xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/nds32/nds32-md-auxiliary.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1 /* Auxiliary functions for output asm template or expand rtl
2    pattern of Andes NDS32 cpu for GNU compiler
3    Copyright (C) 2012-2020 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
nds32_regno_to_enable4(unsigned regno)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
nds32_byte_to_size(int byte)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
nds32_inverse_cond_code(int code)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 *
nds32_cond_code_str(int code)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
output_cond_branch(int code,const char * suffix,bool r5_p,bool long_jump_p,rtx * operands)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
output_cond_branch_compare_zero(int code,const char * suffix,bool long_jump_p,rtx * operands,bool ta_implied_p)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
nds32_split_shiftrtdi3(rtx dst,rtx src,rtx shiftamount,bool logic_shift_p)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
nds32_expand_cbranch(rtx * operands)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
nds32_expand_cstore(rtx * operands)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
nds32_expand_float_cbranch(rtx * operands)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
nds32_expand_float_cstore(rtx * operands)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
nds32_expand_movcc(rtx * operands)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
nds32_expand_float_movcc(rtx * operands)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
nds32_emit_push_fpr_callee_saved(int base_offset)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
nds32_emit_pop_fpr_callee_saved(int gpr_padding_size)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
nds32_emit_v3pop_fpr_callee_saved(int base)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
nds32_expand_extv(rtx * operands)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
nds32_expand_insv(rtx * operands)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 *
nds32_output_casesi_pc_relative(rtx * operands)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 *
nds32_output_casesi(rtx * operands)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
nds32_mem_format(rtx op)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 *
nds32_output_16bit_store(rtx * operands,int byte)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 *
nds32_output_16bit_load(rtx * operands,int byte)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 *
nds32_output_32bit_store(rtx * operands,int byte)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 *
nds32_output_32bit_load(rtx * operands,int byte)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 *
nds32_output_32bit_load_s(rtx * operands,int byte)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 *
nds32_output_stack_push(rtx par_rtx)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 *
nds32_output_stack_pop(rtx par_rtx ATTRIBUTE_UNUSED)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 *
nds32_output_return(void)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 *
nds32_output_float_load(rtx * operands)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 *
nds32_output_float_store(rtx * operands)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 *
nds32_output_smw_single_word(rtx * operands)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 *
nds32_output_smw_double_word(rtx * operands)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 *
nds32_output_lmw_single_word(rtx * operands)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
nds32_expand_unaligned_load(rtx * operands,enum machine_mode mode)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
nds32_expand_unaligned_store(rtx * operands,enum machine_mode mode)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 *
nds32_output_double(rtx * operands,bool load_p)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 *
nds32_output_cbranchsi4_equality_zero(rtx_insn * insn,rtx * operands)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 *
nds32_output_cbranchsi4_equality_reg(rtx_insn * insn,rtx * operands)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 *
nds32_output_cbranchsi4_equality_reg_or_const_int(rtx_insn * insn,rtx * operands)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 *
nds32_output_cbranchsi4_greater_less_zero(rtx_insn * insn,rtx * operands)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 *
nds32_output_unpkd8(rtx output,rtx input,rtx high_idx_rtx,rtx low_idx_rtx,bool signed_p)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
nds32_symbol_binds_local_p(const_rtx x)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 *
nds32_output_call(rtx insn,rtx * operands,rtx symbol,const char * long_call,const char * call,bool align_p)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
nds32_need_split_sms_p(rtx in0_idx0,rtx in1_idx0,rtx in0_idx1,rtx in1_idx1)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 *
nds32_output_sms(rtx in0_idx0,rtx in1_idx0,rtx in0_idx1,rtx in1_idx1)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
nds32_split_sms(rtx out,rtx in0,rtx in1,rtx in0_idx0,rtx in1_idx0,rtx in0_idx1,rtx in1_idx1)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
nds32_spilt_doubleword(rtx * operands,bool load_p)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
nds32_split_ashiftdi3(rtx dst,rtx src,rtx shiftamount)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
nds32_split_ashiftrtdi3(rtx dst,rtx src,rtx shiftamount)3351 nds32_split_ashiftrtdi3 (rtx dst, rtx src, rtx shiftamount)
3352 {
3353   nds32_split_shiftrtdi3 (dst, src, shiftamount, false);
3354 }
3355 
3356 void
nds32_split_lshiftrtdi3(rtx dst,rtx src,rtx shiftamount)3357 nds32_split_lshiftrtdi3 (rtx dst, rtx src, rtx shiftamount)
3358 {
3359   nds32_split_shiftrtdi3 (dst, src, shiftamount, true);
3360 }
3361 
3362 void
nds32_split_rotatertdi3(rtx dst,rtx src,rtx shiftamount)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
symbolic_reference_mentioned_p(rtx op)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
nds32_legitimize_pic_address(rtx x)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
nds32_expand_pic_move(rtx * operands)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
nds32_legitimize_ict_address(rtx x)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
nds32_expand_ict_move(rtx * operands)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
nds32_indirect_call_referenced_p(rtx x)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
nds32_long_call_p(rtx symbol)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
nds32_tls_referenced_p(rtx x)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
nds32_legitimize_tls_address(rtx x)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
nds32_expand_tls_move(rtx * operands)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
nds32_expand_constant(machine_mode mode,HOST_WIDE_INT val,rtx target,rtx source)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
nds32_valid_smw_lwm_base_p(rtx op)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.  */
nds32_di_high_part_subreg(rtx reg)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 
nds32_di_low_part_subreg(rtx reg)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 *
nds32_output_tls_desc(rtx * operands)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 *
nds32_output_tls_ie(rtx * operands)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 *
nds32_output_symrel(rtx * operands)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 }
3939