00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "rtl.h"
00025 #include "regs.h"
00026 #include "hard-reg-set.h"
00027 #include "real.h"
00028 #include "insn-config.h"
00029 #include "conditions.h"
00030 #include "output.h"
00031 #include "insn-attr.h"
00032 #include "tree.h"
00033 #include "function.h"
00034 #include "expr.h"
00035 #include "flags.h"
00036 #include "recog.h"
00037 #include "tm_p.h"
00038 #include "target.h"
00039 #include "target-def.h"
00040 #include "toplev.h"
00041
00042 #ifdef OSF_OS
00043 int ns32k_num_files = 0;
00044 #endif
00045
00046
00047
00048
00049
00050 unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;
00051
00052 enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
00053 {
00054 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00055 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00056 FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
00057 FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
00058 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00059 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00060 FRAME_POINTER_REG, STACK_POINTER_REG
00061 };
00062
00063 static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
00064
00065 static rtx gen_indexed_expr PARAMS ((rtx, rtx, rtx));
00066 static const char *singlemove_string PARAMS ((rtx *));
00067 static void move_tail PARAMS ((rtx[], int, int));
00068 static tree ns32k_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
00069 const struct attribute_spec ns32k_attribute_table[];
00070 static void ns32k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
00071 static void ns32k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
00072
00073
00074 #undef TARGET_ATTRIBUTE_TABLE
00075 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
00076
00077 #undef TARGET_ASM_ALIGNED_HI_OP
00078 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
00079
00080 #ifdef ENCORE_ASM
00081 #undef TARGET_ASM_ALIGNED_SI_OP
00082 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
00083 #endif
00084
00085 #undef TARGET_ASM_FUNCTION_PROLOGUE
00086 #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
00087 #undef TARGET_ASM_FUNCTION_EPILOGUE
00088 #define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue
00089
00090 struct gcc_target targetm = TARGET_INITIALIZER;
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
00131
00132 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
00133 #define ADJSP(FILE, N) \
00134 fprintf (FILE, "\tadjspd %c%d\n", IMMEDIATE_PREFIX, (N))
00135 #else
00136 #define ADJSP(FILE, N) \
00137 fprintf (FILE, "\tadjspd %d\n", (N))
00138 #endif
00139
00140 static void
00141 ns32k_output_function_prologue (file, size)
00142 FILE *file;
00143 HOST_WIDE_INT size;
00144 {
00145 register int regno, g_regs_used = 0;
00146 int used_regs_buf[8], *bufp = used_regs_buf;
00147 int used_fregs_buf[17], *fbufp = used_fregs_buf;
00148
00149 for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
00150 if (regs_ever_live[regno]
00151 && ! call_used_regs[regno])
00152 {
00153 *bufp++ = regno; g_regs_used++;
00154 }
00155 *bufp = -1;
00156
00157 for (; regno < FRAME_POINTER_REGNUM; regno++)
00158 if (regs_ever_live[regno] && !call_used_regs[regno])
00159 {
00160 *fbufp++ = regno;
00161 }
00162 *fbufp = -1;
00163
00164 bufp = used_regs_buf;
00165 if (frame_pointer_needed)
00166 fprintf (file, "\tenter [");
00167 else
00168 {
00169 if (size)
00170 ADJSP (file, size + 4);
00171 if (g_regs_used && g_regs_used > 4)
00172 fprintf (file, "\tsave [");
00173 else
00174 {
00175 while (*bufp >= 0)
00176 fprintf (file, "\tmovd r%d,tos\n", *bufp++);
00177 g_regs_used = 0;
00178 }
00179 }
00180
00181 while (*bufp >= 0)
00182 {
00183 fprintf (file, "r%d", *bufp++);
00184 if (*bufp >= 0)
00185 fputc (',', file);
00186 }
00187
00188 if (frame_pointer_needed)
00189 fprintf (file, "],%d\n", size);
00190 else if (g_regs_used)
00191 fprintf (file, "]\n");
00192
00193 fbufp = used_fregs_buf;
00194 while (*fbufp >= 0)
00195 {
00196 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
00197 fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
00198 else
00199 {
00200 fprintf (file, "\tmovl %s,tos\n",
00201 ns32k_out_reg_names[fbufp[0]]);
00202 fbufp += 2;
00203 }
00204 }
00205
00206 if (flag_pic && current_function_uses_pic_offset_table)
00207 {
00208 fprintf (file, "\tsprd sb,tos\n");
00209 if (TARGET_REGPARM)
00210 {
00211 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
00212 fprintf (file, "\tlprd sb,tos\n");
00213 }
00214 else
00215 {
00216 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
00217 fprintf (file, "\tlprd sb,r0\n");
00218 }
00219 }
00220 }
00221
00222 #else
00223
00224
00225
00226
00227 static void
00228 ns32k_output_function_prologue (file, size)
00229 FILE *file;
00230 HOST_WIDE_INT size;
00231 {
00232 register int regno, g_regs_used = 0;
00233 int used_regs_buf[8], *bufp = used_regs_buf;
00234 int used_fregs_buf[8], *fbufp = used_fregs_buf;
00235
00236 for (regno = 0; regno < 8; regno++)
00237 if (regs_ever_live[regno]
00238 && ! call_used_regs[regno])
00239 {
00240 *bufp++ = regno; g_regs_used++;
00241 }
00242 *bufp = -1;
00243
00244 for (; regno < 16; regno++)
00245 if (regs_ever_live[regno] && !call_used_regs[regno]) {
00246 *fbufp++ = regno;
00247 }
00248 *fbufp = -1;
00249
00250 bufp = used_regs_buf;
00251 if (frame_pointer_needed)
00252 fprintf (file, "\tenter ");
00253 else if (g_regs_used)
00254 fprintf (file, "\tsave ");
00255
00256 if (frame_pointer_needed || g_regs_used)
00257 {
00258 char mask = 0;
00259 while (*bufp >= 0)
00260 mask |= 1 << *bufp++;
00261 fprintf (file, "$0x%x", (int) mask & 0xff);
00262 }
00263
00264 if (frame_pointer_needed)
00265 #ifdef UTEK_ASM
00266 fprintf (file, ",$%d\n", size);
00267 #else
00268 fprintf (file, ",%d\n", size);
00269 #endif
00270 else if (g_regs_used)
00271 fprintf (file, "\n");
00272
00273 fbufp = used_fregs_buf;
00274 while (*fbufp >= 0)
00275 {
00276 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
00277 fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
00278 else
00279 {
00280 fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
00281 fbufp += 2;
00282 }
00283 }
00284 }
00285
00286 #endif
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
00319
00320 static void
00321 ns32k_output_function_epilogue (file, size)
00322 FILE *file;
00323 HOST_WIDE_INT size;
00324 {
00325 register int regno, g_regs_used = 0, f_regs_used = 0;
00326 int used_regs_buf[8], *bufp = used_regs_buf;
00327 int used_fregs_buf[17], *fbufp = used_fregs_buf;
00328
00329 if (flag_pic && current_function_uses_pic_offset_table)
00330 fprintf (file, "\tlprd sb,tos\n");
00331
00332 *fbufp++ = -2;
00333 for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)
00334 if (regs_ever_live[regno] && !call_used_regs[regno])
00335 {
00336 *fbufp++ = regno; f_regs_used++;
00337 }
00338 fbufp--;
00339
00340 for (regno = 0; regno < F0_REGNUM; regno++)
00341 if (regs_ever_live[regno]
00342 && ! call_used_regs[regno])
00343 {
00344 *bufp++ = regno; g_regs_used++;
00345 }
00346
00347 while (fbufp > used_fregs_buf)
00348 {
00349 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
00350 {
00351 fprintf (file, "\tmovl tos,%s\n",
00352 ns32k_out_reg_names[fbufp[-1]]);
00353 fbufp -= 2;
00354 }
00355 else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
00356 }
00357
00358 if (frame_pointer_needed)
00359 fprintf (file, "\texit [");
00360 else
00361 {
00362 if (g_regs_used && g_regs_used > 4)
00363 fprintf (file, "\trestore [");
00364 else
00365 {
00366 while (bufp > used_regs_buf)
00367 fprintf (file, "\tmovd tos,r%d\n", *--bufp);
00368 g_regs_used = 0;
00369 }
00370 }
00371
00372 while (bufp > used_regs_buf)
00373 {
00374 fprintf (file, "r%d", *--bufp);
00375 if (bufp > used_regs_buf)
00376 fputc (',', file);
00377 }
00378
00379 if (g_regs_used || frame_pointer_needed)
00380 fprintf (file, "]\n");
00381
00382 if (size && !frame_pointer_needed)
00383 ADJSP (file, -(size + 4));
00384
00385 if (current_function_pops_args)
00386 fprintf (file, "\tret %d\n", current_function_pops_args);
00387 else
00388 fprintf (file, "\tret 0\n");
00389 }
00390
00391 #else
00392
00393
00394
00395
00396 static void
00397 ns32k_output_function_epilogue (file, size)
00398 FILE *file;
00399 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
00400 {
00401 register int regno, g_regs_used = 0, f_regs_used = 0;
00402 int used_regs_buf[8], *bufp = used_regs_buf;
00403 int used_fregs_buf[8], *fbufp = used_fregs_buf;
00404
00405 *fbufp++ = -2;
00406 for (regno = 8; regno < 16; regno++)
00407 if (regs_ever_live[regno] && !call_used_regs[regno]) {
00408 *fbufp++ = regno; f_regs_used++;
00409 }
00410 fbufp--;
00411
00412 for (regno = 0; regno < 8; regno++)
00413 if (regs_ever_live[regno]
00414 && ! call_used_regs[regno])
00415 {
00416 *bufp++ = regno; g_regs_used++;
00417 }
00418
00419 while (fbufp > used_fregs_buf)
00420 {
00421 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
00422 {
00423 fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);
00424 fbufp -= 2;
00425 }
00426 else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);
00427 }
00428
00429 if (frame_pointer_needed)
00430 fprintf (file, "\texit ");
00431 else if (g_regs_used)
00432 fprintf (file, "\trestore ");
00433
00434 if (g_regs_used || frame_pointer_needed)
00435 {
00436 char mask = 0;
00437
00438 while (bufp > used_regs_buf)
00439 {
00440
00441 mask |= 1 << *--bufp;
00442 }
00443 fprintf (file, "$0x%x\n", (int) mask & 0xff);
00444 }
00445
00446 #ifdef UTEK_ASM
00447 if (current_function_pops_args)
00448 fprintf (file, "\tret $%d\n", current_function_pops_args);
00449 else
00450 fprintf (file, "\tret $0\n");
00451 #else
00452 if (current_function_pops_args)
00453 fprintf (file, "\tret %d\n", current_function_pops_args);
00454 else
00455 fprintf (file, "\tret 0\n");
00456 #endif
00457 }
00458
00459 #endif
00460
00461
00462 int
00463 hard_regno_mode_ok (regno, mode)
00464 int regno;
00465 enum machine_mode mode;
00466 {
00467 int size = GET_MODE_UNIT_SIZE (mode);
00468
00469 if (FLOAT_MODE_P (mode))
00470 {
00471 if (size == UNITS_PER_WORD && regno < L1_REGNUM)
00472 return 1;
00473 if (size == UNITS_PER_WORD * 2
00474 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
00475 return 1;
00476 return 0;
00477 }
00478 if (size == UNITS_PER_WORD * 2
00479 && (regno & 1) == 0 && regno < F0_REGNUM)
00480 return 1;
00481 if (size <= UNITS_PER_WORD
00482 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
00483 || regno == STACK_POINTER_REGNUM))
00484 return 1;
00485 return 0;
00486 }
00487
00488 int register_move_cost (CLASS1, CLASS2)
00489 enum reg_class CLASS1;
00490 enum reg_class CLASS2;
00491 {
00492 if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
00493 return 2;
00494 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
00495 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
00496 return 8;
00497 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
00498 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
00499 return 6;
00500 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
00501 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
00502 return 6;
00503 return 2;
00504 }
00505
00506 #if 0
00507
00508
00509 int secondary_memory_needed (CLASS1, CLASS2, M)
00510 enum reg_class CLASS1;
00511 enum reg_class CLASS2;
00512 enum machine_mode M;
00513 {
00514 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
00515 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
00516 return ret;
00517 }
00518 #endif
00519
00520
00521
00522
00523
00524
00525 int
00526 calc_address_cost (operand)
00527 rtx operand;
00528 {
00529 int i;
00530 int cost = 0;
00531 if (GET_CODE (operand) == MEM)
00532 cost += 3;
00533 if (GET_CODE (operand) == MULT)
00534 cost += 2;
00535 switch (GET_CODE (operand))
00536 {
00537 case REG:
00538 cost += 1;
00539 break;
00540 case POST_DEC:
00541 case PRE_DEC:
00542 break;
00543 case CONST_INT:
00544 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
00545 break;
00546 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
00547 {
00548 cost +=1;
00549 break;
00550 }
00551 case CONST:
00552 case LABEL_REF:
00553 case SYMBOL_REF:
00554 cost +=3;
00555 break;
00556 case CONST_DOUBLE:
00557 cost += 5;
00558 break;
00559 case MEM:
00560 cost += calc_address_cost (XEXP (operand, 0));
00561 break;
00562 case MULT:
00563 case PLUS:
00564 for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
00565 {
00566 cost += calc_address_cost (XEXP (operand, i));
00567 }
00568 default:
00569 break;
00570 }
00571 return cost;
00572 }
00573
00574
00575
00576
00577
00578 enum reg_class
00579 secondary_reload_class (class, mode, in)
00580 enum reg_class class;
00581 enum machine_mode mode ATTRIBUTE_UNUSED;
00582 rtx in;
00583 {
00584 int regno = true_regnum (in);
00585
00586 if (regno >= FIRST_PSEUDO_REGISTER)
00587 regno = -1;
00588
00589 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
00590 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
00591 return GENERAL_REGS;
00592 else
00593 return NO_REGS;
00594 }
00595
00596
00597
00598
00599
00600
00601 static rtx
00602 gen_indexed_expr (base, index, scale)
00603 rtx base, index, scale;
00604 {
00605 rtx addr;
00606
00607
00608
00609 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
00610 base = gen_rtx_MEM (SImode, base);
00611 addr = gen_rtx_MULT (SImode, index,
00612 GEN_INT (1 << INTVAL (scale)));
00613 addr = gen_rtx_PLUS (SImode, base, addr);
00614 return addr;
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624 void
00625 split_di (operands, num, lo_half, hi_half)
00626 rtx operands[];
00627 int num;
00628 rtx lo_half[], hi_half[];
00629 {
00630 while (num--)
00631 {
00632 if (GET_CODE (operands[num]) == REG)
00633 {
00634 lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
00635 hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
00636 }
00637 else if (CONSTANT_P (operands[num]))
00638 {
00639 split_double (operands[num], &lo_half[num], &hi_half[num]);
00640 }
00641 else if (offsettable_memref_p (operands[num]))
00642 {
00643 lo_half[num] = operands[num];
00644 hi_half[num] = adjust_address (operands[num], SImode, 4);
00645 }
00646 else
00647 abort ();
00648 }
00649 }
00650
00651
00652
00653
00654 static const char *
00655 singlemove_string (operands)
00656 rtx *operands;
00657 {
00658 if (GET_CODE (operands[1]) == CONST_INT
00659 && INTVAL (operands[1]) <= 7
00660 && INTVAL (operands[1]) >= -8)
00661 return "movqd %1,%0";
00662 return "movd %1,%0";
00663 }
00664
00665 const char *
00666 output_move_double (operands)
00667 rtx *operands;
00668 {
00669 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
00670 rtx latehalf[2];
00671
00672
00673
00674 if (REG_P (operands[0]))
00675 optype0 = REGOP;
00676 else if (offsettable_memref_p (operands[0]))
00677 optype0 = OFFSOP;
00678 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
00679 optype0 = PUSHOP;
00680 else
00681 optype0 = RNDOP;
00682
00683 if (REG_P (operands[1]))
00684 optype1 = REGOP;
00685 else if (CONSTANT_P (operands[1])
00686 || GET_CODE (operands[1]) == CONST_DOUBLE)
00687 optype1 = CNSTOP;
00688 else if (offsettable_memref_p (operands[1]))
00689 optype1 = OFFSOP;
00690 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
00691 optype1 = PUSHOP;
00692 else
00693 optype1 = RNDOP;
00694
00695
00696
00697
00698
00699 if (optype0 == RNDOP || optype1 == RNDOP)
00700 abort ();
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711 if (optype0 == REGOP)
00712 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
00713 else if (optype0 == OFFSOP)
00714 latehalf[0] = adjust_address (operands[0], SImode, 4);
00715 else
00716 latehalf[0] = operands[0];
00717
00718 if (optype1 == REGOP)
00719 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
00720 else if (optype1 == OFFSOP)
00721 latehalf[1] = adjust_address (operands[1], SImode, 4);
00722 else if (optype1 == CNSTOP)
00723 split_double (operands[1], &operands[1], &latehalf[1]);
00724 else
00725 latehalf[1] = operands[1];
00726
00727
00728
00729
00730
00731 if (optype0 == PUSHOP
00732 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
00733 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
00734 operands[1] = latehalf[1];
00735
00736
00737
00738 else if (optype0 == PUSHOP || optype1 == PUSHOP)
00739 {
00740 output_asm_insn (singlemove_string (latehalf), latehalf);
00741 return singlemove_string (operands);
00742 }
00743
00744
00745
00746
00747
00748 if (optype0 == REGOP && optype1 == REGOP
00749 && REGNO (operands[0]) == REGNO (latehalf[1]))
00750 {
00751
00752 output_asm_insn (singlemove_string (latehalf), latehalf);
00753
00754 return singlemove_string (operands);
00755 }
00756
00757 else if (optype0 == REGOP && optype1 != REGOP
00758 && reg_overlap_mentioned_p (operands[0], operands[1]))
00759 {
00760 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
00761 && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
00762 {
00763
00764
00765
00766 rtx xops[2];
00767 xops[0] = XEXP (operands[1], 0);
00768 xops[1] = operands[0];
00769 output_asm_insn ("addr %a0,%1", xops);
00770 operands[1] = gen_rtx_MEM (DImode, operands[0]);
00771 latehalf[1] = adjust_address (operands[1], SImode, 4);
00772
00773 output_asm_insn (singlemove_string (latehalf), latehalf);
00774
00775 return singlemove_string (operands);
00776 }
00777 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
00778 {
00779
00780 output_asm_insn (singlemove_string (latehalf), latehalf);
00781
00782 return singlemove_string (operands);
00783 }
00784 }
00785
00786
00787
00788 output_asm_insn (singlemove_string (operands), operands);
00789
00790 operands[0] = latehalf[0];
00791 operands[1] = latehalf[1];
00792 return singlemove_string (operands);
00793 }
00794
00795
00796 #define MAX_UNALIGNED_COPY (32)
00797
00798
00799
00800
00801
00802
00803
00804 static void
00805 move_tail (operands, bytes, offset)
00806 rtx operands[];
00807 int bytes;
00808 int offset;
00809 {
00810 if (bytes & 2)
00811 {
00812 emit_move_insn (adjust_address (operands[0], HImode, offset),
00813 adjust_address (operands[1], HImode, offset));
00814 offset += 2;
00815 }
00816 if (bytes & 1)
00817 emit_move_insn (adjust_address (operands[0], QImode, offset),
00818 adjust_address (operands[1], QImode, offset));
00819 }
00820
00821 void
00822 expand_block_move (operands)
00823 rtx operands[];
00824 {
00825 rtx bytes_rtx = operands[2];
00826 rtx align_rtx = operands[3];
00827 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
00828 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
00829 int align = INTVAL (align_rtx);
00830 rtx src_reg = gen_rtx_REG (Pmode, 1);
00831 rtx dest_reg = gen_rtx_REG (Pmode, 2);
00832 rtx count_reg = gen_rtx_REG (SImode, 0);
00833
00834 if (constp && bytes <= 0)
00835 return;
00836
00837 if (constp && bytes < 20)
00838 {
00839 int words = bytes >> 2;
00840
00841 if (words)
00842 {
00843 if (words < 3 || flag_unroll_loops)
00844 {
00845 int offset = 0;
00846
00847 for (; words; words--, offset += 4)
00848 emit_move_insn (adjust_address (operands[0], SImode, offset),
00849 adjust_address (operands[1], SImode, offset));
00850 }
00851 else
00852 {
00853
00854
00855
00856
00857 rtx src, dest;
00858 dest = copy_addr_to_reg (XEXP (operands[0], 0));
00859 src = copy_addr_to_reg (XEXP (operands[1], 0));
00860
00861 emit_insn (gen_movstrsi2(dest, src, GEN_INT (words)));
00862 }
00863 }
00864 move_tail (operands, bytes & 3, bytes & ~3);
00865 return;
00866 }
00867
00868 if (align > UNITS_PER_WORD)
00869 align = UNITS_PER_WORD;
00870
00871
00872 emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
00873 emit_move_insn (dest_reg, XEXP (operands[0], 0));
00874 operands[0] = gen_rtx_MEM (SImode, dest_reg);
00875 emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
00876 emit_move_insn (src_reg, XEXP (operands[1], 0));
00877 operands[1] = gen_rtx_MEM (SImode, src_reg);
00878 emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
00879
00880 if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
00881 {
00882
00883
00884
00885 if (bytes >> 2)
00886 {
00887 emit_move_insn (count_reg, GEN_INT (bytes >> 2));
00888 emit_insn (gen_movstrsi1 (GEN_INT (4)));
00889 }
00890
00891 move_tail (operands, bytes & 3, 0);
00892 }
00893 else if (align == UNITS_PER_WORD)
00894 {
00895
00896 emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT (2)));
00897 emit_insn (gen_movstrsi1 (GEN_INT (4)));
00898 if (constp)
00899 {
00900 move_tail (operands, bytes & 3, 0);
00901 }
00902 else
00903 {
00904
00905 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
00906 emit_insn (gen_movstrsi1 (const1_rtx));
00907 }
00908 }
00909 else
00910 {
00911
00912
00913
00914 rtx aligned_label = gen_label_rtx ();
00915 rtx bytes_reg;
00916
00917 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
00918 if (!constp)
00919 {
00920
00921
00922
00923
00924 emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
00925 emit_jump_insn (gen_blt (aligned_label));
00926 }
00927
00928
00929 emit_insn (gen_negsi2 (count_reg, src_reg));
00930 emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
00931 emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
00932 emit_insn (gen_movstrsi1 (const1_rtx));
00933 if (!constp)
00934 emit_label (aligned_label);
00935
00936
00937 emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT (2)));
00938 emit_insn (gen_movstrsi1 (GEN_INT (4)));
00939
00940
00941 emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
00942 emit_insn (gen_movstrsi1 (const1_rtx));
00943 }
00944 }
00945
00946
00947
00948
00949 int
00950 global_symbolic_reference_mentioned_p (op, f)
00951 rtx op;
00952 int f;
00953 {
00954 register const char *fmt;
00955 register int i;
00956
00957 if (GET_CODE (op) == SYMBOL_REF)
00958 {
00959 if (! SYMBOL_REF_FLAG (op))
00960 return 1;
00961 else
00962 return 0;
00963 }
00964 else if (f && GET_CODE (op) != CONST)
00965 return 0;
00966
00967 fmt = GET_RTX_FORMAT (GET_CODE (op));
00968 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
00969 {
00970 if (fmt[i] == 'E')
00971 {
00972 register int j;
00973
00974 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
00975 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
00976 return 1;
00977 }
00978 else if (fmt[i] == 'e'
00979 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
00980 return 1;
00981 }
00982
00983 return 0;
00984 }
00985
00986
00987
00988
00989 int
00990 symbolic_reference_mentioned_p (op)
00991 rtx op;
00992 {
00993 register const char *fmt;
00994 register int i;
00995
00996 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
00997 return 1;
00998
00999 fmt = GET_RTX_FORMAT (GET_CODE (op));
01000 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
01001 {
01002 if (fmt[i] == 'E')
01003 {
01004 register int j;
01005
01006 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
01007 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
01008 return 1;
01009 }
01010 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
01011 return 1;
01012 }
01013
01014 return 0;
01015 }
01016
01017
01018
01019 const struct attribute_spec ns32k_attribute_table[] =
01020 {
01021
01022
01023
01024 { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
01025
01026 { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
01027 { NULL, 0, 0, false, false, false, NULL }
01028 };
01029
01030
01031
01032 static tree
01033 ns32k_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
01034 tree *node;
01035 tree name;
01036 tree args ATTRIBUTE_UNUSED;
01037 int flags ATTRIBUTE_UNUSED;
01038 bool *no_add_attrs;
01039 {
01040 if (TREE_CODE (*node) != FUNCTION_TYPE
01041 && TREE_CODE (*node) != FIELD_DECL
01042 && TREE_CODE (*node) != TYPE_DECL)
01043 {
01044 warning ("`%s' attribute only applies to functions",
01045 IDENTIFIER_POINTER (name));
01046 *no_add_attrs = true;
01047 }
01048
01049 return NULL_TREE;
01050 }
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070 int
01071 ns32k_return_pops_args (fundecl, funtype, size)
01072 tree fundecl ATTRIBUTE_UNUSED;
01073 tree funtype;
01074 int size;
01075 {
01076 int rtd = TARGET_RTD;
01077
01078 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
01079 return rtd ? size : 0;
01080
01081
01082 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
01083 return 0;
01084
01085
01086 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
01087 rtd = 1;
01088
01089 if (rtd)
01090 {
01091 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
01092 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
01093 return size;
01094 }
01095
01096 return 0;
01097 }
01098
01099
01100
01101
01102
01103
01104 void
01105 print_operand (file, x, code)
01106 FILE *file;
01107 rtx x;
01108 int code;
01109 {
01110 if (code == '$')
01111 PUT_IMMEDIATE_PREFIX (file);
01112 else if (code == '?')
01113 PUT_EXTERNAL_PREFIX (file);
01114 else if (GET_CODE (x) == REG)
01115 fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
01116 else if (GET_CODE (x) == MEM)
01117 {
01118 output_address (XEXP (x, 0));
01119 }
01120 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
01121 {
01122 if (GET_MODE (x) == DFmode)
01123 {
01124 union { double d; int i[2]; } u;
01125 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
01126 PUT_IMMEDIATE_PREFIX (file);
01127 #ifdef SEQUENT_ASM
01128
01129 fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
01130 #else
01131 #ifdef ENCORE_ASM
01132 fprintf (file, "0f%.20e", u.d);
01133 #else
01134 fprintf (file, "0d%.20e", u.d);
01135 #endif
01136 #endif
01137 }
01138 else
01139 {
01140 union { double d; int i[2]; } u;
01141 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
01142 PUT_IMMEDIATE_PREFIX (file);
01143 #ifdef SEQUENT_ASM
01144
01145
01146 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
01147 abort ();
01148 #endif
01149 {
01150 union { float f; long l; } uu;
01151 uu.f = u.d;
01152 fprintf (file, "0Fx%08lx", uu.l);
01153 }
01154 #else
01155 fprintf (file, "0f%.20e", u.d);
01156 #endif
01157 }
01158 }
01159 else
01160 {
01161 if (flag_pic
01162 && GET_CODE (x) == CONST
01163 && symbolic_reference_mentioned_p (x))
01164 {
01165 fprintf (stderr, "illegal constant for pic-mode: \n");
01166 print_rtl (stderr, x);
01167 fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
01168 GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
01169 abort ();
01170 }
01171 else if (flag_pic
01172 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
01173 {
01174 output_addr_const (file, x);
01175 fprintf (file, "(sb)");
01176 }
01177 else
01178 {
01179 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
01180 if (GET_CODE (x) == CONST_INT)
01181 #endif
01182 PUT_IMMEDIATE_PREFIX (file);
01183 output_addr_const (file, x);
01184 }
01185 }
01186 }
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197 void
01198 print_operand_address (file, addr)
01199 register FILE *file;
01200 register rtx addr;
01201 {
01202 static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
01203 rtx offset, base, indexexp, tmp;
01204 int scale;
01205 extern int flag_pic;
01206
01207 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
01208 {
01209 fprintf (file, "tos");
01210 return;
01211 }
01212
01213 offset = NULL;
01214 base = NULL;
01215 indexexp = NULL;
01216 while (addr != NULL)
01217 {
01218 if (GET_CODE (addr) == PLUS)
01219 {
01220 if (GET_CODE (XEXP (addr, 0)) == PLUS)
01221 {
01222 tmp = XEXP (addr, 1);
01223 addr = XEXP (addr, 0);
01224 }
01225 else
01226 {
01227 tmp = XEXP (addr,0);
01228 addr = XEXP (addr,1);
01229 }
01230 }
01231 else
01232 {
01233 tmp = addr;
01234 addr = NULL;
01235 }
01236 switch (GET_CODE (tmp))
01237 {
01238 case PLUS:
01239 abort ();
01240 case MEM:
01241 if (base)
01242 {
01243 indexexp = base;
01244 base = tmp;
01245 }
01246 else
01247 base = tmp;
01248 break;
01249 case REG:
01250 if (REGNO (tmp) < F0_REGNUM)
01251 if (base)
01252 {
01253 indexexp = tmp;
01254 }
01255 else
01256 base = tmp;
01257 else
01258 if (base)
01259 {
01260 indexexp = base;
01261 base = tmp;
01262 }
01263 else
01264 base = tmp;
01265 break;
01266 case MULT:
01267 indexexp = tmp;
01268 break;
01269 case SYMBOL_REF:
01270 if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
01271 && ! SYMBOL_REF_FLAG (tmp))
01272 {
01273 if (base)
01274 {
01275 if (indexexp)
01276 abort ();
01277 indexexp = base;
01278 }
01279 base = tmp;
01280 break;
01281 }
01282 case CONST:
01283 if (flag_pic && GET_CODE (tmp) == CONST)
01284 {
01285 rtx sym, off, tmp1;
01286 tmp1 = XEXP (tmp,0);
01287 if (GET_CODE (tmp1) != PLUS)
01288 abort ();
01289
01290 sym = XEXP (tmp1,0);
01291 if (GET_CODE (sym) != SYMBOL_REF)
01292 {
01293 off = sym;
01294 sym = XEXP (tmp1,1);
01295 }
01296 else
01297 off = XEXP (tmp1,1);
01298 if (GET_CODE (sym) == SYMBOL_REF)
01299 {
01300 if (GET_CODE (off) != CONST_INT)
01301 abort ();
01302
01303 if (CONSTANT_POOL_ADDRESS_P (sym)
01304 || SYMBOL_REF_FLAG (sym))
01305 {
01306 SYMBOL_REF_FLAG (tmp) = 1;
01307 }
01308 else
01309 {
01310 if (base)
01311 {
01312 if (indexexp)
01313 abort ();
01314
01315 indexexp = base;
01316 }
01317
01318 if (offset != 0)
01319 abort ();
01320
01321 base = sym;
01322 offset = off;
01323 break;
01324 }
01325 }
01326 }
01327 case CONST_INT:
01328 case LABEL_REF:
01329 if (offset)
01330 offset = gen_rtx_PLUS (SImode, tmp, offset);
01331 else
01332 offset = tmp;
01333 break;
01334 default:
01335 abort ();
01336 }
01337 }
01338 if (! offset)
01339 offset = const0_rtx;
01340
01341 if (base
01342 #ifndef INDEX_RATHER_THAN_BASE
01343 && (flag_pic || TARGET_HIMEM)
01344 && GET_CODE (base) != SYMBOL_REF
01345 && GET_CODE (offset) != CONST_INT
01346 #else
01347
01348 #endif
01349 && !indexexp && GET_CODE (base) == REG
01350 && REG_OK_FOR_INDEX_P (base))
01351 {
01352 indexexp = base;
01353 base = NULL;
01354 }
01355
01356
01357 #ifndef BASE_REG_NEEDED
01358 if (! base)
01359 {
01360 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
01361 if (GET_CODE (offset) == CONST_INT)
01362 #endif
01363 PUT_ABSOLUTE_PREFIX (file);
01364 }
01365 #endif
01366
01367 output_addr_const (file, offset);
01368 if (base)
01369 switch (GET_CODE (base))
01370 {
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380 case REG:
01381 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
01382 break;
01383 case SYMBOL_REF:
01384 if (! flag_pic)
01385 abort ();
01386
01387 fprintf (file, "(");
01388 output_addr_const (file, base);
01389 fprintf (file, "(sb))");
01390 break;
01391 case MEM:
01392 addr = XEXP (base,0);
01393 base = NULL;
01394 offset = NULL;
01395 while (addr != NULL)
01396 {
01397 if (GET_CODE (addr) == PLUS)
01398 {
01399 if (GET_CODE (XEXP (addr, 0)) == PLUS)
01400 {
01401 tmp = XEXP (addr, 1);
01402 addr = XEXP (addr, 0);
01403 }
01404 else
01405 {
01406 tmp = XEXP (addr, 0);
01407 addr = XEXP (addr, 1);
01408 }
01409 }
01410 else
01411 {
01412 tmp = addr;
01413 addr = NULL;
01414 }
01415 switch (GET_CODE (tmp))
01416 {
01417 case REG:
01418 base = tmp;
01419 break;
01420 case CONST:
01421 case CONST_INT:
01422 case SYMBOL_REF:
01423 case LABEL_REF:
01424 if (offset)
01425 offset = gen_rtx_PLUS (SImode, tmp, offset);
01426 else
01427 offset = tmp;
01428 break;
01429 default:
01430 abort ();
01431 }
01432 }
01433 if (! offset)
01434 offset = const0_rtx;
01435 fprintf (file, "(");
01436 output_addr_const (file, offset);
01437 if (base)
01438 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
01439 else if (TARGET_SB)
01440 fprintf (file, "(sb)");
01441 else
01442 abort ();
01443 fprintf (file, ")");
01444 break;
01445 default:
01446 abort ();
01447 }
01448 #ifdef PC_RELATIVE
01449 else if (GET_CODE (offset) != CONST_INT)
01450 fprintf (file, "(pc)");
01451 #ifdef BASE_REG_NEEDED
01452 else if (TARGET_SB)
01453 fprintf (file, "(sb)");
01454 else
01455 abort ();
01456 #endif
01457 #endif
01458
01459
01460 if (indexexp)
01461 {
01462 if (GET_CODE (indexexp) == MULT)
01463 {
01464 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
01465 indexexp = XEXP (indexexp, 0);
01466 }
01467 else
01468 scale = 0;
01469 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
01470 abort ();
01471
01472 #ifdef UTEK_ASM
01473 fprintf (file, "[%c`%s]",
01474 scales[scale],
01475 ns32k_out_reg_names[REGNO (indexexp)]);
01476 #else
01477 fprintf (file, "[%s:%c]",
01478 ns32k_out_reg_names[REGNO (indexexp)],
01479 scales[scale]);
01480 #endif
01481 }
01482 }
01483
01484
01485
01486
01487 const char *
01488 output_shift_insn (operands)
01489 rtx *operands;
01490 {
01491 if (GET_CODE (operands[2]) == CONST_INT
01492 && INTVAL (operands[2]) > 0
01493 && INTVAL (operands[2]) <= 3)
01494 {
01495 if (GET_CODE (operands[0]) == REG)
01496 {
01497 if (GET_CODE (operands[1]) == REG)
01498 {
01499 if (REGNO (operands[0]) == REGNO (operands[1]))
01500 {
01501 if (operands[2] == const1_rtx)
01502 return "addd %0,%0";
01503 else if (INTVAL (operands[2]) == 2)
01504 return "addd %0,%0\n\taddd %0,%0";
01505 }
01506 if (operands[2] == const1_rtx)
01507 return "movd %1,%0\n\taddd %0,%0";
01508
01509 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
01510 return "addr %a1,%0";
01511 }
01512 if (operands[2] == const1_rtx)
01513 return "movd %1,%0\n\taddd %0,%0";
01514 }
01515 else if (GET_CODE (operands[1]) == REG)
01516 {
01517 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
01518 return "addr %a1,%0";
01519 }
01520 else if (INTVAL (operands[2]) == 1
01521 && GET_CODE (operands[1]) == MEM
01522 && rtx_equal_p (operands [0], operands[1]))
01523 {
01524 rtx temp = XEXP (operands[1], 0);
01525
01526 if (GET_CODE (temp) == REG
01527 || (GET_CODE (temp) == PLUS
01528 && GET_CODE (XEXP (temp, 0)) == REG
01529 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
01530 return "addd %0,%0";
01531 }
01532 else return "ashd %2,%0";
01533 }
01534 return "ashd %2,%0";
01535 }
01536
01537 const char *
01538 output_move_dconst (n, s)
01539 int n;
01540 const char *s;
01541 {
01542 static char r[32];
01543
01544 if (n > -9 && n < 8)
01545 strcpy (r, "movqd ");
01546 else if (n > 0 && n < 256)
01547 strcpy (r, "movzbd ");
01548 else if (n > 0 && n < 65536)
01549 strcpy (r, "movzwd ");
01550 else if (n < 0 && n > -129)
01551 strcpy (r, "movxbd ");
01552 else if (n < 0 && n > -32769)
01553 strcpy (r, "movxwd ");
01554 else
01555 strcpy (r, "movd ");
01556 strcat (r, s);
01557 return r;
01558 }