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 <signal.h>
00027 #include "rtl.h"
00028 #include "regs.h"
00029 #include "hard-reg-set.h"
00030 #include "real.h"
00031 #include "insn-config.h"
00032 #include "conditions.h"
00033 #include "insn-attr.h"
00034 #include "recog.h"
00035 #include "toplev.h"
00036 #include "output.h"
00037 #include "tree.h"
00038 #include "function.h"
00039 #include "expr.h"
00040 #include "optabs.h"
00041 #include "flags.h"
00042 #include "reload.h"
00043 #include "tm_p.h"
00044 #include "ggc.h"
00045 #include "gstab.h"
00046 #include "hashtab.h"
00047 #include "debug.h"
00048 #include "target.h"
00049 #include "target-def.h"
00050 #include "integrate.h"
00051 #include "langhooks.h"
00052 #include "cfglayout.h"
00053 #include "score-mdaux.h"
00054
00055 #define GR_REG_CLASS_P(C) ((C) == G16_REGS || (C) == G32_REGS)
00056 #define SP_REG_CLASS_P(C) \
00057 ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS)
00058 #define CP_REG_CLASS_P(C) \
00059 ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS)
00060 #define CE_REG_CLASS_P(C) \
00061 ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS)
00062
00063 static int score_arg_partial_bytes (const CUMULATIVE_ARGS *,
00064 enum machine_mode, tree, int);
00065
00066 static int score_symbol_insns (enum score_symbol_type);
00067
00068 static int score_address_insns (rtx, enum machine_mode);
00069
00070 static bool score_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *);
00071
00072 static int score_address_cost (rtx);
00073
00074 #undef TARGET_ASM_FILE_START
00075 #define TARGET_ASM_FILE_START th_asm_file_start
00076
00077 #undef TARGET_ASM_FILE_END
00078 #define TARGET_ASM_FILE_END th_asm_file_end
00079
00080 #undef TARGET_ASM_FUNCTION_PROLOGUE
00081 #define TARGET_ASM_FUNCTION_PROLOGUE th_function_prologue
00082
00083 #undef TARGET_ASM_FUNCTION_EPILOGUE
00084 #define TARGET_ASM_FUNCTION_EPILOGUE th_function_epilogue
00085
00086 #undef TARGET_SCHED_ISSUE_RATE
00087 #define TARGET_SCHED_ISSUE_RATE th_issue_rate
00088
00089 #undef TARGET_ASM_SELECT_RTX_SECTION
00090 #define TARGET_ASM_SELECT_RTX_SECTION th_select_rtx_section
00091
00092 #undef TARGET_IN_SMALL_DATA_P
00093 #define TARGET_IN_SMALL_DATA_P th_in_small_data_p
00094
00095 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
00096 #define TARGET_FUNCTION_OK_FOR_SIBCALL th_function_ok_for_sibcall
00097
00098 #undef TARGET_STRICT_ARGUMENT_NAMING
00099 #define TARGET_STRICT_ARGUMENT_NAMING th_strict_argument_naming
00100
00101 #undef TARGET_ASM_OUTPUT_MI_THUNK
00102 #define TARGET_ASM_OUTPUT_MI_THUNK th_output_mi_thunk
00103
00104 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
00105 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
00106
00107 #undef TARGET_PROMOTE_FUNCTION_ARGS
00108 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
00109
00110 #undef TARGET_PROMOTE_FUNCTION_RETURN
00111 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
00112
00113 #undef TARGET_PROMOTE_PROTOTYPES
00114 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
00115
00116 #undef TARGET_MUST_PASS_IN_STACK
00117 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
00118
00119 #undef TARGET_ARG_PARTIAL_BYTES
00120 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
00121
00122 #undef TARGET_PASS_BY_REFERENCE
00123 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
00124
00125 #undef TARGET_RETURN_IN_MEMORY
00126 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
00127
00128 #undef TARGET_RTX_COSTS
00129 #define TARGET_RTX_COSTS score_rtx_costs
00130
00131 #undef TARGET_ADDRESS_COST
00132 #define TARGET_ADDRESS_COST score_address_cost
00133
00134 #undef TARGET_DEFAULT_TARGET_FLAGS
00135 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
00136
00137
00138
00139
00140 static bool
00141 score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
00142 {
00143 return ((TYPE_MODE (type) == BLKmode)
00144 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
00145 || (int_size_in_bytes (type) == -1));
00146 }
00147
00148
00149 static bool
00150 score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
00151 enum machine_mode mode, tree type,
00152 bool named ATTRIBUTE_UNUSED)
00153 {
00154
00155 return targetm.calls.must_pass_in_stack (mode, type);
00156 }
00157
00158
00159 static rtx
00160 score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
00161 {
00162 if (!IMM_IN_RANGE (offset, 15, 1))
00163 {
00164 reg = expand_simple_binop (GET_MODE (reg), PLUS,
00165 gen_int_mode (offset & 0xffffc000,
00166 GET_MODE (reg)),
00167 reg, NULL, 0, OPTAB_WIDEN);
00168 offset &= 0x3fff;
00169 }
00170
00171 return plus_constant (reg, offset);
00172 }
00173
00174
00175
00176 static void
00177 th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
00178 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
00179 tree function)
00180 {
00181 rtx this, temp1, temp2, insn, fnaddr;
00182
00183
00184 no_new_pseudos = 1;
00185 reload_completed = 1;
00186 reset_block_changes ();
00187
00188
00189 temp1 = gen_rtx_REG (Pmode, 8);
00190 temp2 = gen_rtx_REG (Pmode, 9);
00191
00192
00193 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
00194 this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
00195 else
00196 this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
00197
00198
00199 if (delta != 0)
00200 {
00201 rtx offset = GEN_INT (delta);
00202 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
00203 {
00204 emit_move_insn (temp1, offset);
00205 offset = temp1;
00206 }
00207 emit_insn (gen_add3_insn (this, this, offset));
00208 }
00209
00210
00211 if (vcall_offset != 0)
00212 {
00213 rtx addr;
00214
00215
00216 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
00217
00218
00219 addr = score_add_offset (temp2, temp1, vcall_offset);
00220
00221
00222 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
00223 emit_insn (gen_add3_insn (this, this, temp1));
00224 }
00225
00226
00227 fnaddr = XEXP (DECL_RTL (function), 0);
00228 insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx));
00229 SIBLING_CALL_P (insn) = 1;
00230
00231
00232
00233 insn = get_insns ();
00234 insn_locators_initialize ();
00235 split_all_insns_noflow ();
00236 shorten_branches (insn);
00237 final_start_function (insn, file, 1);
00238 final (insn, file, 1);
00239 final_end_function ();
00240
00241
00242
00243 reload_completed = 0;
00244 no_new_pseudos = 0;
00245 }
00246
00247
00248 static bool
00249 th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
00250 {
00251 return true;
00252 }
00253
00254
00255 static bool
00256 th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
00257 ATTRIBUTE_UNUSED tree exp)
00258 {
00259 return true;
00260 }
00261
00262 struct score_arg_info
00263 {
00264
00265 unsigned int num_bytes;
00266
00267
00268 unsigned int reg_words;
00269
00270
00271
00272 unsigned int reg_offset;
00273
00274
00275 unsigned int stack_words;
00276
00277
00278
00279 unsigned int stack_offset;
00280 };
00281
00282
00283
00284
00285
00286 static void
00287 classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
00288 tree type, int named, struct score_arg_info *info)
00289 {
00290 int even_reg_p;
00291 unsigned int num_words, max_regs;
00292
00293 even_reg_p = 0;
00294 if (GET_MODE_CLASS (mode) == MODE_INT
00295 || GET_MODE_CLASS (mode) == MODE_FLOAT)
00296 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
00297 else
00298 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
00299 even_reg_p = 1;
00300
00301 if (TARGET_MUST_PASS_IN_STACK (mode, type))
00302 info->reg_offset = ARG_REG_NUM;
00303 else
00304 {
00305 info->reg_offset = cum->num_gprs;
00306 if (even_reg_p)
00307 info->reg_offset += info->reg_offset & 1;
00308 }
00309
00310 if (mode == BLKmode)
00311 info->num_bytes = int_size_in_bytes (type);
00312 else
00313 info->num_bytes = GET_MODE_SIZE (mode);
00314
00315 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
00316 max_regs = ARG_REG_NUM - info->reg_offset;
00317
00318
00319 info->reg_words = MIN (num_words, max_regs);
00320 info->stack_words = num_words - info->reg_words;
00321
00322
00323 if (info->stack_words)
00324 {
00325 info->stack_offset = cum->stack_words;
00326 if (even_reg_p)
00327 info->stack_offset += info->stack_offset & 1;
00328 }
00329 }
00330
00331
00332 static void
00333 th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
00334 {
00335 const char *fnname;
00336 struct score_frame_info *f = mda_cached_frame ();
00337 HOST_WIDE_INT tsize = f->total_size;
00338
00339 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
00340 if (!flag_inhibit_size_directive)
00341 {
00342 fputs ("\t.ent\t", file);
00343 assemble_name (file, fnname);
00344 fputs ("\n", file);
00345 }
00346 assemble_name (file, fnname);
00347 fputs (":\n", file);
00348
00349 if (!flag_inhibit_size_directive)
00350 {
00351 fprintf (file,
00352 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
00353 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
00354 ", args= " HOST_WIDE_INT_PRINT_DEC
00355 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
00356 (reg_names[(frame_pointer_needed)
00357 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
00358 tsize,
00359 reg_names[RA_REGNUM],
00360 current_function_is_leaf ? 1 : 0,
00361 f->var_size,
00362 f->num_gp,
00363 f->args_size,
00364 f->cprestore_size);
00365
00366 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
00367 f->mask,
00368 (f->gp_sp_offset - f->total_size));
00369 }
00370 }
00371
00372
00373
00374 static void
00375 th_function_epilogue (FILE *file,
00376 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
00377 {
00378 if (!flag_inhibit_size_directive)
00379 {
00380 const char *fnname;
00381 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
00382 fputs ("\t.end\t", file);
00383 assemble_name (file, fnname);
00384 fputs ("\n", file);
00385 }
00386 }
00387
00388
00389 static int
00390 th_issue_rate (void)
00391 {
00392 return 1;
00393 }
00394
00395
00396 static bool
00397 symbolic_expression_p (rtx x)
00398 {
00399 if (GET_CODE (x) == SYMBOL_REF)
00400 return true;
00401
00402 if (GET_CODE (x) == CONST)
00403 return symbolic_expression_p (XEXP (x, 0));
00404
00405 if (UNARY_P (x))
00406 return symbolic_expression_p (XEXP (x, 0));
00407
00408 if (ARITHMETIC_P (x))
00409 return (symbolic_expression_p (XEXP (x, 0))
00410 || symbolic_expression_p (XEXP (x, 1)));
00411
00412 return false;
00413 }
00414
00415
00416
00417 static section *
00418 th_select_rtx_section (enum machine_mode mode, rtx x,
00419 unsigned HOST_WIDE_INT align)
00420 {
00421 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
00422 return get_named_section (0, ".sdata", 0);
00423 else if (flag_pic && symbolic_expression_p (x))
00424 return get_named_section (0, ".data.rel.ro", 3);
00425 else
00426 return mergeable_constant_section (mode, align, 0);
00427 }
00428
00429
00430 static bool
00431 th_in_small_data_p (tree decl)
00432 {
00433 HOST_WIDE_INT size;
00434
00435 if (TREE_CODE (decl) == STRING_CST
00436 || TREE_CODE (decl) == FUNCTION_DECL)
00437 return false;
00438
00439 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
00440 {
00441 const char *name;
00442 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
00443 if (strcmp (name, ".sdata") != 0
00444 && strcmp (name, ".sbss") != 0)
00445 return true;
00446 if (!DECL_EXTERNAL (decl))
00447 return false;
00448 }
00449 size = int_size_in_bytes (TREE_TYPE (decl));
00450 return (size > 0 && size <= SCORE_SDATA_MAX);
00451 }
00452
00453
00454 static void
00455 th_asm_file_start (void)
00456 {
00457 default_file_start ();
00458 fprintf (asm_out_file, ASM_COMMENT_START
00459 "GCC for S+core %s \n", SCORE_GCC_VERSION);
00460
00461 if (flag_pic)
00462 fprintf (asm_out_file, "\t.set pic\n");
00463 }
00464
00465
00466
00467 struct extern_list *extern_head = 0;
00468
00469 static void
00470 th_asm_file_end (void)
00471 {
00472 tree name_tree;
00473 struct extern_list *p;
00474 if (extern_head)
00475 {
00476 fputs ("\n", asm_out_file);
00477 for (p = extern_head; p != 0; p = p->next)
00478 {
00479 name_tree = get_identifier (p->name);
00480 if (!TREE_ASM_WRITTEN (name_tree)
00481 && TREE_SYMBOL_REFERENCED (name_tree))
00482 {
00483 TREE_ASM_WRITTEN (name_tree) = 1;
00484 fputs ("\t.extern\t", asm_out_file);
00485 assemble_name (asm_out_file, p->name);
00486 fprintf (asm_out_file, ", %d\n", p->size);
00487 }
00488 }
00489 }
00490 }
00491
00492 static unsigned int sdata_max;
00493
00494 int
00495 score_sdata_max (void)
00496 {
00497 return sdata_max;
00498 }
00499
00500
00501 enum reg_class score_char_to_class[256];
00502
00503
00504 void
00505 score_override_options (void)
00506 {
00507 flag_pic = false;
00508 if (!flag_pic)
00509 sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
00510 else
00511 {
00512 sdata_max = 0;
00513 if (g_switch_set && (g_switch_value != 0))
00514 warning (0, "-fPIC and -G are incompatible");
00515 }
00516
00517 score_char_to_class['d'] = G32_REGS;
00518 score_char_to_class['e'] = G16_REGS;
00519 score_char_to_class['t'] = T32_REGS;
00520
00521 score_char_to_class['h'] = HI_REG;
00522 score_char_to_class['l'] = LO_REG;
00523 score_char_to_class['x'] = CE_REGS;
00524
00525 score_char_to_class['q'] = CN_REG;
00526 score_char_to_class['y'] = LC_REG;
00527 score_char_to_class['z'] = SC_REG;
00528 score_char_to_class['a'] = SP_REGS;
00529
00530 score_char_to_class['c'] = CR_REGS;
00531
00532 score_char_to_class['b'] = CP1_REGS;
00533 score_char_to_class['f'] = CP2_REGS;
00534 score_char_to_class['i'] = CP3_REGS;
00535 score_char_to_class['j'] = CPA_REGS;
00536 }
00537
00538
00539 int
00540 score_reg_class (int regno)
00541 {
00542 int c;
00543 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
00544
00545 if (regno == FRAME_POINTER_REGNUM
00546 || regno == ARG_POINTER_REGNUM)
00547 return ALL_REGS;
00548
00549 for (c = 0; c < N_REG_CLASSES; c++)
00550 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
00551 return c;
00552
00553 return NO_REGS;
00554 }
00555
00556
00557 enum reg_class
00558 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
00559 {
00560 if (reg_class_subset_p (G16_REGS, class))
00561 return G16_REGS;
00562 if (reg_class_subset_p (G32_REGS, class))
00563 return G32_REGS;
00564 return class;
00565 }
00566
00567
00568
00569 enum reg_class
00570 score_secondary_reload_class (enum reg_class class,
00571 enum machine_mode mode ATTRIBUTE_UNUSED,
00572 rtx x)
00573 {
00574 int regno = -1;
00575 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
00576 regno = true_regnum (x);
00577
00578 if (!GR_REG_CLASS_P (class))
00579 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
00580 return NO_REGS;
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591 int
00592 score_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
00593 {
00594 switch (c)
00595 {
00596 case 'I': return ((value & 0xffff) == 0);
00597 case 'J': return IMM_IN_RANGE (value, 5, 0);
00598 case 'K': return IMM_IN_RANGE (value, 16, 0);
00599 case 'L': return IMM_IN_RANGE (value, 16, 1);
00600 case 'M': return IMM_IN_RANGE (value, 14, 0);
00601 case 'N': return IMM_IN_RANGE (value, 14, 1);
00602 default : return 0;
00603 }
00604 }
00605
00606
00607
00608 int
00609 score_extra_constraint (rtx op, char c)
00610 {
00611 switch (c)
00612 {
00613 case 'Z':
00614 return GET_CODE (op) == SYMBOL_REF;
00615 default:
00616 gcc_unreachable ();
00617 }
00618 }
00619
00620
00621
00622 int
00623 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
00624 {
00625 int size = GET_MODE_SIZE (mode);
00626 enum mode_class class = GET_MODE_CLASS (mode);
00627
00628 if (class == MODE_CC)
00629 return regno == CC_REGNUM;
00630 else if (regno == FRAME_POINTER_REGNUM
00631 || regno == ARG_POINTER_REGNUM)
00632 return class == MODE_INT;
00633 else if (GP_REG_P (regno))
00634
00635 return !(regno & 1) || (size <= UNITS_PER_WORD);
00636 else if (CE_REG_P (regno))
00637 return (class == MODE_INT
00638 && ((size <= UNITS_PER_WORD)
00639 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
00640 else
00641 return (class == MODE_INT) && (size <= UNITS_PER_WORD);
00642 }
00643
00644
00645
00646
00647 HOST_WIDE_INT
00648 score_initial_elimination_offset (int from,
00649 int to ATTRIBUTE_UNUSED)
00650 {
00651 struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
00652 switch (from)
00653 {
00654 case ARG_POINTER_REGNUM:
00655 return f->total_size;
00656 case FRAME_POINTER_REGNUM:
00657 return 0;
00658 default:
00659 gcc_unreachable ();
00660 }
00661 }
00662
00663
00664
00665
00666 void
00667 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
00668 tree fntype ATTRIBUTE_UNUSED,
00669 rtx libname ATTRIBUTE_UNUSED)
00670 {
00671 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
00672 }
00673
00674
00675 void
00676 score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
00677 tree type, int named)
00678 {
00679 struct score_arg_info info;
00680 classify_arg (cum, mode, type, named, &info);
00681 cum->num_gprs = info.reg_offset + info.reg_words;
00682 if (info.stack_words > 0)
00683 cum->stack_words = info.stack_offset + info.stack_words;
00684 cum->arg_number++;
00685 }
00686
00687
00688 static int
00689 score_arg_partial_bytes (const CUMULATIVE_ARGS *cum,
00690 enum machine_mode mode, tree type, int named)
00691 {
00692 struct score_arg_info info;
00693 classify_arg (cum, mode, type, named, &info);
00694 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
00695 }
00696
00697
00698 rtx
00699 score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
00700 tree type, int named)
00701 {
00702 struct score_arg_info info;
00703
00704 if (mode == VOIDmode || !named)
00705 return 0;
00706
00707 classify_arg (cum, mode, type, named, &info);
00708
00709 if (info.reg_offset == ARG_REG_NUM)
00710 return 0;
00711
00712 if (!info.stack_words)
00713 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
00714 else
00715 {
00716 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
00717 unsigned int i, part_offset = 0;
00718 for (i = 0; i < info.reg_words; i++)
00719 {
00720 rtx reg;
00721 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
00722 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
00723 GEN_INT (part_offset));
00724 part_offset += UNITS_PER_WORD;
00725 }
00726 return ret;
00727 }
00728 }
00729
00730
00731
00732
00733 rtx
00734 score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
00735 enum machine_mode mode)
00736 {
00737 if (valtype)
00738 {
00739 int unsignedp;
00740 mode = TYPE_MODE (valtype);
00741 unsignedp = TYPE_UNSIGNED (valtype);
00742 mode = promote_mode (valtype, mode, &unsignedp, 1);
00743 }
00744 return gen_rtx_REG (mode, RT_REGNUM);
00745 }
00746
00747
00748 void
00749 score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
00750 {
00751 #define FFCACHE "_flush_cache"
00752 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
00753
00754 unsigned int tramp[TRAMPOLINE_INSNS] = {
00755 0x8103bc56,
00756 0x9000bc05,
00757 0xc1238000 | (CODE_SIZE - 8),
00758 0xc0038000
00759 | (STATIC_CHAIN_REGNUM << 21)
00760 | (CODE_SIZE - 4),
00761 0x8068bc56,
00762 0x8009bc08,
00763 0x0,
00764 0x0,
00765 };
00766 rtx pfunc, pchain;
00767 int i;
00768
00769 for (i = 0; i < TRAMPOLINE_INSNS; i++)
00770 emit_move_insn (gen_rtx_MEM (ptr_mode, plus_constant (ADDR, i << 2)),
00771 GEN_INT (tramp[i]));
00772
00773 pfunc = plus_constant (ADDR, CODE_SIZE);
00774 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (ptr_mode));
00775
00776 emit_move_insn (gen_rtx_MEM (ptr_mode, pfunc), FUNC);
00777 emit_move_insn (gen_rtx_MEM (ptr_mode, pchain), CHAIN);
00778 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
00779 0, VOIDmode, 2,
00780 ADDR, Pmode,
00781 GEN_INT (TRAMPOLINE_SIZE), SImode);
00782 #undef FFCACHE
00783 #undef CODE_SIZE
00784 }
00785
00786
00787 int
00788 score_regno_mode_ok_for_base_p (int regno, int strict)
00789 {
00790 if (regno >= FIRST_PSEUDO_REGISTER)
00791 {
00792 if (!strict)
00793 return 1;
00794 regno = reg_renumber[regno];
00795 }
00796 if (regno == ARG_POINTER_REGNUM
00797 || regno == FRAME_POINTER_REGNUM)
00798 return 1;
00799 return GP_REG_P (regno);
00800 }
00801
00802
00803 int
00804 score_address_p (enum machine_mode mode, rtx x, int strict)
00805 {
00806 struct score_address_info addr;
00807
00808 return mda_classify_address (&addr, mode, x, strict);
00809 }
00810
00811
00812
00813 static rtx
00814 score_force_temporary (rtx dest, rtx value)
00815 {
00816 if (!no_new_pseudos)
00817 return force_reg (Pmode, value);
00818 else
00819 {
00820 emit_move_insn (copy_rtx (dest), value);
00821 return dest;
00822 }
00823 }
00824
00825
00826
00827 static rtx
00828 score_split_symbol (rtx temp, rtx addr)
00829 {
00830 rtx high = score_force_temporary (temp,
00831 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
00832 return gen_rtx_LO_SUM (Pmode, high, addr);
00833 }
00834
00835
00836
00837
00838 int
00839 score_legitimize_address (rtx *xloc)
00840 {
00841 enum score_symbol_type symbol_type;
00842
00843 if (mda_symbolic_constant_p (*xloc, &symbol_type)
00844 && symbol_type == SYMBOL_GENERAL)
00845 {
00846 *xloc = score_split_symbol (0, *xloc);
00847 return 1;
00848 }
00849
00850 if (GET_CODE (*xloc) == PLUS
00851 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
00852 {
00853 rtx reg = XEXP (*xloc, 0);
00854 if (!mda_valid_base_register_p (reg, 0))
00855 reg = copy_to_mode_reg (Pmode, reg);
00856 *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1)));
00857 return 1;
00858 }
00859 return 0;
00860 }
00861
00862
00863
00864 int
00865 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
00866 enum reg_class from, enum reg_class to)
00867 {
00868 if (GR_REG_CLASS_P (from))
00869 {
00870 if (GR_REG_CLASS_P (to))
00871 return 2;
00872 else if (SP_REG_CLASS_P (to))
00873 return 4;
00874 else if (CP_REG_CLASS_P (to))
00875 return 5;
00876 else if (CE_REG_CLASS_P (to))
00877 return 6;
00878 }
00879 if (GR_REG_CLASS_P (to))
00880 {
00881 if (GR_REG_CLASS_P (from))
00882 return 2;
00883 else if (SP_REG_CLASS_P (from))
00884 return 4;
00885 else if (CP_REG_CLASS_P (from))
00886 return 5;
00887 else if (CE_REG_CLASS_P (from))
00888 return 6;
00889 }
00890 return 12;
00891 }
00892
00893
00894
00895 static int
00896 score_symbol_insns (enum score_symbol_type type)
00897 {
00898 switch (type)
00899 {
00900 case SYMBOL_GENERAL:
00901 return 2;
00902
00903 case SYMBOL_SMALL_DATA:
00904 return 1;
00905 }
00906
00907 gcc_unreachable ();
00908 }
00909
00910
00911
00912 static int
00913 score_address_insns (rtx x, enum machine_mode mode)
00914 {
00915 struct score_address_info addr;
00916 int factor;
00917
00918 if (mode == BLKmode)
00919 factor = 1;
00920 else
00921 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
00922
00923 if (mda_classify_address (&addr, mode, x, false))
00924 switch (addr.type)
00925 {
00926 case ADD_REG:
00927 case ADD_CONST_INT:
00928 return factor;
00929
00930 case ADD_SYMBOLIC:
00931 return factor * score_symbol_insns (addr.symbol_type);
00932 }
00933 return 0;
00934 }
00935
00936
00937 static bool
00938 score_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
00939 int *total)
00940 {
00941 enum machine_mode mode = GET_MODE (x);
00942
00943 switch (code)
00944 {
00945 case CONST_INT:
00946 if (outer_code == SET)
00947 {
00948 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
00949 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
00950 *total = COSTS_N_INSNS (1);
00951 else
00952 *total = COSTS_N_INSNS (2);
00953 }
00954 else if (outer_code == PLUS || outer_code == MINUS)
00955 {
00956 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
00957 *total = 0;
00958 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
00959 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
00960 *total = 1;
00961 else
00962 *total = COSTS_N_INSNS (2);
00963 }
00964 else if (outer_code == AND || outer_code == IOR)
00965 {
00966 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
00967 *total = 0;
00968 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
00969 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
00970 *total = 1;
00971 else
00972 *total = COSTS_N_INSNS (2);
00973 }
00974 else
00975 {
00976 *total = 0;
00977 }
00978 return true;
00979
00980 case CONST:
00981 case SYMBOL_REF:
00982 case LABEL_REF:
00983 case CONST_DOUBLE:
00984 *total = COSTS_N_INSNS (2);
00985 return true;
00986
00987 case MEM:
00988 {
00989
00990
00991 int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
00992 if (n > 0)
00993 {
00994 *total = COSTS_N_INSNS (n + 1);
00995 return true;
00996 }
00997 return false;
00998 }
00999
01000 case FFS:
01001 *total = COSTS_N_INSNS (6);
01002 return true;
01003
01004 case NOT:
01005 *total = COSTS_N_INSNS (1);
01006 return true;
01007
01008 case AND:
01009 case IOR:
01010 case XOR:
01011 if (mode == DImode)
01012 {
01013 *total = COSTS_N_INSNS (2);
01014 return true;
01015 }
01016 return false;
01017
01018 case ASHIFT:
01019 case ASHIFTRT:
01020 case LSHIFTRT:
01021 if (mode == DImode)
01022 {
01023 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
01024 ? 4 : 12);
01025 return true;
01026 }
01027 return false;
01028
01029 case ABS:
01030 *total = COSTS_N_INSNS (4);
01031 return true;
01032
01033 case PLUS:
01034 case MINUS:
01035 if (mode == DImode)
01036 {
01037 *total = COSTS_N_INSNS (4);
01038 return true;
01039 }
01040 *total = COSTS_N_INSNS (1);
01041 return true;
01042
01043 case NEG:
01044 if (mode == DImode)
01045 {
01046 *total = COSTS_N_INSNS (4);
01047 return true;
01048 }
01049 return false;
01050
01051 case MULT:
01052 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
01053 return true;
01054
01055 case DIV:
01056 case MOD:
01057 case UDIV:
01058 case UMOD:
01059 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
01060 return true;
01061
01062 case SIGN_EXTEND:
01063 case ZERO_EXTEND:
01064 switch (GET_MODE (XEXP (x, 0)))
01065 {
01066 case QImode:
01067 case HImode:
01068 if (GET_CODE (XEXP (x, 0)) == MEM)
01069 {
01070 *total = COSTS_N_INSNS (2);
01071
01072 if (!TARGET_LITTLE_ENDIAN &&
01073 side_effects_p (XEXP (XEXP (x, 0), 0)))
01074 *total = 100;
01075 }
01076 else
01077 *total = COSTS_N_INSNS (1);
01078 break;
01079
01080 default:
01081 *total = COSTS_N_INSNS (1);
01082 break;
01083 }
01084 return true;
01085
01086 default:
01087 return false;
01088 }
01089 }
01090
01091
01092 int
01093 score_address_cost (rtx addr)
01094 {
01095 return score_address_insns (addr, SImode);
01096 }
01097
01098
01099 int
01100 score_output_external (FILE *file ATTRIBUTE_UNUSED,
01101 tree decl, const char *name)
01102 {
01103 register struct extern_list *p;
01104
01105 if (th_in_small_data_p (decl))
01106 {
01107 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
01108 p->next = extern_head;
01109 p->name = name;
01110 p->size = int_size_in_bytes (TREE_TYPE (decl));
01111 extern_head = p;
01112 }
01113 return 0;
01114 }
01115
01116
01117 void
01118 score_declare_object (FILE *stream, const char *name,
01119 const char *directive, const char *fmt, ...)
01120 {
01121 va_list ap;
01122 fputs (directive, stream);
01123 assemble_name (stream, name);
01124 va_start (ap, fmt);
01125 vfprintf (stream, fmt, ap);
01126 va_end (ap);
01127 }
01128
01129
01130
01131 rtx
01132 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
01133 {
01134 if (count != 0)
01135 return const0_rtx;
01136 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
01137 }
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152 void
01153 score_print_operand (FILE *file, rtx op, int c)
01154 {
01155 enum rtx_code code = -1;
01156 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
01157 code = GET_CODE (op);
01158
01159 if (c == '[')
01160 {
01161 fprintf (file, ".set r1\n");
01162 }
01163 else if (c == ']')
01164 {
01165 fprintf (file, "\n\t.set nor1");
01166 }
01167 else if (c == 'U')
01168 {
01169 gcc_assert (code == CONST_INT);
01170 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
01171 (unsigned HOST_WIDE_INT) INTVAL (op) >> 16);
01172 }
01173 else if (c == 'D')
01174 {
01175 if (GET_CODE (op) == CONST_DOUBLE)
01176 {
01177 rtx temp = gen_lowpart (SImode, op);
01178 gcc_assert (GET_MODE (op) == SFmode);
01179 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp));
01180 }
01181 else
01182 output_addr_const (file, op);
01183 }
01184 else if (c == 'S')
01185 {
01186 gcc_assert (code == REG);
01187 if (G16_REG_P (REGNO (op)))
01188 fprintf (file, "!");
01189 }
01190 else if (c == 'V')
01191 {
01192 gcc_assert (code == REG);
01193 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
01194 }
01195 else if (c == 'C')
01196 {
01197 enum machine_mode mode = GET_MODE (XEXP (op, 0));
01198
01199 switch (code)
01200 {
01201 case EQ: fputs ("eq", file); break;
01202 case NE: fputs ("ne", file); break;
01203 case GT: fputs ("gt", file); break;
01204 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
01205 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
01206 case LE: fputs ("le", file); break;
01207 case GTU: fputs ("gtu", file); break;
01208 case GEU: fputs ("cs", file); break;
01209 case LTU: fputs ("cc", file); break;
01210 case LEU: fputs ("leu", file); break;
01211 default:
01212 output_operand_lossage ("invalid operand for code: '%c'", code);
01213 }
01214 }
01215 else if (c == 'E')
01216 {
01217 unsigned HOST_WIDE_INT i;
01218 unsigned HOST_WIDE_INT pow2mask = 1;
01219 unsigned HOST_WIDE_INT val;
01220
01221 val = INTVAL (op);
01222 for (i = 0; i < 32; i++)
01223 {
01224 if (val == pow2mask)
01225 break;
01226 pow2mask <<= 1;
01227 }
01228 gcc_assert (i < 32);
01229 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
01230 }
01231 else if (c == 'F')
01232 {
01233 unsigned HOST_WIDE_INT i;
01234 unsigned HOST_WIDE_INT pow2mask = 1;
01235 unsigned HOST_WIDE_INT val;
01236
01237 val = ~INTVAL (op);
01238 for (i = 0; i < 32; i++)
01239 {
01240 if (val == pow2mask)
01241 break;
01242 pow2mask <<= 1;
01243 }
01244 gcc_assert (i < 32);
01245 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
01246 }
01247 else if (code == REG)
01248 {
01249 int regnum = REGNO (op);
01250 if ((c == 'H' && !WORDS_BIG_ENDIAN)
01251 || (c == 'L' && WORDS_BIG_ENDIAN))
01252 regnum ++;
01253 fprintf (file, "%s", reg_names[regnum]);
01254 }
01255 else
01256 {
01257 switch (code)
01258 {
01259 case MEM:
01260 score_print_operand_address (file, op);
01261 break;
01262 default:
01263 output_addr_const (file, op);
01264 }
01265 }
01266 }
01267
01268
01269 void
01270 score_print_operand_address (FILE *file, rtx x)
01271 {
01272 struct score_address_info addr;
01273 enum rtx_code code = GET_CODE (x);
01274 enum machine_mode mode = GET_MODE (x);
01275
01276 if (code == MEM)
01277 x = XEXP (x, 0);
01278
01279 if (mda_classify_address (&addr, mode, x, true))
01280 {
01281 switch (addr.type)
01282 {
01283 case ADD_REG:
01284 {
01285 switch (addr.code)
01286 {
01287 case PRE_DEC:
01288 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
01289 INTVAL (addr.offset));
01290 break;
01291 case POST_DEC:
01292 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
01293 INTVAL (addr.offset));
01294 break;
01295 case PRE_INC:
01296 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
01297 INTVAL (addr.offset));
01298 break;
01299 case POST_INC:
01300 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
01301 INTVAL (addr.offset));
01302 break;
01303 default:
01304 fprintf (file, "[%s,%ld]", reg_names[REGNO (addr.reg)],
01305 INTVAL (addr.offset));
01306 break;
01307 }
01308 }
01309 return;
01310 case ADD_CONST_INT:
01311 case ADD_SYMBOLIC:
01312 output_addr_const (file, x);
01313 return;
01314 }
01315 }
01316 print_rtl (stderr, x);
01317 gcc_unreachable ();
01318 }
01319
01320
01321 enum machine_mode
01322 score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
01323 {
01324 if ((op == EQ || op == NE || op == LT || op == GE)
01325 && y == const0_rtx
01326 && GET_MODE (x) == SImode)
01327 {
01328 switch (GET_CODE (x))
01329 {
01330 case PLUS:
01331 case MINUS:
01332 case NEG:
01333 case AND:
01334 case IOR:
01335 case XOR:
01336 case NOT:
01337 case ASHIFT:
01338 case LSHIFTRT:
01339 case ASHIFTRT:
01340 return CC_NZmode;
01341
01342 case SIGN_EXTEND:
01343 case ZERO_EXTEND:
01344 case ROTATE:
01345 case ROTATERT:
01346 return (op == LT || op == GE) ? CC_Nmode : CCmode;
01347
01348 default:
01349 return CCmode;
01350 }
01351 }
01352
01353 if ((op == EQ || op == NE)
01354 && (GET_CODE (y) == NEG)
01355 && register_operand (XEXP (y, 0), SImode)
01356 && register_operand (x, SImode))
01357 {
01358 return CC_NZmode;
01359 }
01360
01361 return CCmode;
01362 }
01363
01364 struct gcc_target targetm = TARGET_INITIALIZER;