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 "coretypes.h"
00025 #include "tm.h"
00026 #include "rtl.h"
00027 #include "regs.h"
00028 #include "hard-reg-set.h"
00029 #include "real.h"
00030 #include "insn-config.h"
00031 #include "conditions.h"
00032 #include "insn-attr.h"
00033 #include "recog.h"
00034 #include "toplev.h"
00035 #include "output.h"
00036 #include "integrate.h"
00037 #include "tree.h"
00038 #include "function.h"
00039 #include "expr.h"
00040 #include "optabs.h"
00041 #include "libfuncs.h"
00042 #include "flags.h"
00043 #include "tm_p.h"
00044 #include "ggc.h"
00045 #include "insn-flags.h"
00046 #include "obstack.h"
00047 #include "except.h"
00048 #include "target.h"
00049 #include "target-def.h"
00050 #include "basic-block.h"
00051
00052
00053 #define FP_MASK (1 << (GPR_FP))
00054
00055
00056 #define LINK_MASK (1 << (GPR_LINK))
00057
00058
00059 #define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
00060
00061
00062
00063 struct machine_function GTY(())
00064 {
00065
00066 int ra_needs_full_frame;
00067 struct rtx_def * eh_stack_adjust;
00068 int interrupt_handler;
00069 int has_loops;
00070 };
00071
00072
00073
00074 struct rtx_def * mt_compare_op0;
00075 struct rtx_def * mt_compare_op1;
00076
00077
00078 struct mt_frame_info current_frame_info;
00079
00080
00081 struct mt_frame_info zero_frame_info;
00082
00083
00084 struct rtx_def * mt_ucmpsi3_libcall;
00085
00086 static int mt_flag_delayed_branch;
00087
00088
00089 static rtx
00090 mt_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED,
00091 int incoming ATTRIBUTE_UNUSED)
00092 {
00093 return gen_rtx_REG (Pmode, RETVAL_REGNUM);
00094 }
00095
00096
00097 rtx
00098 mt_return_addr_rtx (int count)
00099 {
00100 if (count != 0)
00101 return NULL_RTX;
00102
00103 return get_hard_reg_initial_val (Pmode, GPR_LINK);
00104 }
00105
00106
00107
00108
00109 static int mt_nops_required = 0;
00110 static const char * mt_nop_reasons = "";
00111
00112
00113 const char *
00114 mt_asm_output_opcode (FILE *f ATTRIBUTE_UNUSED, const char *ptr)
00115 {
00116 if (mt_nops_required)
00117 fprintf (f, ";# need %d nops because of %s\n\t",
00118 mt_nops_required, mt_nop_reasons);
00119
00120 while (mt_nops_required)
00121 {
00122 fprintf (f, "nop\n\t");
00123 -- mt_nops_required;
00124 }
00125
00126 return ptr;
00127 }
00128
00129
00130
00131 static enum attr_type
00132 mt_get_attr_type (rtx complete_insn)
00133 {
00134 rtx insn = PATTERN (complete_insn);
00135
00136 if (JUMP_P (complete_insn))
00137 return TYPE_BRANCH;
00138 if (CALL_P (complete_insn))
00139 return TYPE_BRANCH;
00140
00141 if (GET_CODE (insn) != SET)
00142 return TYPE_ARITH;
00143
00144 if (SET_DEST (insn) == pc_rtx)
00145 return TYPE_BRANCH;
00146
00147 if (GET_CODE (SET_DEST (insn)) == MEM)
00148 return TYPE_STORE;
00149
00150 if (GET_CODE (SET_SRC (insn)) == MEM)
00151 return TYPE_LOAD;
00152
00153 return TYPE_ARITH;
00154 }
00155
00156
00157
00158 static void
00159 insn_dependent_p_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
00160 {
00161 rtx * pinsn = (rtx *) data;
00162
00163 if (*pinsn && reg_mentioned_p (x, *pinsn))
00164 *pinsn = NULL_RTX;
00165 }
00166
00167
00168
00169
00170 static bool
00171 insn_dependent_p (rtx x, rtx y)
00172 {
00173 rtx tmp;
00174
00175 if (! INSN_P (x) || ! INSN_P (y))
00176 return 0;
00177
00178 tmp = PATTERN (y);
00179 note_stores (PATTERN (x), insn_dependent_p_1, &tmp);
00180 if (tmp == NULL_RTX)
00181 return true;
00182
00183 tmp = PATTERN (x);
00184 note_stores (PATTERN (y), insn_dependent_p_1, &tmp);
00185 return (tmp == NULL_RTX);
00186 }
00187
00188
00189
00190
00191 static bool
00192 insn_true_dependent_p (rtx x, rtx y)
00193 {
00194 rtx tmp;
00195
00196 if (! INSN_P (x) || ! INSN_P (y))
00197 return 0;
00198
00199 tmp = PATTERN (y);
00200 note_stores (PATTERN (x), insn_dependent_p_1, &tmp);
00201 return (tmp == NULL_RTX);
00202 }
00203
00204
00205
00206
00207
00208
00209 void
00210 mt_final_prescan_insn (rtx insn,
00211 rtx * opvec ATTRIBUTE_UNUSED,
00212 int noperands ATTRIBUTE_UNUSED)
00213 {
00214 rtx prev_i;
00215 enum attr_type prev_attr;
00216
00217 mt_nops_required = 0;
00218 mt_nop_reasons = "";
00219
00220
00221 if (TARGET_MS2)
00222 return;
00223
00224
00225 if (! INSN_P (insn))
00226 return;
00227
00228
00229 for (prev_i = PREV_INSN (insn);
00230 prev_i != NULL
00231 && (! INSN_P (prev_i)
00232 || GET_CODE (PATTERN (prev_i)) == USE
00233 || GET_CODE (PATTERN (prev_i)) == CLOBBER);
00234 prev_i = PREV_INSN (prev_i))
00235 {
00236
00237 if (BARRIER_P (prev_i))
00238 return;
00239 }
00240
00241
00242 if (prev_i == NULL || ! INSN_P (prev_i))
00243 return;
00244
00245 prev_attr = mt_get_attr_type (prev_i);
00246
00247
00248 if (prev_attr == TYPE_BRANCH)
00249 return;
00250
00251 switch (mt_get_attr_type (insn))
00252 {
00253 case TYPE_LOAD:
00254 case TYPE_STORE:
00255
00256 if ((prev_attr == TYPE_LOAD || prev_attr == TYPE_STORE)
00257 && TARGET_MS1_64_001)
00258 {
00259 mt_nops_required = 1;
00260 mt_nop_reasons = "consecutive mem ops";
00261 }
00262
00263
00264 case TYPE_ARITH:
00265 case TYPE_COMPLEX:
00266
00267
00268 if (prev_attr == TYPE_LOAD
00269 && insn_true_dependent_p (prev_i, insn))
00270 {
00271 mt_nops_required = 1;
00272 mt_nop_reasons = "load->arith dependency delay";
00273 }
00274 break;
00275
00276 case TYPE_BRANCH:
00277 if (insn_dependent_p (prev_i, insn))
00278 {
00279 if (prev_attr == TYPE_ARITH && TARGET_MS1_64_001)
00280 {
00281
00282
00283 mt_nops_required = 1;
00284 mt_nop_reasons = "arith->branch dependency delay";
00285 }
00286 else if (prev_attr == TYPE_LOAD)
00287 {
00288
00289
00290 if (TARGET_MS1_64_001)
00291 mt_nops_required = 2;
00292 else
00293 mt_nops_required = 1;
00294 mt_nop_reasons = "load->branch dependency delay";
00295 }
00296 }
00297 break;
00298
00299 default:
00300 fatal_insn ("mt_final_prescan_insn, invalid insn #1", insn);
00301 break;
00302 }
00303 }
00304
00305
00306 static void
00307 mt_debug_stack (struct mt_frame_info * info)
00308 {
00309 int regno;
00310
00311 if (!info)
00312 {
00313 error ("info pointer NULL");
00314 gcc_unreachable ();
00315 }
00316
00317 fprintf (stderr, "\nStack information for function %s:\n",
00318 ((current_function_decl && DECL_NAME (current_function_decl))
00319 ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
00320 : "<unknown>"));
00321
00322 fprintf (stderr, "\ttotal_size = %d\n", info->total_size);
00323 fprintf (stderr, "\tpretend_size = %d\n", info->pretend_size);
00324 fprintf (stderr, "\targs_size = %d\n", info->args_size);
00325 fprintf (stderr, "\textra_size = %d\n", info->extra_size);
00326 fprintf (stderr, "\treg_size = %d\n", info->reg_size);
00327 fprintf (stderr, "\tvar_size = %d\n", info->var_size);
00328 fprintf (stderr, "\tframe_size = %d\n", info->frame_size);
00329 fprintf (stderr, "\treg_mask = 0x%x\n", info->reg_mask);
00330 fprintf (stderr, "\tsave_fp = %d\n", info->save_fp);
00331 fprintf (stderr, "\tsave_lr = %d\n", info->save_lr);
00332 fprintf (stderr, "\tinitialized = %d\n", info->initialized);
00333 fprintf (stderr, "\tsaved registers =");
00334
00335
00336 for (regno = GPR_R0; regno <= GPR_LAST; regno++)
00337 if ( (1 << regno) & info->reg_mask)
00338 fprintf (stderr, " %s", reg_names[regno]);
00339
00340 putc ('\n', stderr);
00341 fflush (stderr);
00342 }
00343
00344
00345
00346 static void
00347 mt_print_operand_simple_address (FILE * file, rtx addr)
00348 {
00349 if (!addr)
00350 error ("PRINT_OPERAND_ADDRESS, null pointer");
00351
00352 else
00353 switch (GET_CODE (addr))
00354 {
00355 case REG:
00356 fprintf (file, "%s, #0", reg_names [REGNO (addr)]);
00357 break;
00358
00359 case PLUS:
00360 {
00361 rtx reg = 0;
00362 rtx offset = 0;
00363 rtx arg0 = XEXP (addr, 0);
00364 rtx arg1 = XEXP (addr, 1);
00365
00366 if (GET_CODE (arg0) == REG)
00367 {
00368 reg = arg0;
00369 offset = arg1;
00370 if (GET_CODE (offset) == REG)
00371 fatal_insn ("PRINT_OPERAND_ADDRESS, 2 regs", addr);
00372 }
00373
00374 else if (GET_CODE (arg1) == REG)
00375 reg = arg1, offset = arg0;
00376 else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
00377 {
00378 fprintf (file, "%s, #", reg_names [GPR_R0]);
00379 output_addr_const (file, addr);
00380 break;
00381 }
00382 fprintf (file, "%s, #", reg_names [REGNO (reg)]);
00383 output_addr_const (file, offset);
00384 break;
00385 }
00386
00387 case LABEL_REF:
00388 case SYMBOL_REF:
00389 case CONST_INT:
00390 case CONST:
00391 output_addr_const (file, addr);
00392 break;
00393
00394 default:
00395 fatal_insn ("PRINT_OPERAND_ADDRESS, invalid insn #1", addr);
00396 break;
00397 }
00398 }
00399
00400
00401 void
00402 mt_print_operand_address (FILE * file, rtx addr)
00403 {
00404 if (GET_CODE (addr) == AND
00405 && GET_CODE (XEXP (addr, 1)) == CONST_INT
00406 && INTVAL (XEXP (addr, 1)) == -3)
00407 mt_print_operand_simple_address (file, XEXP (addr, 0));
00408 else
00409 mt_print_operand_simple_address (file, addr);
00410 }
00411
00412
00413 void
00414 mt_print_operand (FILE * file, rtx x, int code)
00415 {
00416 switch (code)
00417 {
00418 case '#':
00419
00420 if (dbr_sequence_length () == 0)
00421 fputs ("\n\tnop", file);
00422 return;
00423
00424 case 'H':
00425 fprintf(file, "#%%hi16(");
00426 output_addr_const (file, x);
00427 fprintf(file, ")");
00428 return;
00429
00430 case 'L':
00431 fprintf(file, "#%%lo16(");
00432 output_addr_const (file, x);
00433 fprintf(file, ")");
00434 return;
00435
00436 case 'N':
00437 fprintf(file, "#%ld", ~INTVAL (x));
00438 return;
00439
00440 case 'z':
00441 if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
00442 {
00443 fputs (reg_names[GPR_R0], file);
00444 return;
00445 }
00446
00447 case 0:
00448
00449 break;
00450
00451 default:
00452
00453 fprintf (file, "unknown code");
00454 return;
00455 }
00456
00457 switch (GET_CODE (x))
00458 {
00459 case REG:
00460 fputs (reg_names [REGNO (x)], file);
00461 break;
00462
00463 case CONST:
00464 case CONST_INT:
00465 fprintf(file, "#%ld", INTVAL (x));
00466 break;
00467
00468 case MEM:
00469 mt_print_operand_address(file, XEXP (x,0));
00470 break;
00471
00472 case LABEL_REF:
00473 case SYMBOL_REF:
00474 output_addr_const (file, x);
00475 break;
00476
00477 default:
00478 fprintf(file, "Uknown code: %d", GET_CODE (x));
00479 break;
00480 }
00481
00482 return;
00483 }
00484
00485
00486 void
00487 mt_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, rtx libname,
00488 tree fndecl ATTRIBUTE_UNUSED, int incoming)
00489 {
00490 *cum = 0;
00491
00492 if (TARGET_DEBUG_ARG)
00493 {
00494 fprintf (stderr, "\nmt_init_cumulative_args:");
00495
00496 if (incoming)
00497 fputs (" incoming", stderr);
00498
00499 if (fntype)
00500 {
00501 tree ret_type = TREE_TYPE (fntype);
00502 fprintf (stderr, " return = %s,",
00503 tree_code_name[ (int)TREE_CODE (ret_type) ]);
00504 }
00505
00506 if (libname && GET_CODE (libname) == SYMBOL_REF)
00507 fprintf (stderr, " libname = %s", XSTR (libname, 0));
00508
00509 if (cfun->returns_struct)
00510 fprintf (stderr, " return-struct");
00511
00512 putc ('\n', stderr);
00513 }
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 static int
00531 mt_function_arg_slotno (const CUMULATIVE_ARGS * cum,
00532 enum machine_mode mode,
00533 tree type,
00534 int named ATTRIBUTE_UNUSED,
00535 int incoming_p ATTRIBUTE_UNUSED,
00536 int * pregno)
00537 {
00538 int regbase = FIRST_ARG_REGNUM;
00539 int slotno = * cum;
00540
00541 if (mode == VOIDmode || targetm.calls.must_pass_in_stack (mode, type))
00542 return -1;
00543
00544 if (slotno >= MT_NUM_ARG_REGS)
00545 return -1;
00546
00547 * pregno = regbase + slotno;
00548
00549 return slotno;
00550 }
00551
00552
00553 rtx
00554 mt_function_arg (const CUMULATIVE_ARGS * cum,
00555 enum machine_mode mode,
00556 tree type,
00557 int named,
00558 int incoming_p)
00559 {
00560 int slotno, regno;
00561 rtx reg;
00562
00563 slotno = mt_function_arg_slotno (cum, mode, type, named, incoming_p, ®no);
00564
00565 if (slotno == -1)
00566 reg = NULL_RTX;
00567 else
00568 reg = gen_rtx_REG (mode, regno);
00569
00570 return reg;
00571 }
00572
00573
00574 void
00575 mt_function_arg_advance (CUMULATIVE_ARGS * cum,
00576 enum machine_mode mode,
00577 tree type ATTRIBUTE_UNUSED,
00578 int named)
00579 {
00580 int slotno, regno;
00581
00582
00583 slotno = mt_function_arg_slotno (cum, mode, type, named, 0, ®no);
00584
00585 * cum += (mode != BLKmode
00586 ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
00587 : ROUND_ADVANCE (int_size_in_bytes (type)));
00588
00589 if (TARGET_DEBUG_ARG)
00590 fprintf (stderr,
00591 "mt_function_arg_advance: words = %2d, mode = %4s, named = %d, size = %3d\n",
00592 *cum, GET_MODE_NAME (mode), named,
00593 (*cum) * UNITS_PER_WORD);
00594 }
00595
00596
00597
00598
00599
00600
00601
00602 static int
00603 mt_arg_partial_bytes (CUMULATIVE_ARGS * pcum,
00604 enum machine_mode mode,
00605 tree type,
00606 bool named ATTRIBUTE_UNUSED)
00607 {
00608 int cum = * pcum;
00609 int words;
00610
00611 if (mode == BLKmode)
00612 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
00613 / UNITS_PER_WORD);
00614 else
00615 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
00616
00617 if (! targetm.calls.pass_by_reference (&cum, mode, type, named)
00618 && cum < MT_NUM_ARG_REGS
00619 && (cum + words) > MT_NUM_ARG_REGS)
00620 {
00621 int bytes = (MT_NUM_ARG_REGS - cum) * UNITS_PER_WORD;
00622
00623 if (TARGET_DEBUG)
00624 fprintf (stderr, "function_arg_partial_nregs = %d\n", bytes);
00625 return bytes;
00626 }
00627
00628 return 0;
00629 }
00630
00631
00632
00633 static bool
00634 mt_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
00635 enum machine_mode mode ATTRIBUTE_UNUSED,
00636 tree type,
00637 bool named ATTRIBUTE_UNUSED)
00638 {
00639 return (type && int_size_in_bytes (type) > 4 * UNITS_PER_WORD);
00640 }
00641
00642
00643 int
00644 mt_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
00645 tree type ATTRIBUTE_UNUSED)
00646 {
00647 return BITS_PER_WORD;
00648 }
00649
00650
00651 int
00652 mt_reg_ok_for_base_p (rtx x, int strict)
00653 {
00654 if (strict)
00655 return (((unsigned) REGNO (x)) < FIRST_PSEUDO_REGISTER);
00656 return 1;
00657 }
00658
00659
00660
00661 static bool
00662 mt_legitimate_simple_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
00663 rtx xinsn, int strict)
00664 {
00665 if (TARGET_DEBUG)
00666 {
00667 fprintf (stderr, "\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
00668 strict ? "" : "not ");
00669 debug_rtx (xinsn);
00670 }
00671
00672 if (GET_CODE (xinsn) == REG && mt_reg_ok_for_base_p (xinsn, strict))
00673 return true;
00674
00675 if (GET_CODE (xinsn) == PLUS
00676 && GET_CODE (XEXP (xinsn, 0)) == REG
00677 && mt_reg_ok_for_base_p (XEXP (xinsn, 0), strict)
00678 && GET_CODE (XEXP (xinsn, 1)) == CONST_INT
00679 && SMALL_INT (XEXP (xinsn, 1)))
00680 return true;
00681
00682 return false;
00683 }
00684
00685
00686
00687
00688 int
00689 mt_legitimate_address_p (enum machine_mode mode, rtx xinsn, int strict)
00690 {
00691 if (mt_legitimate_simple_address_p (mode, xinsn, strict))
00692 return 1;
00693
00694 if ((mode) == SImode
00695 && GET_CODE (xinsn) == AND
00696 && GET_CODE (XEXP (xinsn, 1)) == CONST_INT
00697 && INTVAL (XEXP (xinsn, 1)) == -3)
00698 return mt_legitimate_simple_address_p (mode, XEXP (xinsn, 0), strict);
00699 else
00700 return 0;
00701 }
00702
00703
00704
00705
00706 int
00707 uns_arith_operand (rtx op, enum machine_mode mode)
00708 {
00709 if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))
00710 return 1;
00711
00712 return register_operand (op, mode);
00713 }
00714
00715
00716
00717
00718 int
00719 arith_operand (rtx op, enum machine_mode mode)
00720 {
00721 if (GET_CODE (op) == CONST_INT && SMALL_INT (op))
00722 return 1;
00723
00724 return register_operand (op, mode);
00725 }
00726
00727
00728
00729 int
00730 reg_or_0_operand (rtx op, enum machine_mode mode)
00731 {
00732 switch (GET_CODE (op))
00733 {
00734 case CONST_INT:
00735 return INTVAL (op) == 0;
00736
00737 case REG:
00738 case SUBREG:
00739 return register_operand (op, mode);
00740
00741 default:
00742 break;
00743 }
00744
00745 return 0;
00746 }
00747
00748
00749
00750
00751 int
00752 big_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
00753 {
00754 if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (op), 'M'))
00755 return 1;
00756
00757 return 0;
00758 }
00759
00760
00761
00762
00763 int
00764 single_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
00765 {
00766 if (big_const_operand (op, mode)
00767 || GET_CODE (op) == CONST
00768 || GET_CODE (op) == LABEL_REF
00769 || GET_CODE (op) == SYMBOL_REF)
00770 return 0;
00771
00772 return 1;
00773 }
00774
00775
00776
00777 int interrupt_handler;
00778 enum processor_type mt_cpu;
00779
00780 static struct machine_function *
00781 mt_init_machine_status (void)
00782 {
00783 struct machine_function *f;
00784
00785 f = ggc_alloc_cleared (sizeof (struct machine_function));
00786
00787 return f;
00788 }
00789
00790
00791 void
00792 mt_override_options (void)
00793 {
00794 if (mt_cpu_string != NULL)
00795 {
00796 if (!strcmp (mt_cpu_string, "ms1-64-001"))
00797 mt_cpu = PROCESSOR_MS1_64_001;
00798 else if (!strcmp (mt_cpu_string, "ms1-16-002"))
00799 mt_cpu = PROCESSOR_MS1_16_002;
00800 else if (!strcmp (mt_cpu_string, "ms1-16-003"))
00801 mt_cpu = PROCESSOR_MS1_16_003;
00802 else if (!strcmp (mt_cpu_string, "ms2"))
00803 mt_cpu = PROCESSOR_MS2;
00804 else
00805 error ("bad value (%s) for -march= switch", mt_cpu_string);
00806 }
00807 else
00808 mt_cpu = PROCESSOR_MS1_16_002;
00809
00810 if (flag_exceptions)
00811 {
00812 flag_omit_frame_pointer = 0;
00813 flag_gcse = 0;
00814 }
00815
00816
00817 mt_flag_delayed_branch = flag_delayed_branch;
00818 flag_delayed_branch = 0;
00819
00820 init_machine_status = mt_init_machine_status;
00821 }
00822
00823
00824
00825
00826
00827 static void
00828 mt_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
00829 enum machine_mode mode ATTRIBUTE_UNUSED,
00830 tree type ATTRIBUTE_UNUSED,
00831 int *pretend_size, int no_rtl)
00832 {
00833 int regno;
00834 int regs = MT_NUM_ARG_REGS - *cum;
00835
00836 *pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs;
00837
00838 if (no_rtl)
00839 return;
00840
00841 for (regno = *cum; regno < MT_NUM_ARG_REGS; regno++)
00842 {
00843 rtx reg = gen_rtx_REG (SImode, FIRST_ARG_REGNUM + regno);
00844 rtx slot = gen_rtx_PLUS (Pmode,
00845 gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
00846 GEN_INT (UNITS_PER_WORD * regno));
00847
00848 emit_move_insn (gen_rtx_MEM (SImode, slot), reg);
00849 }
00850 }
00851
00852
00853
00854
00855
00856 unsigned int
00857 mt_compute_frame_size (int size)
00858 {
00859 int regno;
00860 unsigned int total_size;
00861 unsigned int var_size;
00862 unsigned int args_size;
00863 unsigned int pretend_size;
00864 unsigned int extra_size;
00865 unsigned int reg_size;
00866 unsigned int frame_size;
00867 unsigned int reg_mask;
00868
00869 var_size = size;
00870 args_size = current_function_outgoing_args_size;
00871 pretend_size = current_function_pretend_args_size;
00872 extra_size = FIRST_PARM_OFFSET (0);
00873 total_size = extra_size + pretend_size + args_size + var_size;
00874 reg_size = 0;
00875 reg_mask = 0;
00876
00877
00878 for (regno = GPR_R0; regno <= GPR_LAST; regno++)
00879 {
00880 if (MUST_SAVE_REGISTER (regno))
00881 {
00882 reg_size += UNITS_PER_WORD;
00883 reg_mask |= 1 << regno;
00884 }
00885 }
00886
00887 current_frame_info.save_fp = (regs_ever_live [GPR_FP]
00888 || frame_pointer_needed
00889 || interrupt_handler);
00890 current_frame_info.save_lr = (regs_ever_live [GPR_LINK]
00891 || profile_flag
00892 || interrupt_handler);
00893
00894 reg_size += (current_frame_info.save_fp + current_frame_info.save_lr)
00895 * UNITS_PER_WORD;
00896 total_size += reg_size;
00897 total_size = ((total_size + 3) & ~3);
00898
00899 frame_size = total_size;
00900
00901
00902 current_frame_info.pretend_size = pretend_size;
00903 current_frame_info.var_size = var_size;
00904 current_frame_info.args_size = args_size;
00905 current_frame_info.reg_size = reg_size;
00906 current_frame_info.frame_size = args_size + var_size;
00907 current_frame_info.total_size = total_size;
00908 current_frame_info.extra_size = extra_size;
00909 current_frame_info.reg_mask = reg_mask;
00910 current_frame_info.initialized = reload_completed;
00911
00912 return total_size;
00913 }
00914
00915
00916
00917
00918 static void
00919 mt_emit_save_restore (enum save_direction direction,
00920 rtx reg, rtx mem, int stack_offset)
00921 {
00922 if (direction == FROM_PROCESSOR_TO_MEM)
00923 {
00924 rtx insn;
00925
00926 insn = emit_move_insn (mem, reg);
00927 RTX_FRAME_RELATED_P (insn) = 1;
00928 REG_NOTES (insn)
00929 = gen_rtx_EXPR_LIST
00930 (REG_FRAME_RELATED_EXPR,
00931 gen_rtx_SET (VOIDmode,
00932 gen_rtx_MEM (SImode,
00933 gen_rtx_PLUS (SImode,
00934 stack_pointer_rtx,
00935 GEN_INT (stack_offset))),
00936 reg),
00937 REG_NOTES (insn));
00938 }
00939 else
00940 emit_move_insn (reg, mem);
00941 }
00942
00943
00944
00945
00946
00947 static void
00948 mt_emit_save_fp (enum save_direction direction,
00949 struct mt_frame_info info)
00950 {
00951 rtx base_reg;
00952 int reg_mask = info.reg_mask & ~(FP_MASK | LINK_MASK);
00953 int offset = info.total_size;
00954 int stack_offset = info.total_size;
00955
00956
00957 if (! info.save_fp && ! info.save_lr && ! reg_mask)
00958 return;
00959
00960
00961
00962 if (CONST_OK_FOR_LETTER_P(offset, 'O'))
00963 base_reg = stack_pointer_rtx;
00964 else
00965 {
00966
00967 base_reg = gen_rtx_REG (SImode, GPR_R9);
00968 offset = 0;
00969 }
00970
00971 if (info.save_fp)
00972 {
00973 offset -= UNITS_PER_WORD;
00974 stack_offset -= UNITS_PER_WORD;
00975 mt_emit_save_restore
00976 (direction, gen_rtx_REG (SImode, GPR_FP),
00977 gen_rtx_MEM (SImode,
00978 gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
00979 stack_offset);
00980 }
00981 }
00982
00983
00984
00985
00986 static void
00987 mt_emit_save_regs (enum save_direction direction,
00988 struct mt_frame_info info)
00989 {
00990 rtx base_reg;
00991 int regno;
00992 int reg_mask = info.reg_mask & ~(FP_MASK | LINK_MASK);
00993 int offset = info.total_size;
00994 int stack_offset = info.total_size;
00995
00996
00997 if (! info.save_fp && ! info.save_lr && ! reg_mask)
00998 return;
00999
01000
01001
01002 if (CONST_OK_FOR_LETTER_P(offset, 'O'))
01003 base_reg = stack_pointer_rtx;
01004 else
01005 {
01006
01007 base_reg = gen_rtx_REG (SImode, GPR_R9);
01008 offset = 0;
01009 }
01010
01011 if (info.save_fp)
01012 {
01013
01014
01015 offset -= UNITS_PER_WORD;
01016 stack_offset -= UNITS_PER_WORD;
01017 }
01018
01019 if (info.save_lr)
01020 {
01021 offset -= UNITS_PER_WORD;
01022 stack_offset -= UNITS_PER_WORD;
01023 mt_emit_save_restore
01024 (direction, gen_rtx_REG (SImode, GPR_LINK),
01025 gen_rtx_MEM (SImode,
01026 gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
01027 stack_offset);
01028 }
01029
01030
01031 for (regno = GPR_R0; regno <= GPR_LAST; regno++)
01032 {
01033 if ((reg_mask & (1 << regno)) != 0)
01034 {
01035 offset -= UNITS_PER_WORD;
01036 stack_offset -= UNITS_PER_WORD;
01037 mt_emit_save_restore
01038 (direction, gen_rtx_REG (SImode, regno),
01039 gen_rtx_MEM (SImode,
01040 gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
01041 stack_offset);
01042 }
01043 }
01044 }
01045
01046
01047 static bool
01048 mt_interrupt_function_p (tree func)
01049 {
01050 tree a;
01051
01052 if (TREE_CODE (func) != FUNCTION_DECL)
01053 return false;
01054
01055 a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
01056 return a != NULL_TREE;
01057 }
01058
01059
01060 void
01061 mt_expand_prologue (void)
01062 {
01063 rtx size_rtx, insn;
01064 unsigned int frame_size;
01065
01066 if (mt_interrupt_function_p (current_function_decl))
01067 {
01068 interrupt_handler = 1;
01069 if (cfun->machine)
01070 cfun->machine->interrupt_handler = 1;
01071 }
01072
01073 mt_compute_frame_size (get_frame_size ());
01074
01075 if (TARGET_DEBUG_STACK)
01076 mt_debug_stack (¤t_frame_info);
01077
01078
01079 frame_size = current_frame_info.total_size;
01080
01081
01082
01083 if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
01084 size_rtx = GEN_INT (frame_size);
01085 else
01086 {
01087
01088 gcc_assert (!interrupt_handler);
01089
01090 size_rtx = gen_rtx_REG (SImode, GPR_R9);
01091 insn = emit_move_insn (size_rtx, GEN_INT (frame_size & 0xffff0000));
01092 insn = emit_insn (gen_iorsi3 (size_rtx, size_rtx,
01093 GEN_INT (frame_size & 0x0000ffff)));
01094 }
01095
01096
01097
01098
01099 if (frame_size)
01100 {
01101 insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
01102 stack_pointer_rtx,
01103 size_rtx));
01104 RTX_FRAME_RELATED_P (insn) = 1;
01105 REG_NOTES (insn)
01106 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
01107 gen_rtx_SET (VOIDmode,
01108 stack_pointer_rtx,
01109 gen_rtx_MINUS (SImode,
01110 stack_pointer_rtx,
01111 GEN_INT (frame_size))),
01112 REG_NOTES (insn));
01113 }
01114
01115
01116
01117 if ( current_frame_info.reg_size != 0
01118 && !CONST_OK_FOR_LETTER_P (frame_size, 'O'))
01119 emit_insn (gen_addsi3 (size_rtx, size_rtx, stack_pointer_rtx));
01120
01121
01122 mt_emit_save_fp (FROM_PROCESSOR_TO_MEM, current_frame_info);
01123
01124
01125 if (frame_pointer_needed)
01126 {
01127 insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
01128 RTX_FRAME_RELATED_P (insn) = 1;
01129 }
01130
01131
01132 mt_emit_save_regs (FROM_PROCESSOR_TO_MEM, current_frame_info);
01133
01134
01135
01136 if (profile_flag)
01137 emit_insn (gen_blockage ());
01138 }
01139
01140
01141 int
01142 mt_epilogue_uses (int regno)
01143 {
01144 if (cfun->machine && cfun->machine->interrupt_handler && reload_completed)
01145 return 1;
01146 return regno == GPR_LINK;
01147 }
01148
01149
01150
01151
01152 void
01153 mt_expand_epilogue (enum epilogue_type eh_mode)
01154 {
01155 rtx size_rtx, insn;
01156 unsigned frame_size;
01157
01158 mt_compute_frame_size (get_frame_size ());
01159
01160 if (TARGET_DEBUG_STACK)
01161 mt_debug_stack (& current_frame_info);
01162
01163
01164 frame_size = current_frame_info.total_size;
01165
01166
01167
01168 if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
01169 size_rtx = GEN_INT (frame_size);
01170 else
01171 {
01172
01173 gcc_assert (!interrupt_handler);
01174
01175 size_rtx = gen_rtx_REG (SImode, GPR_R9);
01176 insn = emit_move_insn (size_rtx, GEN_INT (frame_size & 0xffff0000));
01177 insn = emit_insn (gen_iorsi3 (size_rtx, size_rtx,
01178 GEN_INT (frame_size & 0x0000ffff)));
01179
01180
01181 emit_insn (gen_addsi3 (size_rtx, size_rtx, stack_pointer_rtx));
01182 }
01183
01184
01185 if (frame_pointer_needed)
01186 insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
01187
01188
01189 mt_emit_save_fp (FROM_MEM_TO_PROCESSOR, current_frame_info);
01190 mt_emit_save_regs (FROM_MEM_TO_PROCESSOR, current_frame_info);
01191
01192
01193
01194 if (frame_size)
01195 {
01196 if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
01197
01198 insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
01199 stack_pointer_rtx,
01200 size_rtx));
01201 else
01202
01203 insn = emit_move_insn (stack_pointer_rtx,
01204 gen_rtx_REG (SImode, GPR_R9));
01205
01206 REG_NOTES (insn)
01207 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
01208 gen_rtx_SET (VOIDmode,
01209 stack_pointer_rtx,
01210 gen_rtx_PLUS (SImode,
01211 stack_pointer_rtx,
01212 GEN_INT (frame_size))),
01213 REG_NOTES (insn));
01214 }
01215
01216 if (cfun->machine && cfun->machine->eh_stack_adjust != NULL_RTX)
01217
01218 emit_insn (gen_addsi3 (stack_pointer_rtx,
01219 stack_pointer_rtx,
01220 cfun->machine->eh_stack_adjust));
01221
01222
01223 if (eh_mode == EH_EPILOGUE)
01224 {
01225 emit_jump_insn (gen_eh_return_internal ());
01226 emit_barrier ();
01227 }
01228 else if (interrupt_handler)
01229 emit_jump_insn (gen_return_interrupt_internal ());
01230 else
01231 emit_jump_insn (gen_return_internal ());
01232
01233
01234 interrupt_handler = 0;
01235 current_frame_info = zero_frame_info;
01236 if (cfun->machine)
01237 cfun->machine->eh_stack_adjust = NULL_RTX;
01238 }
01239
01240
01241
01242 void
01243 mt_expand_eh_return (rtx * operands)
01244 {
01245 if (GET_CODE (operands[0]) != REG
01246 || REGNO (operands[0]) != EH_RETURN_STACKADJ_REGNO)
01247 {
01248 rtx sp = EH_RETURN_STACKADJ_RTX;
01249
01250 emit_move_insn (sp, operands[0]);
01251 operands[0] = sp;
01252 }
01253
01254 emit_insn (gen_eh_epilogue (operands[0]));
01255 }
01256
01257
01258 void
01259 mt_emit_eh_epilogue (rtx * operands ATTRIBUTE_UNUSED)
01260 {
01261 cfun->machine->eh_stack_adjust = EH_RETURN_STACKADJ_RTX;
01262 mt_expand_epilogue (EH_EPILOGUE);
01263 }
01264
01265
01266 static tree
01267 mt_handle_interrupt_attribute (tree * node,
01268 tree name,
01269 tree args ATTRIBUTE_UNUSED,
01270 int flags ATTRIBUTE_UNUSED,
01271 bool * no_add_attrs)
01272 {
01273 if (TREE_CODE (*node) != FUNCTION_DECL)
01274 {
01275 warning (OPT_Wattributes,
01276 "%qs attribute only applies to functions",
01277 IDENTIFIER_POINTER (name));
01278 *no_add_attrs = true;
01279 }
01280
01281 return NULL_TREE;
01282 }
01283
01284
01285 const struct attribute_spec mt_attribute_table[] =
01286 {
01287
01288 { "interrupt", 0, 0, false, false, false, mt_handle_interrupt_attribute },
01289 { NULL, 0, 0, false, false, false, NULL }
01290 };
01291
01292
01293 int
01294 mt_initial_elimination_offset (int from, int to)
01295 {
01296 mt_compute_frame_size (get_frame_size ());
01297
01298 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
01299 return 0;
01300
01301 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
01302 return current_frame_info.total_size;
01303
01304 else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
01305 return current_frame_info.total_size;
01306
01307 else
01308 gcc_unreachable ();
01309 }
01310
01311
01312
01313
01314 static rtx
01315 mt_generate_compare (enum rtx_code code, rtx op0, rtx op1)
01316 {
01317 rtx scratch0, scratch1, const_scratch;
01318
01319 switch (code)
01320 {
01321 case GTU:
01322 case LTU:
01323 case GEU:
01324 case LEU:
01325
01326 scratch0 = gen_reg_rtx (SImode);
01327 scratch1 = gen_reg_rtx (SImode);
01328 const_scratch = force_reg (SImode, GEN_INT(MT_MIN_INT));
01329 emit_insn (gen_addsi3 (scratch0, const_scratch, op0));
01330 emit_insn (gen_addsi3 (scratch1, const_scratch, op1));
01331 break;
01332 default:
01333 scratch0 = op0;
01334 scratch1 = op1;
01335 break;
01336 }
01337
01338
01339 switch (code)
01340 {
01341 case GTU:
01342 code = GT; break;
01343 case LTU:
01344 code = LT; break;
01345 case GEU:
01346 code = GE; break;
01347 case LEU:
01348 code = LE; break;
01349 default:
01350
01351 break;
01352 }
01353
01354
01355 return gen_rtx_fmt_ee (code, VOIDmode, scratch0, scratch1);
01356 }
01357
01358
01359
01360 void
01361 mt_emit_cbranch (enum rtx_code code, rtx loc, rtx op0, rtx op1)
01362 {
01363 rtx condition_rtx, loc_ref;
01364
01365 if (! reg_or_0_operand (op0, SImode))
01366 op0 = copy_to_mode_reg (SImode, op0);
01367
01368 if (! reg_or_0_operand (op1, SImode))
01369 op1 = copy_to_mode_reg (SImode, op1);
01370
01371 condition_rtx = mt_generate_compare (code, op0, op1);
01372 loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
01373 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
01374 gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
01375 loc_ref, pc_rtx)));
01376 }
01377
01378
01379
01380
01381 static void
01382 mt_set_memflags_1 (rtx x, int in_struct_p, int volatile_p)
01383 {
01384 int i;
01385
01386 switch (GET_CODE (x))
01387 {
01388 case SEQUENCE:
01389 case PARALLEL:
01390 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
01391 mt_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p);
01392 break;
01393
01394 case INSN:
01395 mt_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p);
01396 break;
01397
01398 case SET:
01399 mt_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p);
01400 mt_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p);
01401 break;
01402
01403 case MEM:
01404 MEM_IN_STRUCT_P (x) = in_struct_p;
01405 MEM_VOLATILE_P (x) = volatile_p;
01406
01407
01408
01409
01410
01411
01412 break;
01413
01414 default:
01415 break;
01416 }
01417 }
01418
01419
01420
01421
01422
01423 void
01424 mt_set_memflags (rtx ref)
01425 {
01426 rtx insn;
01427 int in_struct_p, volatile_p;
01428
01429 if (GET_CODE (ref) != MEM)
01430 return;
01431
01432 in_struct_p = MEM_IN_STRUCT_P (ref);
01433 volatile_p = MEM_VOLATILE_P (ref);
01434
01435
01436
01437
01438 if (! in_struct_p && ! volatile_p)
01439 return;
01440
01441 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
01442 mt_set_memflags_1 (insn, in_struct_p, volatile_p);
01443 }
01444
01445
01446 enum reg_class
01447 mt_secondary_reload_class (enum reg_class class ATTRIBUTE_UNUSED,
01448 enum machine_mode mode,
01449 rtx x)
01450 {
01451 if ((mode == QImode && (!TARGET_BYTE_ACCESS)) || mode == HImode)
01452 {
01453 if (GET_CODE (x) == MEM
01454 || (GET_CODE (x) == REG && true_regnum (x) == -1)
01455 || (GET_CODE (x) == SUBREG
01456 && (GET_CODE (SUBREG_REG (x)) == MEM
01457 || (GET_CODE (SUBREG_REG (x)) == REG
01458 && true_regnum (SUBREG_REG (x)) == -1))))
01459 return GENERAL_REGS;
01460 }
01461
01462 return NO_REGS;
01463 }
01464
01465
01466
01467 rtx
01468 mt_function_value (tree valtype, enum machine_mode mode, tree func_decl ATTRIBUTE_UNUSED)
01469 {
01470 if ((mode) == DImode || (mode) == DFmode)
01471 return gen_rtx_MEM (mode, gen_rtx_REG (mode, RETURN_VALUE_REGNUM));
01472
01473 if (valtype)
01474 mode = TYPE_MODE (valtype);
01475
01476 return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
01477 }
01478
01479
01480
01481
01482
01483
01484
01485 void
01486 mt_split_words (enum machine_mode nmode,
01487 enum machine_mode omode,
01488 rtx *operands)
01489 {
01490 rtx dl,dh;
01491 rtx sl,sh;
01492 int move_high_first = 0;
01493
01494 switch (GET_CODE (operands[0]))
01495 {
01496 case SUBREG:
01497 case REG:
01498 if ((GET_CODE (operands[1]) == REG
01499 || GET_CODE (operands[1]) == SUBREG)
01500 && true_regnum (operands[0]) <= true_regnum (operands[1]))
01501 move_high_first = 1;
01502
01503 if (GET_CODE (operands[0]) == SUBREG)
01504 {
01505 dl = gen_rtx_SUBREG (nmode, SUBREG_REG (operands[0]),
01506 SUBREG_BYTE (operands[0]) + GET_MODE_SIZE (nmode));
01507 dh = gen_rtx_SUBREG (nmode, SUBREG_REG (operands[0]), SUBREG_BYTE (operands[0]));
01508 }
01509 else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0]))
01510 {
01511 int r = REGNO (operands[0]);
01512 dh = gen_rtx_REG (nmode, r);
01513 dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
01514 }
01515 else
01516 {
01517 dh = gen_rtx_SUBREG (nmode, operands[0], 0);
01518 dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode));
01519 }
01520 break;
01521
01522 case MEM:
01523 switch (GET_CODE (XEXP (operands[0], 0)))
01524 {
01525 case POST_INC:
01526 case POST_DEC:
01527 gcc_unreachable ();
01528 default:
01529 dl = operand_subword (operands[0],
01530 GET_MODE_SIZE (nmode)/UNITS_PER_WORD,
01531 0, omode);
01532 dh = operand_subword (operands[0], 0, 0, omode);
01533 }
01534 break;
01535 default:
01536 gcc_unreachable ();
01537 }
01538
01539 switch (GET_CODE (operands[1]))
01540 {
01541 case REG:
01542 if (! IS_PSEUDO_P (operands[1]))
01543 {
01544 int r = REGNO (operands[1]);
01545
01546 sh = gen_rtx_REG (nmode, r);
01547 sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
01548 }
01549 else
01550 {
01551 sh = gen_rtx_SUBREG (nmode, operands[1], 0);
01552 sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode));
01553 }
01554 break;
01555
01556 case CONST_DOUBLE:
01557 if (operands[1] == const0_rtx)
01558 sh = sl = const0_rtx;
01559 else
01560 split_double (operands[1], & sh, & sl);
01561 break;
01562
01563 case CONST_INT:
01564 if (operands[1] == const0_rtx)
01565 sh = sl = const0_rtx;
01566 else
01567 {
01568 int vl, vh;
01569
01570 switch (nmode)
01571 {
01572 default:
01573 gcc_unreachable ();
01574 }
01575
01576 sl = GEN_INT (vl);
01577 sh = GEN_INT (vh);
01578 }
01579 break;
01580
01581 case SUBREG:
01582 sl = gen_rtx_SUBREG (nmode,
01583 SUBREG_REG (operands[1]),
01584 SUBREG_BYTE (operands[1]) + GET_MODE_SIZE (nmode));
01585 sh = gen_rtx_SUBREG (nmode,
01586 SUBREG_REG (operands[1]),
01587 SUBREG_BYTE (operands[1]));
01588 break;
01589
01590 case MEM:
01591 switch (GET_CODE (XEXP (operands[1], 0)))
01592 {
01593 case POST_DEC:
01594 case POST_INC:
01595 gcc_unreachable ();
01596 break;
01597 default:
01598 sl = operand_subword (operands[1],
01599 GET_MODE_SIZE (nmode)/UNITS_PER_WORD,
01600 0, omode);
01601 sh = operand_subword (operands[1], 0, 0, omode);
01602
01603
01604
01605
01606 if (GET_CODE (dl) == REG
01607 && true_regnum (dl)
01608 == true_regnum (XEXP (XEXP (sl, 0 ), 0)))
01609 move_high_first = 1;
01610 }
01611 break;
01612 default:
01613 gcc_unreachable ();
01614 }
01615
01616 if (move_high_first)
01617 {
01618 operands[2] = dh;
01619 operands[3] = sh;
01620 operands[4] = dl;
01621 operands[5] = sl;
01622 }
01623 else
01624 {
01625 operands[2] = dl;
01626 operands[3] = sl;
01627 operands[4] = dh;
01628 operands[5] = sh;
01629 }
01630 return;
01631 }
01632
01633
01634 static bool
01635 mt_pass_in_stack (enum machine_mode mode ATTRIBUTE_UNUSED, tree type)
01636 {
01637 return (((type) != 0
01638 && (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
01639 || TREE_ADDRESSABLE (type))));
01640 }
01641
01642
01643
01644
01645 void mt_add_loop (void)
01646 {
01647 cfun->machine->has_loops++;
01648 }
01649
01650
01651
01652 #define MAX_LOOP_DEPTH 4
01653
01654
01655 #define MAX_LOOP_LENGTH (200 * 4)
01656
01657
01658 typedef struct loop_info *loop_info;
01659 DEF_VEC_P (loop_info);
01660 DEF_VEC_ALLOC_P (loop_info,heap);
01661
01662
01663
01664 struct loop_info GTY (())
01665 {
01666
01667 int loop_no;
01668
01669
01670
01671 basic_block predecessor;
01672
01673
01674
01675 basic_block head;
01676
01677
01678 basic_block tail;
01679
01680
01681
01682 basic_block successor;
01683
01684
01685 rtx dbnz;
01686
01687
01688 rtx init;
01689
01690
01691 rtx loop_init;
01692
01693
01694 rtx loop_end;
01695
01696
01697 rtx end_label;
01698
01699
01700 int depth;
01701
01702
01703 int length;
01704
01705
01706 struct loop_info *next;
01707
01708
01709
01710 VEC (basic_block,heap) *blocks;
01711
01712
01713 VEC (loop_info,heap) *loops;
01714 };
01715
01716
01717 typedef struct loop_work GTY(())
01718 {
01719
01720 basic_block block;
01721
01722
01723 loop_info loop;
01724 } loop_work;
01725
01726
01727 DEF_VEC_O (loop_work);
01728 DEF_VEC_ALLOC_O (loop_work,heap);
01729
01730
01731
01732
01733 static bool
01734 mt_loop_nesting (loop_info loop)
01735 {
01736 loop_info inner;
01737 unsigned ix;
01738 int inner_depth = 0;
01739
01740 if (!loop->depth)
01741 {
01742
01743 if (EDGE_COUNT (loop->head->preds) == 2)
01744 {
01745 loop->predecessor = EDGE_PRED (loop->head, 0)->src;
01746 if (loop->predecessor == loop->tail)
01747
01748 loop->predecessor = EDGE_PRED (loop->head, 1)->src;
01749
01750
01751
01752 if (EDGE_COUNT (loop->predecessor->succs) != 1
01753 || !(EDGE_SUCC (loop->predecessor, 0)->flags & EDGE_FALLTHRU))
01754 loop->predecessor = NULL;
01755 }
01756
01757
01758 loop->depth = -1;
01759 if (loop->predecessor)
01760 {
01761 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix++, inner);)
01762 {
01763 if (!inner->depth)
01764 mt_loop_nesting (inner);
01765
01766 if (inner->depth < 0)
01767 {
01768 inner_depth = -1;
01769 break;
01770 }
01771
01772 if (inner_depth < inner->depth)
01773 inner_depth = inner->depth;
01774 loop->length += inner->length;
01775 }
01776
01777
01778 if (inner_depth >= 0)
01779 loop->depth = inner_depth + 1;
01780 }
01781 }
01782 return (loop->depth > 0
01783 && loop->predecessor
01784 && loop->depth < MAX_LOOP_DEPTH
01785 && loop->length < MAX_LOOP_LENGTH);
01786 }
01787
01788
01789
01790 static int
01791 mt_block_length (basic_block bb)
01792 {
01793 int length = 0;
01794 rtx insn;
01795
01796 for (insn = BB_HEAD (bb);
01797 insn != NEXT_INSN (BB_END (bb));
01798 insn = NEXT_INSN (insn))
01799 {
01800 if (!INSN_P (insn))
01801 continue;
01802 if (CALL_P (insn))
01803 {
01804
01805 length = MAX_LOOP_LENGTH + 1;
01806 break;
01807 }
01808
01809 length += get_attr_length (insn);
01810 }
01811 return length;
01812 }
01813
01814
01815
01816
01817
01818 static bool
01819 mt_scan_loop (loop_info loop, rtx reg, rtx dbnz)
01820 {
01821 unsigned ix;
01822 loop_info inner;
01823 basic_block bb;
01824
01825 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
01826 {
01827 rtx insn;
01828
01829 for (insn = BB_HEAD (bb);
01830 insn != NEXT_INSN (BB_END (bb));
01831 insn = NEXT_INSN (insn))
01832 {
01833 if (!INSN_P (insn))
01834 continue;
01835 if (insn == dbnz)
01836 continue;
01837 if (reg_mentioned_p (reg, PATTERN (insn)))
01838 return true;
01839 }
01840 }
01841 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
01842 if (mt_scan_loop (inner, reg, NULL_RTX))
01843 return true;
01844
01845 return false;
01846 }
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881 static void
01882 mt_reorg_loops (FILE *dump_file)
01883 {
01884 basic_block bb;
01885 loop_info loops = NULL;
01886 loop_info loop;
01887 int nloops = 0;
01888 unsigned dwork = 0;
01889 VEC (loop_work,heap) *works = VEC_alloc (loop_work,heap,20);
01890 loop_work *work;
01891 edge e;
01892 edge_iterator ei;
01893 bool replaced = false;
01894
01895
01896
01897
01898 FOR_EACH_BB (bb)
01899 {
01900 rtx tail = BB_END (bb);
01901
01902 while (GET_CODE (tail) == NOTE)
01903 tail = PREV_INSN (tail);
01904
01905 bb->aux = NULL;
01906 if (recog_memoized (tail) == CODE_FOR_decrement_and_branch_until_zero)
01907 {
01908
01909
01910 loop = XNEW (struct loop_info);
01911 loop->next = loops;
01912 loops = loop;
01913 loop->tail = bb;
01914 loop->head = BRANCH_EDGE (bb)->dest;
01915 loop->successor = FALLTHRU_EDGE (bb)->dest;
01916 loop->predecessor = NULL;
01917 loop->dbnz = tail;
01918 loop->depth = 0;
01919 loop->length = mt_block_length (bb);
01920 loop->blocks = VEC_alloc (basic_block, heap, 20);
01921 VEC_quick_push (basic_block, loop->blocks, bb);
01922 loop->loops = NULL;
01923 loop->loop_no = nloops++;
01924
01925 loop->init = loop->end_label = NULL_RTX;
01926 loop->loop_init = loop->loop_end = NULL_RTX;
01927
01928 work = VEC_safe_push (loop_work, heap, works, NULL);
01929 work->block = loop->head;
01930 work->loop = loop;
01931
01932 bb->aux = loop;
01933
01934 if (dump_file)
01935 {
01936 fprintf (dump_file, ";; potential loop %d ending at\n",
01937 loop->loop_no);
01938 print_rtl_single (dump_file, tail);
01939 }
01940 }
01941 }
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958 while (VEC_iterate (loop_work, works, dwork++, work))
01959 {
01960 loop = work->loop;
01961 bb = work->block;
01962 if (bb == EXIT_BLOCK_PTR)
01963
01964 loop->depth = -1;
01965 else if (!bb->aux)
01966 {
01967
01968
01969 bb->aux = loop;
01970 loop->length += mt_block_length (bb);
01971 VEC_safe_push (basic_block, heap, loop->blocks, bb);
01972 FOR_EACH_EDGE (e, ei, bb->succs)
01973 {
01974 if (!VEC_space (loop_work, works, 1))
01975 {
01976 if (dwork)
01977 {
01978 VEC_block_remove (loop_work, works, 0, dwork);
01979 dwork = 0;
01980 }
01981 else
01982 VEC_reserve (loop_work, heap, works, 1);
01983 }
01984 work = VEC_quick_push (loop_work, works, NULL);
01985 work->block = EDGE_SUCC (bb, ei.index)->dest;
01986 work->loop = loop;
01987 }
01988 }
01989 else if (bb->aux != loop)
01990 {
01991
01992
01993
01994
01995 loop_info other = bb->aux;
01996
01997 if (other->head != bb)
01998 loop->depth = -1;
01999 else
02000 {
02001 VEC_safe_push (loop_info, heap, loop->loops, other);
02002 work = VEC_safe_push (loop_work, heap, works, NULL);
02003 work->loop = loop;
02004 work->block = other->successor;
02005 }
02006 }
02007 }
02008 VEC_free (loop_work, heap, works);
02009
02010
02011 for (loop = loops; loop; loop = loop->next)
02012 {
02013 rtx iter_reg, insn, init_insn;
02014 rtx init_val, loop_end, loop_init, end_label, head_label;
02015
02016 if (!mt_loop_nesting (loop))
02017 {
02018 if (dump_file)
02019 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
02020 continue;
02021 }
02022
02023
02024 iter_reg = SET_DEST (XVECEXP (PATTERN (loop->dbnz), 0, 1));
02025
02026 if (!REG_P (iter_reg))
02027 {
02028
02029 if (dump_file)
02030 fprintf (dump_file, ";; loop %d has spilled iteration count\n",
02031 loop->loop_no);
02032 continue;
02033 }
02034
02035
02036 init_insn = NULL_RTX;
02037 for (insn = BB_END (loop->predecessor);
02038 insn != PREV_INSN (BB_HEAD (loop->predecessor));
02039 insn = PREV_INSN (insn))
02040 {
02041 if (!INSN_P (insn))
02042 continue;
02043 if (reg_mentioned_p (iter_reg, PATTERN (insn)))
02044 {
02045 rtx set = single_set (insn);
02046
02047 if (set && rtx_equal_p (iter_reg, SET_DEST (set)))
02048 init_insn = insn;
02049 break;
02050 }
02051 }
02052
02053 if (!init_insn)
02054 {
02055 if (dump_file)
02056 fprintf (dump_file, ";; loop %d has no initializer\n",
02057 loop->loop_no);
02058 continue;
02059 }
02060 if (dump_file)
02061 {
02062 fprintf (dump_file, ";; loop %d initialized by\n",
02063 loop->loop_no);
02064 print_rtl_single (dump_file, init_insn);
02065 }
02066
02067 init_val = PATTERN (init_insn);
02068 if (GET_CODE (init_val) == SET)
02069 init_val = SET_SRC (init_val);
02070 if (GET_CODE (init_val) != CONST_INT || INTVAL (init_val) >= 65535)
02071 {
02072 if (dump_file)
02073 fprintf (dump_file, ";; loop %d has complex initializer\n",
02074 loop->loop_no);
02075 continue;
02076 }
02077
02078
02079 if (mt_scan_loop (loop, iter_reg, loop->dbnz))
02080 {
02081 if (dump_file)
02082 fprintf (dump_file, ";; loop %d uses iterator\n",
02083 loop->loop_no);
02084 continue;
02085 }
02086
02087
02088
02089
02090 init_val = GEN_INT (INTVAL (init_val) + 1);
02091
02092 iter_reg = gen_rtx_REG (SImode, LOOP_FIRST + loop->depth - 1);
02093 end_label = gen_label_rtx ();
02094 head_label = XEXP (SET_SRC (XVECEXP (PATTERN (loop->dbnz), 0, 0)), 1);
02095 loop_end = gen_loop_end (iter_reg, head_label);
02096 loop_init = gen_loop_init (iter_reg, init_val, end_label);
02097 loop->init = init_insn;
02098 loop->end_label = end_label;
02099 loop->loop_init = loop_init;
02100 loop->loop_end = loop_end;
02101 replaced = true;
02102
02103 if (dump_file)
02104 {
02105 fprintf (dump_file, ";; replacing loop %d initializer with\n",
02106 loop->loop_no);
02107 print_rtl_single (dump_file, loop->loop_init);
02108 fprintf (dump_file, ";; replacing loop %d terminator with\n",
02109 loop->loop_no);
02110 print_rtl_single (dump_file, loop->loop_end);
02111 }
02112 }
02113
02114
02115
02116 for (loop = loops; loop; loop = loop->next)
02117 if (loop->loop_init)
02118 {
02119 emit_jump_insn_after (loop->loop_init, BB_END (loop->predecessor));
02120 delete_insn (loop->init);
02121 emit_label_before (loop->end_label, loop->dbnz);
02122 emit_jump_insn_before (loop->loop_end, loop->dbnz);
02123 delete_insn (loop->dbnz);
02124 }
02125
02126
02127 while (loops)
02128 {
02129 loop = loops;
02130 loops = loop->next;
02131 VEC_free (loop_info, heap, loop->loops);
02132 VEC_free (basic_block, heap, loop->blocks);
02133 XDELETE (loop);
02134 }
02135
02136 if (replaced && dump_file)
02137 {
02138 fprintf (dump_file, ";; Replaced loops\n");
02139 print_rtl (dump_file, get_insns ());
02140 }
02141 }
02142
02143
02144 typedef struct branch_info
02145 {
02146 rtx insn;
02147
02148 struct branch_info *next;
02149 } branch_info;
02150
02151 typedef struct label_info
02152 {
02153 rtx label;
02154 branch_info *branches;
02155 struct label_info *next;
02156 } label_info;
02157
02158
02159 static label_info *mt_labels;
02160
02161
02162
02163
02164 static int
02165 mt_add_branches (rtx *x, void *insn)
02166 {
02167 if (GET_CODE (*x) == LABEL_REF)
02168 {
02169 branch_info *branch = xmalloc (sizeof (*branch));
02170 rtx label = XEXP (*x, 0);
02171 label_info *info;
02172
02173 for (info = mt_labels; info; info = info->next)
02174 if (info->label == label)
02175 break;
02176
02177 if (!info)
02178 {
02179 info = xmalloc (sizeof (*info));
02180 info->next = mt_labels;
02181 mt_labels = info;
02182
02183 info->label = label;
02184 info->branches = NULL;
02185 }
02186
02187 branch->next = info->branches;
02188 info->branches = branch;
02189 branch->insn = insn;
02190 }
02191 return 0;
02192 }
02193
02194
02195
02196
02197
02198
02199
02200 static rtx
02201 mt_check_delay_slot (rtx branch, rtx insn)
02202 {
02203 rtx slot;
02204 rtx tmp;
02205 rtx p;
02206 rtx jmp;
02207
02208 gcc_assert (GET_CODE (PATTERN (branch)) == SEQUENCE);
02209 if (INSN_DELETED_P (branch))
02210 return NULL_RTX;
02211 slot = XVECEXP (PATTERN (branch), 0, 1);
02212
02213 tmp = PATTERN (insn);
02214 note_stores (PATTERN (slot), insn_dependent_p_1, &tmp);
02215 if (tmp)
02216
02217 return NULL_RTX;
02218
02219
02220 jmp = XVECEXP (PATTERN (branch), 0, 0);
02221
02222 tmp = PATTERN (jmp);
02223 note_stores (PATTERN (slot), insn_dependent_p_1, &tmp);
02224 if (!tmp)
02225
02226 return branch;
02227
02228 p = PREV_INSN (branch);
02229 NEXT_INSN (p) = slot;
02230 PREV_INSN (slot) = p;
02231 NEXT_INSN (slot) = jmp;
02232 PREV_INSN (jmp) = slot;
02233 NEXT_INSN (jmp) = branch;
02234 PREV_INSN (branch) = jmp;
02235 XVECEXP (PATTERN (branch), 0, 0) = NULL_RTX;
02236 XVECEXP (PATTERN (branch), 0, 1) = NULL_RTX;
02237 delete_insn (branch);
02238 return jmp;
02239 }
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254 static void
02255 mt_reorg_hazard (void)
02256 {
02257 rtx insn, next;
02258
02259
02260 for (insn = get_insns ();
02261 insn;
02262 insn = NEXT_INSN (insn))
02263 {
02264 rtx jmp;
02265
02266 if (!INSN_P (insn))
02267 continue;
02268
02269 jmp = PATTERN (insn);
02270
02271 if (GET_CODE (jmp) != SEQUENCE)
02272
02273
02274 continue;
02275
02276 jmp = XVECEXP (jmp, 0, 0);
02277
02278 if (recog_memoized (jmp) == CODE_FOR_tablejump)
02279 for (jmp = XEXP (XEXP (XVECEXP (PATTERN (jmp), 0, 1), 0), 0);
02280 !JUMP_TABLE_DATA_P (jmp);
02281 jmp = NEXT_INSN (jmp))
02282 continue;
02283
02284 for_each_rtx (&PATTERN (jmp), mt_add_branches, insn);
02285 }
02286
02287
02288 for (insn = get_insns ();
02289 insn && !INSN_P (insn);
02290 insn = NEXT_INSN (insn))
02291 continue;
02292
02293 for (;
02294 insn;
02295 insn = next)
02296 {
02297 rtx jmp, tmp;
02298 enum attr_type attr;
02299
02300 gcc_assert (INSN_P (insn) && !INSN_DELETED_P (insn));
02301 for (next = NEXT_INSN (insn);
02302 next;
02303 next = NEXT_INSN (next))
02304 {
02305 if (!INSN_P (next))
02306 continue;
02307 if (GET_CODE (PATTERN (next)) != USE)
02308 break;
02309 }
02310
02311 jmp = insn;
02312 if (GET_CODE (PATTERN (insn)) == SEQUENCE)
02313 jmp = XVECEXP (PATTERN (insn), 0, 0);
02314
02315 attr = recog_memoized (jmp) >= 0 ? get_attr_type (jmp) : TYPE_UNKNOWN;
02316
02317 if (next && attr == TYPE_LOAD)
02318 {
02319
02320
02321
02322 tmp = PATTERN (next);
02323 if (GET_CODE (tmp) == SEQUENCE)
02324 tmp = PATTERN (XVECEXP (tmp, 0, 0));
02325 note_stores (PATTERN (insn), insn_dependent_p_1, &tmp);
02326 if (!tmp)
02327 emit_insn_after (gen_nop (), insn);
02328 }
02329
02330 if (attr == TYPE_CALL)
02331 {
02332
02333
02334 int nops = 0;
02335 int count;
02336 rtx prev = insn;
02337 rtx rescan = NULL_RTX;
02338
02339 for (count = 2; count && !nops;)
02340 {
02341 int type;
02342
02343 prev = PREV_INSN (prev);
02344 if (!prev)
02345 {
02346
02347
02348
02349 nops = count;
02350 break;
02351 }
02352
02353 if (BARRIER_P (prev))
02354 break;
02355 if (LABEL_P (prev))
02356 {
02357
02358 label_info *label;
02359 branch_info *branch;
02360
02361 for (label = mt_labels;
02362 label;
02363 label = label->next)
02364 if (label->label == prev)
02365 {
02366 for (branch = label->branches;
02367 branch;
02368 branch = branch->next)
02369 {
02370 tmp = mt_check_delay_slot (branch->insn, jmp);
02371
02372 if (tmp == branch->insn)
02373 {
02374 nops = count;
02375 break;
02376 }
02377
02378 if (tmp && branch->insn == next)
02379 rescan = tmp;
02380 }
02381 break;
02382 }
02383 continue;
02384 }
02385 if (!INSN_P (prev) || GET_CODE (PATTERN (prev)) == USE)
02386 continue;
02387
02388 if (GET_CODE (PATTERN (prev)) == SEQUENCE)
02389 {
02390
02391 tmp = mt_check_delay_slot (prev, jmp);
02392 if (tmp == prev)
02393 nops = count;
02394 break;
02395 }
02396
02397 type = (INSN_CODE (prev) >= 0 ? get_attr_type (prev)
02398 : TYPE_COMPLEX);
02399 if (type == TYPE_CALL || type == TYPE_BRANCH)
02400 break;
02401
02402 if (type == TYPE_LOAD
02403 || type == TYPE_ARITH
02404 || type == TYPE_COMPLEX)
02405 {
02406 tmp = PATTERN (jmp);
02407 note_stores (PATTERN (prev), insn_dependent_p_1, &tmp);
02408 if (!tmp)
02409 {
02410 nops = count;
02411 break;
02412 }
02413 }
02414
02415 if (INSN_CODE (prev) >= 0)
02416 count--;
02417 }
02418
02419 if (rescan)
02420 for (next = NEXT_INSN (rescan);
02421 next && !INSN_P (next);
02422 next = NEXT_INSN (next))
02423 continue;
02424 while (nops--)
02425 emit_insn_before (gen_nop (), insn);
02426 }
02427 }
02428
02429
02430 while (mt_labels)
02431 {
02432 label_info *label = mt_labels;
02433 branch_info *branch, *next;
02434
02435 mt_labels = label->next;
02436 for (branch = label->branches; branch; branch = next)
02437 {
02438 next = branch->next;
02439 free (branch);
02440 }
02441 free (label);
02442 }
02443 }
02444
02445
02446
02447
02448 static void
02449 mt_machine_reorg (void)
02450 {
02451 if (cfun->machine->has_loops && TARGET_MS2)
02452 mt_reorg_loops (dump_file);
02453
02454 if (mt_flag_delayed_branch)
02455 dbr_schedule (get_insns ());
02456
02457 if (TARGET_MS2)
02458 {
02459
02460 split_all_insns_noflow ();
02461 mt_reorg_hazard ();
02462 }
02463 }
02464
02465
02466 const struct attribute_spec mt_attribute_table[];
02467
02468 #undef TARGET_ATTRIBUTE_TABLE
02469 #define TARGET_ATTRIBUTE_TABLE mt_attribute_table
02470 #undef TARGET_STRUCT_VALUE_RTX
02471 #define TARGET_STRUCT_VALUE_RTX mt_struct_value_rtx
02472 #undef TARGET_PROMOTE_PROTOTYPES
02473 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
02474 #undef TARGET_PASS_BY_REFERENCE
02475 #define TARGET_PASS_BY_REFERENCE mt_pass_by_reference
02476 #undef TARGET_MUST_PASS_IN_STACK
02477 #define TARGET_MUST_PASS_IN_STACK mt_pass_in_stack
02478 #undef TARGET_ARG_PARTIAL_BYTES
02479 #define TARGET_ARG_PARTIAL_BYTES mt_arg_partial_bytes
02480 #undef TARGET_SETUP_INCOMING_VARARGS
02481 #define TARGET_SETUP_INCOMING_VARARGS mt_setup_incoming_varargs
02482 #undef TARGET_MACHINE_DEPENDENT_REORG
02483 #define TARGET_MACHINE_DEPENDENT_REORG mt_machine_reorg
02484
02485 struct gcc_target targetm = TARGET_INITIALIZER;
02486
02487 #include "gt-mt.h"