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 "insn-codes.h"
00032 #include "conditions.h"
00033 #include "insn-flags.h"
00034 #include "output.h"
00035 #include "insn-attr.h"
00036 #include "tree.h"
00037 #include "flags.h"
00038 #include "except.h"
00039 #include "function.h"
00040 #include "input.h"
00041 #include "target.h"
00042 #include "target-def.h"
00043 #include "expr.h"
00044 #include "toplev.h"
00045 #include "recog.h"
00046 #include "ggc.h"
00047 #include "integrate.h"
00048 #include "langhooks.h"
00049 #include "bfin-protos.h"
00050 #include "tm-preds.h"
00051 #include "gt-bfin.h"
00052
00053
00054
00055 rtx bfin_compare_op0, bfin_compare_op1;
00056
00057
00058 extern GTY(()) rtx bfin_cc_rtx;
00059 extern GTY(()) rtx bfin_rets_rtx;
00060 rtx bfin_cc_rtx, bfin_rets_rtx;
00061
00062 int max_arg_registers = 0;
00063
00064
00065 const char *short_reg_names[] = SHORT_REGISTER_NAMES;
00066 const char *high_reg_names[] = HIGH_REGISTER_NAMES;
00067 const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
00068 const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
00069
00070 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
00071
00072 const char *bfin_library_id_string;
00073
00074 static void
00075 bfin_globalize_label (FILE *stream, const char *name)
00076 {
00077 fputs (".global ", stream);
00078 assemble_name (stream, name);
00079 fputc (';',stream);
00080 fputc ('\n',stream);
00081 }
00082
00083 static void
00084 output_file_start (void)
00085 {
00086 FILE *file = asm_out_file;
00087 int i;
00088
00089 fprintf (file, ".file \"%s\";\n", input_filename);
00090
00091 for (i = 0; arg_regs[i] >= 0; i++)
00092 ;
00093 max_arg_registers = i;
00094 }
00095
00096
00097
00098
00099 void
00100 conditional_register_usage (void)
00101 {
00102
00103 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
00104 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
00105 }
00106
00107
00108
00109
00110 static e_funkind funkind (tree funtype)
00111 {
00112 tree attrs = TYPE_ATTRIBUTES (funtype);
00113 if (lookup_attribute ("interrupt_handler", attrs))
00114 return INTERRUPT_HANDLER;
00115 else if (lookup_attribute ("exception_handler", attrs))
00116 return EXCPT_HANDLER;
00117 else if (lookup_attribute ("nmi_handler", attrs))
00118 return NMI_HANDLER;
00119 else
00120 return SUBROUTINE;
00121 }
00122
00123
00124
00125
00126
00127
00128
00129 static int
00130 n_dregs_to_save (void)
00131 {
00132 unsigned i;
00133
00134 for (i = REG_R0; i <= REG_R7; i++)
00135 {
00136 if (regs_ever_live[i] && ! call_used_regs[i])
00137 return REG_R7 - i + 1;
00138
00139 if (current_function_calls_eh_return)
00140 {
00141 unsigned j;
00142 for (j = 0; ; j++)
00143 {
00144 unsigned test = EH_RETURN_DATA_REGNO (j);
00145 if (test == INVALID_REGNUM)
00146 break;
00147 if (test == i)
00148 return REG_R7 - i + 1;
00149 }
00150 }
00151
00152 }
00153 return 0;
00154 }
00155
00156
00157
00158 static int
00159 n_pregs_to_save (void)
00160 {
00161 unsigned i;
00162
00163 for (i = REG_P0; i <= REG_P5; i++)
00164 if ((regs_ever_live[i] && ! call_used_regs[i])
00165 || (i == PIC_OFFSET_TABLE_REGNUM
00166 && (current_function_uses_pic_offset_table
00167 || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))
00168 return REG_P5 - i + 1;
00169 return 0;
00170 }
00171
00172
00173
00174 static bool
00175 must_save_fp_p (void)
00176 {
00177 return (frame_pointer_needed || regs_ever_live[REG_FP]);
00178 }
00179
00180 static bool
00181 stack_frame_needed_p (void)
00182 {
00183
00184
00185 if (current_function_calls_eh_return)
00186 return true;
00187 return frame_pointer_needed;
00188 }
00189
00190
00191
00192
00193
00194 static void
00195 expand_prologue_reg_save (rtx spreg, int saveall)
00196 {
00197 int ndregs = saveall ? 8 : n_dregs_to_save ();
00198 int npregs = saveall ? 6 : n_pregs_to_save ();
00199 int dregno = REG_R7 + 1 - ndregs;
00200 int pregno = REG_P5 + 1 - npregs;
00201 int total = ndregs + npregs;
00202 int i;
00203 rtx pat, insn, val;
00204
00205 if (total == 0)
00206 return;
00207
00208 val = GEN_INT (-total * 4);
00209 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));
00210 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
00211 UNSPEC_PUSH_MULTIPLE);
00212 XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,
00213 gen_rtx_PLUS (Pmode, spreg,
00214 val));
00215 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;
00216 for (i = 0; i < total; i++)
00217 {
00218 rtx memref = gen_rtx_MEM (word_mode,
00219 gen_rtx_PLUS (Pmode, spreg,
00220 GEN_INT (- i * 4 - 4)));
00221 rtx subpat;
00222 if (ndregs > 0)
00223 {
00224 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
00225 dregno++));
00226 ndregs--;
00227 }
00228 else
00229 {
00230 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
00231 pregno++));
00232 npregs++;
00233 }
00234 XVECEXP (pat, 0, i + 1) = subpat;
00235 RTX_FRAME_RELATED_P (subpat) = 1;
00236 }
00237 insn = emit_insn (pat);
00238 RTX_FRAME_RELATED_P (insn) = 1;
00239 }
00240
00241
00242
00243
00244
00245 static void
00246 expand_epilogue_reg_restore (rtx spreg, int saveall)
00247 {
00248 int ndregs = saveall ? 8 : n_dregs_to_save ();
00249 int npregs = saveall ? 6 : n_pregs_to_save ();
00250 int total = ndregs + npregs;
00251 int i, regno;
00252 rtx pat, insn;
00253
00254 if (total == 0)
00255 return;
00256
00257 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));
00258 XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,
00259 gen_rtx_PLUS (Pmode, spreg,
00260 GEN_INT (total * 4)));
00261
00262 if (npregs > 0)
00263 regno = REG_P5 + 1;
00264 else
00265 regno = REG_R7 + 1;
00266
00267 for (i = 0; i < total; i++)
00268 {
00269 rtx addr = (i > 0
00270 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
00271 : spreg);
00272 rtx memref = gen_rtx_MEM (word_mode, addr);
00273
00274 regno--;
00275 XVECEXP (pat, 0, i + 1)
00276 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
00277
00278 if (npregs > 0)
00279 {
00280 if (--npregs == 0)
00281 regno = REG_R7 + 1;
00282 }
00283 }
00284
00285 insn = emit_insn (pat);
00286 RTX_FRAME_RELATED_P (insn) = 1;
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 static void
00312 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
00313 enum machine_mode mode ATTRIBUTE_UNUSED,
00314 tree type ATTRIBUTE_UNUSED, int *pretend_size,
00315 int no_rtl)
00316 {
00317 rtx mem;
00318 int i;
00319
00320 if (no_rtl)
00321 return;
00322
00323
00324
00325
00326
00327
00328 for (i = cum->words + 1; i < max_arg_registers; i++)
00329 {
00330 mem = gen_rtx_MEM (Pmode,
00331 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
00332 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
00333 }
00334
00335 *pretend_size = 0;
00336 }
00337
00338
00339
00340
00341
00342 int
00343 bfin_frame_pointer_required (void)
00344 {
00345 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00346
00347 if (fkind != SUBROUTINE)
00348 return 1;
00349
00350
00351
00352 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
00353 return 1;
00354
00355 return 0;
00356 }
00357
00358
00359
00360 static int
00361 n_regs_saved_by_prologue (void)
00362 {
00363 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00364 int n = n_dregs_to_save () + n_pregs_to_save ();
00365
00366 if (stack_frame_needed_p ())
00367
00368 n += 2;
00369 else
00370 {
00371 if (must_save_fp_p ())
00372 n++;
00373 if (! current_function_is_leaf)
00374 n++;
00375 }
00376
00377 if (fkind != SUBROUTINE)
00378 {
00379 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00380 tree all = lookup_attribute ("saveall", attrs);
00381 int i;
00382
00383
00384 n++;
00385
00386
00387 if (lookup_attribute ("nesting", attrs))
00388 n++;
00389
00390 for (i = REG_P7 + 1; i < REG_CC; i++)
00391 if (all
00392 || regs_ever_live[i]
00393 || (!leaf_function_p () && call_used_regs[i]))
00394 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
00395 }
00396 return n;
00397 }
00398
00399
00400
00401
00402 HOST_WIDE_INT
00403 bfin_initial_elimination_offset (int from, int to)
00404 {
00405 HOST_WIDE_INT offset = 0;
00406
00407 if (from == ARG_POINTER_REGNUM)
00408 offset = n_regs_saved_by_prologue () * 4;
00409
00410 if (to == STACK_POINTER_REGNUM)
00411 {
00412 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
00413 offset += current_function_outgoing_args_size;
00414 else if (current_function_outgoing_args_size)
00415 offset += FIXED_STACK_AREA;
00416
00417 offset += get_frame_size ();
00418 }
00419
00420 return offset;
00421 }
00422
00423
00424
00425
00426
00427 static void
00428 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant)
00429 {
00430 rtx insn;
00431 rtx cst = GEN_INT (constant);
00432
00433 if (constant >= -32768 && constant < 65536)
00434 insn = emit_move_insn (reg, cst);
00435 else
00436 {
00437
00438
00439 insn = emit_insn (gen_movsi_high (reg, cst));
00440 RTX_FRAME_RELATED_P (insn) = 1;
00441 insn = emit_insn (gen_movsi_low (reg, reg, cst));
00442 }
00443 RTX_FRAME_RELATED_P (insn) = 1;
00444 }
00445
00446
00447
00448
00449
00450 static void
00451 add_to_sp (rtx spreg, HOST_WIDE_INT value, int frame)
00452 {
00453 if (value == 0)
00454 return;
00455
00456
00457
00458
00459 if (value > 120 || value < -120)
00460 {
00461 rtx tmpreg = gen_rtx_REG (SImode, REG_P1);
00462 rtx insn;
00463
00464 if (frame)
00465 frame_related_constant_load (tmpreg, value);
00466 else
00467 {
00468 insn = emit_move_insn (tmpreg, GEN_INT (value));
00469 if (frame)
00470 RTX_FRAME_RELATED_P (insn) = 1;
00471 }
00472
00473 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
00474 if (frame)
00475 RTX_FRAME_RELATED_P (insn) = 1;
00476 }
00477 else
00478 do
00479 {
00480 int size = value;
00481 rtx insn;
00482
00483 if (size > 60)
00484 size = 60;
00485 else if (size < -60)
00486
00487
00488 size = -60;
00489
00490 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size)));
00491 if (frame)
00492 RTX_FRAME_RELATED_P (insn) = 1;
00493 value -= size;
00494 }
00495 while (value != 0);
00496 }
00497
00498
00499
00500
00501
00502 static void
00503 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
00504 {
00505 HOST_WIDE_INT link_size = frame_size;
00506 rtx insn;
00507 int i;
00508
00509 if (link_size > 262140)
00510 link_size = 262140;
00511
00512
00513
00514 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
00515 RTX_FRAME_RELATED_P (insn) = 1;
00516
00517 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
00518 {
00519 rtx set = XVECEXP (PATTERN (insn), 0, i);
00520 if (GET_CODE (set) != SET)
00521 abort ();
00522 RTX_FRAME_RELATED_P (set) = 1;
00523 }
00524
00525 frame_size -= link_size;
00526
00527 if (frame_size > 0)
00528 {
00529
00530 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
00531
00532 frame_related_constant_load (tmpreg, -frame_size);
00533 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
00534 RTX_FRAME_RELATED_P (insn) = 1;
00535 }
00536 }
00537
00538
00539
00540
00541 static HOST_WIDE_INT
00542 arg_area_size (void)
00543 {
00544 if (current_function_outgoing_args_size)
00545 {
00546 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
00547 return current_function_outgoing_args_size;
00548 else
00549 return FIXED_STACK_AREA;
00550 }
00551 return 0;
00552 }
00553
00554
00555
00556 static void
00557 do_link (rtx spreg, HOST_WIDE_INT frame_size)
00558 {
00559 frame_size += arg_area_size ();
00560
00561 if (stack_frame_needed_p ()
00562 || (must_save_fp_p () && ! current_function_is_leaf))
00563 emit_link_insn (spreg, frame_size);
00564 else
00565 {
00566 if (! current_function_is_leaf)
00567 {
00568 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
00569 gen_rtx_PRE_DEC (Pmode, spreg)),
00570 bfin_rets_rtx);
00571 rtx insn = emit_insn (pat);
00572 RTX_FRAME_RELATED_P (insn) = 1;
00573 }
00574 if (must_save_fp_p ())
00575 {
00576 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
00577 gen_rtx_PRE_DEC (Pmode, spreg)),
00578 gen_rtx_REG (Pmode, REG_FP));
00579 rtx insn = emit_insn (pat);
00580 RTX_FRAME_RELATED_P (insn) = 1;
00581 }
00582 add_to_sp (spreg, -frame_size, 1);
00583 }
00584 }
00585
00586
00587
00588 static void
00589 do_unlink (rtx spreg, HOST_WIDE_INT frame_size)
00590 {
00591 frame_size += arg_area_size ();
00592
00593 if (stack_frame_needed_p ())
00594 emit_insn (gen_unlink ());
00595 else
00596 {
00597 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
00598
00599 add_to_sp (spreg, frame_size, 0);
00600 if (must_save_fp_p ())
00601 {
00602 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
00603 emit_move_insn (fpreg, postinc);
00604 emit_insn (gen_rtx_USE (VOIDmode, fpreg));
00605 }
00606 if (! current_function_is_leaf)
00607 {
00608 emit_move_insn (bfin_rets_rtx, postinc);
00609 emit_insn (gen_rtx_USE (VOIDmode, bfin_rets_rtx));
00610 }
00611 }
00612 }
00613
00614
00615
00616
00617
00618 static void
00619 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind)
00620 {
00621 int i;
00622 HOST_WIDE_INT frame_size = get_frame_size ();
00623 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
00624 rtx predec = gen_rtx_MEM (SImode, predec1);
00625 rtx insn;
00626 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00627 tree all = lookup_attribute ("saveall", attrs);
00628 tree kspisusp = lookup_attribute ("kspisusp", attrs);
00629
00630 if (kspisusp)
00631 {
00632 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
00633 RTX_FRAME_RELATED_P (insn) = 1;
00634 }
00635
00636
00637
00638 if (fkind == EXCPT_HANDLER)
00639 {
00640 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
00641 RTX_FRAME_RELATED_P (insn) = 1;
00642 }
00643
00644 insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
00645 RTX_FRAME_RELATED_P (insn) = 1;
00646
00647 expand_prologue_reg_save (spreg, all != NULL_TREE);
00648
00649 for (i = REG_P7 + 1; i < REG_CC; i++)
00650 if (all
00651 || regs_ever_live[i]
00652 || (!leaf_function_p () && call_used_regs[i]))
00653 {
00654 if (i == REG_A0 || i == REG_A1)
00655 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
00656 gen_rtx_REG (PDImode, i));
00657 else
00658 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
00659 RTX_FRAME_RELATED_P (insn) = 1;
00660 }
00661
00662 if (lookup_attribute ("nesting", attrs))
00663 {
00664 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
00665 : fkind == NMI_HANDLER ? REG_RETN
00666 : REG_RETI));
00667 insn = emit_move_insn (predec, srcreg);
00668 RTX_FRAME_RELATED_P (insn) = 1;
00669 }
00670
00671 do_link (spreg, frame_size);
00672
00673 if (fkind == EXCPT_HANDLER)
00674 {
00675 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
00676 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
00677 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
00678 rtx insn;
00679
00680 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
00681 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00682 NULL_RTX);
00683 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
00684 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00685 NULL_RTX);
00686 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
00687 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00688 NULL_RTX);
00689 insn = emit_move_insn (r1reg, spreg);
00690 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00691 NULL_RTX);
00692 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
00693 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00694 NULL_RTX);
00695 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
00696 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00697 NULL_RTX);
00698 }
00699 }
00700
00701
00702
00703
00704
00705 static void
00706 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind)
00707 {
00708 int i;
00709 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
00710 rtx postinc = gen_rtx_MEM (SImode, postinc1);
00711 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00712 tree all = lookup_attribute ("saveall", attrs);
00713
00714
00715
00716 MEM_VOLATILE_P (postinc) = 1;
00717
00718 do_unlink (spreg, get_frame_size ());
00719
00720 if (lookup_attribute ("nesting", attrs))
00721 {
00722 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
00723 : fkind == NMI_HANDLER ? REG_RETN
00724 : REG_RETI));
00725 emit_move_insn (srcreg, postinc);
00726 }
00727
00728 for (i = REG_CC - 1; i > REG_P7; i--)
00729 if (all
00730 || regs_ever_live[i]
00731 || (!leaf_function_p () && call_used_regs[i]))
00732 {
00733 if (i == REG_A0 || i == REG_A1)
00734 {
00735 rtx mem = gen_rtx_MEM (PDImode, postinc1);
00736 MEM_VOLATILE_P (mem) = 1;
00737 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
00738 }
00739 else
00740 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
00741 }
00742
00743 expand_epilogue_reg_restore (spreg, all != NULL_TREE);
00744
00745 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
00746
00747
00748
00749 if (fkind == EXCPT_HANDLER)
00750 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
00751
00752 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
00753 }
00754
00755
00756
00757 void
00758 bfin_expand_prologue (void)
00759 {
00760 rtx insn;
00761 HOST_WIDE_INT frame_size = get_frame_size ();
00762 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
00763 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00764
00765 if (fkind != SUBROUTINE)
00766 {
00767 expand_interrupt_handler_prologue (spreg, fkind);
00768 return;
00769 }
00770
00771 expand_prologue_reg_save (spreg, 0);
00772
00773 do_link (spreg, frame_size);
00774
00775 if (TARGET_ID_SHARED_LIBRARY
00776 && (current_function_uses_pic_offset_table
00777 || !current_function_is_leaf))
00778 {
00779 rtx addr;
00780
00781 if (bfin_library_id_string)
00782 addr = plus_constant (pic_offset_table_rtx, atoi (bfin_library_id_string));
00783 else
00784 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
00785 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
00786 UNSPEC_LIBRARY_OFFSET));
00787 insn = emit_insn (gen_movsi (pic_offset_table_rtx,
00788 gen_rtx_MEM (Pmode, addr)));
00789 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
00790 }
00791 }
00792
00793
00794
00795
00796
00797 void
00798 bfin_expand_epilogue (int need_return, int eh_return)
00799 {
00800 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
00801 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00802
00803 if (fkind != SUBROUTINE)
00804 {
00805 expand_interrupt_handler_epilogue (spreg, fkind);
00806 return;
00807 }
00808
00809 do_unlink (spreg, get_frame_size ());
00810
00811 expand_epilogue_reg_restore (spreg, 0);
00812
00813
00814 if (! need_return)
00815 return;
00816
00817 if (eh_return)
00818 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
00819
00820 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
00821 }
00822
00823
00824
00825 int
00826 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
00827 unsigned int new_reg)
00828 {
00829
00830
00831
00832
00833 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
00834 && !regs_ever_live[new_reg])
00835 return 0;
00836
00837 return 1;
00838 }
00839
00840
00841
00842
00843
00844 rtx
00845 bfin_return_addr_rtx (int count)
00846 {
00847 if (count != 0)
00848 return const0_rtx;
00849
00850 return get_hard_reg_initial_val (Pmode, REG_RETS);
00851 }
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862 rtx
00863 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
00864 enum machine_mode mode ATTRIBUTE_UNUSED)
00865 {
00866 return NULL_RTX;
00867 }
00868
00869
00870
00871
00872
00873 int
00874 effective_address_32bit_p (rtx op, enum machine_mode mode)
00875 {
00876 HOST_WIDE_INT offset;
00877
00878 mode = GET_MODE (op);
00879 op = XEXP (op, 0);
00880
00881 if (REG_P (op) || GET_CODE (op) == POST_INC
00882 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC)
00883 return 0;
00884 if (GET_CODE (op) != PLUS)
00885 abort ();
00886
00887 offset = INTVAL (XEXP (op, 1));
00888
00889
00890 if (GET_MODE_SIZE (mode) == 1)
00891 return 1;
00892
00893 if (GET_MODE_SIZE (mode) == 4)
00894 {
00895
00896
00897 if (XEXP (op, 0) == frame_pointer_rtx)
00898 return offset < -128 || offset > 60;
00899 return offset < 0 || offset > 60;
00900 }
00901
00902
00903 return offset < 0 || offset > 30;
00904 }
00905
00906
00907
00908
00909 static int
00910 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED)
00911 {
00912 return 1;
00913 }
00914
00915
00916
00917 void
00918 print_address_operand (FILE *file, rtx x)
00919 {
00920 if (GET_CODE (x) == MEM)
00921 abort ();
00922
00923 switch (GET_CODE (x))
00924 {
00925 case PLUS:
00926 output_address (XEXP (x, 0));
00927 fprintf (file, "+");
00928 output_address (XEXP (x, 1));
00929 break;
00930
00931 case PRE_DEC:
00932 fprintf (file, "--");
00933 output_address (XEXP (x, 0));
00934 break;
00935 case POST_INC:
00936 output_address (XEXP (x, 0));
00937 fprintf (file, "++");
00938 break;
00939 case POST_DEC:
00940 output_address (XEXP (x, 0));
00941 fprintf (file, "--");
00942 break;
00943
00944 default:
00945 print_operand (file, x, 0);
00946 }
00947 }
00948
00949
00950
00951
00952
00953
00954 void
00955 print_operand (FILE *file, rtx x, char code)
00956 {
00957 enum machine_mode mode = GET_MODE (x);
00958
00959 switch (code)
00960 {
00961 case 'j':
00962 switch (GET_CODE (x))
00963 {
00964 case EQ:
00965 fprintf (file, "e");
00966 break;
00967 case NE:
00968 fprintf (file, "ne");
00969 break;
00970 case GT:
00971 fprintf (file, "g");
00972 break;
00973 case LT:
00974 fprintf (file, "l");
00975 break;
00976 case GE:
00977 fprintf (file, "ge");
00978 break;
00979 case LE:
00980 fprintf (file, "le");
00981 break;
00982 case GTU:
00983 fprintf (file, "g");
00984 break;
00985 case LTU:
00986 fprintf (file, "l");
00987 break;
00988 case GEU:
00989 fprintf (file, "ge");
00990 break;
00991 case LEU:
00992 fprintf (file, "le");
00993 break;
00994 default:
00995 output_operand_lossage ("invalid %%j value");
00996 }
00997 break;
00998
00999 case 'J':
01000 switch (GET_CODE(x))
01001 {
01002 case EQ:
01003 fprintf (file, "ne");
01004 break;
01005 case NE:
01006 fprintf (file, "e");
01007 break;
01008 case GT:
01009 fprintf (file, "le");
01010 break;
01011 case LT:
01012 fprintf (file, "ge");
01013 break;
01014 case GE:
01015 fprintf (file, "l");
01016 break;
01017 case LE:
01018 fprintf (file, "g");
01019 break;
01020 case GTU:
01021 fprintf (file, "le");
01022 break;
01023 case LTU:
01024 fprintf (file, "ge");
01025 break;
01026 case GEU:
01027 fprintf (file, "l");
01028 break;
01029 case LEU:
01030 fprintf (file, "g");
01031 break;
01032 default:
01033 output_operand_lossage ("invalid %%J value");
01034 }
01035 break;
01036
01037 default:
01038 switch (GET_CODE (x))
01039 {
01040 case REG:
01041 if (code == 'h')
01042 {
01043 gcc_assert (REGNO (x) < 32);
01044 fprintf (file, "%s", short_reg_names[REGNO (x)]);
01045
01046 break;
01047 }
01048 else if (code == 'd')
01049 {
01050 gcc_assert (REGNO (x) < 32);
01051 fprintf (file, "%s", high_reg_names[REGNO (x)]);
01052 break;
01053 }
01054 else if (code == 'w')
01055 {
01056 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
01057 fprintf (file, "%s.w", reg_names[REGNO (x)]);
01058 }
01059 else if (code == 'x')
01060 {
01061 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
01062 fprintf (file, "%s.x", reg_names[REGNO (x)]);
01063 }
01064 else if (code == 'D')
01065 {
01066 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
01067 }
01068 else if (code == 'H')
01069 {
01070 gcc_assert (mode == DImode || mode == DFmode);
01071 gcc_assert (REG_P (x));
01072 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
01073 }
01074 else if (code == 'T')
01075 {
01076 if (REGNO (x) > 7)
01077 abort ();
01078 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
01079 }
01080 else
01081 fprintf (file, "%s", reg_names[REGNO (x)]);
01082 break;
01083
01084 case MEM:
01085 fputc ('[', file);
01086 x = XEXP (x,0);
01087 print_address_operand (file, x);
01088 fputc (']', file);
01089 break;
01090
01091 case CONST_INT:
01092
01093
01094 if (code == 'd')
01095 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
01096 else if (code == 'h')
01097 x = GEN_INT (INTVAL (x) & 0xffff);
01098 else if (code == 'X')
01099 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
01100 else if (code == 'Y')
01101 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
01102 else if (code == 'Z')
01103
01104 x = GEN_INT (-8 - INTVAL (x));
01105
01106
01107
01108 case SYMBOL_REF:
01109 output_addr_const (file, x);
01110 if (code == 'G' && flag_pic)
01111 fprintf (file, "@GOT");
01112 break;
01113
01114 case CONST_DOUBLE:
01115 output_operand_lossage ("invalid const_double operand");
01116 break;
01117
01118 case UNSPEC:
01119 if (XINT (x, 1) == UNSPEC_MOVE_PIC)
01120 {
01121 output_addr_const (file, XVECEXP (x, 0, 0));
01122 fprintf (file, "@GOT");
01123 }
01124 else if (XINT (x, 1) == UNSPEC_LIBRARY_OFFSET)
01125 fprintf (file, "_current_shared_library_p5_offset_");
01126 else
01127 abort ();
01128 break;
01129
01130 default:
01131 output_addr_const (file, x);
01132 }
01133 }
01134 }
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145 void
01146 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
01147 rtx libname ATTRIBUTE_UNUSED)
01148 {
01149 static CUMULATIVE_ARGS zero_cum;
01150
01151 *cum = zero_cum;
01152
01153
01154
01155 cum->nregs = max_arg_registers;
01156 cum->arg_regs = arg_regs;
01157
01158 cum->call_cookie = CALL_NORMAL;
01159
01160 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
01161 cum->call_cookie |= CALL_SHORT;
01162 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
01163 cum->call_cookie |= CALL_LONG;
01164
01165 return;
01166 }
01167
01168
01169
01170
01171
01172 void
01173 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
01174 int named ATTRIBUTE_UNUSED)
01175 {
01176 int count, bytes, words;
01177
01178 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
01179 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
01180
01181 cum->words += words;
01182 cum->nregs -= words;
01183
01184 if (cum->nregs <= 0)
01185 {
01186 cum->nregs = 0;
01187 cum->arg_regs = NULL;
01188 }
01189 else
01190 {
01191 for (count = 1; count <= words; count++)
01192 cum->arg_regs++;
01193 }
01194
01195 return;
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211 struct rtx_def *
01212 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
01213 int named ATTRIBUTE_UNUSED)
01214 {
01215 int bytes
01216 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
01217
01218 if (mode == VOIDmode)
01219
01220 return GEN_INT (cum->call_cookie);
01221
01222 if (bytes == -1)
01223 return NULL_RTX;
01224
01225 if (cum->nregs)
01226 return gen_rtx_REG (mode, *(cum->arg_regs));
01227
01228 return NULL_RTX;
01229 }
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240 static int
01241 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
01242 tree type ATTRIBUTE_UNUSED,
01243 bool named ATTRIBUTE_UNUSED)
01244 {
01245 int bytes
01246 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
01247 int bytes_left = cum->nregs * UNITS_PER_WORD;
01248
01249 if (bytes == -1)
01250 return 0;
01251
01252 if (bytes_left == 0)
01253 return 0;
01254 if (bytes > bytes_left)
01255 return bytes_left;
01256 return 0;
01257 }
01258
01259
01260
01261 static bool
01262 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
01263 enum machine_mode mode ATTRIBUTE_UNUSED,
01264 tree type, bool named ATTRIBUTE_UNUSED)
01265 {
01266 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
01267 }
01268
01269
01270
01271
01272
01273 int
01274 bfin_return_in_memory (tree type)
01275 {
01276 int size = int_size_in_bytes (type);
01277 return size > 2 * UNITS_PER_WORD || size == -1;
01278 }
01279
01280
01281
01282 static rtx
01283 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
01284 int incoming ATTRIBUTE_UNUSED)
01285 {
01286 return gen_rtx_REG (Pmode, REG_P0);
01287 }
01288
01289
01290
01291 bool
01292 function_arg_regno_p (int n)
01293 {
01294 int i;
01295 for (i = 0; arg_regs[i] != -1; i++)
01296 if (n == arg_regs[i])
01297 return true;
01298 return false;
01299 }
01300
01301
01302
01303 int
01304 symbolic_reference_mentioned_p (rtx op)
01305 {
01306 register const char *fmt;
01307 register int i;
01308
01309 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
01310 return 1;
01311
01312 fmt = GET_RTX_FORMAT (GET_CODE (op));
01313 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
01314 {
01315 if (fmt[i] == 'E')
01316 {
01317 register int j;
01318
01319 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
01320 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
01321 return 1;
01322 }
01323
01324 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
01325 return 1;
01326 }
01327
01328 return 0;
01329 }
01330
01331
01332
01333
01334
01335 static bool
01336 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
01337 tree exp ATTRIBUTE_UNUSED)
01338 {
01339 return true;
01340 }
01341
01342
01343
01344
01345
01346 void
01347 initialize_trampoline (tramp, fnaddr, cxt)
01348 rtx tramp, fnaddr, cxt;
01349 {
01350 rtx t1 = copy_to_reg (fnaddr);
01351 rtx t2 = copy_to_reg (cxt);
01352 rtx addr;
01353
01354 addr = memory_address (Pmode, plus_constant (tramp, 2));
01355 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
01356 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
01357 addr = memory_address (Pmode, plus_constant (tramp, 6));
01358 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
01359
01360 addr = memory_address (Pmode, plus_constant (tramp, 10));
01361 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
01362 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
01363 addr = memory_address (Pmode, plus_constant (tramp, 14));
01364 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
01365 }
01366
01367
01368
01369
01370
01371
01372 rtx
01373 legitimize_pic_address (rtx orig, rtx reg)
01374 {
01375 rtx addr = orig;
01376 rtx new = orig;
01377
01378 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
01379 {
01380 if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
01381 reg = new = orig;
01382 else
01383 {
01384 if (reg == 0)
01385 {
01386 if (no_new_pseudos)
01387 abort ();
01388 reg = gen_reg_rtx (Pmode);
01389 }
01390
01391 if (flag_pic == 2)
01392 {
01393 emit_insn (gen_movsi_high_pic (reg, addr));
01394 emit_insn (gen_movsi_low_pic (reg, reg, addr));
01395 emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
01396 new = gen_rtx_MEM (Pmode, reg);
01397 }
01398 else
01399 {
01400 rtx tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
01401 UNSPEC_MOVE_PIC);
01402 new = gen_rtx_MEM (Pmode,
01403 gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
01404 tmp));
01405 }
01406 emit_move_insn (reg, new);
01407 }
01408 current_function_uses_pic_offset_table = 1;
01409 return reg;
01410 }
01411
01412 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
01413 {
01414 rtx base;
01415
01416 if (GET_CODE (addr) == CONST)
01417 {
01418 addr = XEXP (addr, 0);
01419 if (GET_CODE (addr) != PLUS)
01420 abort ();
01421 }
01422
01423 if (XEXP (addr, 0) == pic_offset_table_rtx)
01424 return orig;
01425
01426 if (reg == 0)
01427 {
01428 if (no_new_pseudos)
01429 abort ();
01430 reg = gen_reg_rtx (Pmode);
01431 }
01432
01433 base = legitimize_pic_address (XEXP (addr, 0), reg);
01434 addr = legitimize_pic_address (XEXP (addr, 1),
01435 base == reg ? NULL_RTX : reg);
01436
01437 if (GET_CODE (addr) == CONST_INT)
01438 {
01439 if (! reload_in_progress && ! reload_completed)
01440 addr = force_reg (Pmode, addr);
01441 else
01442
01443 abort ();
01444 }
01445
01446 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
01447 {
01448 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
01449 addr = XEXP (addr, 1);
01450 }
01451
01452 return gen_rtx_PLUS (Pmode, base, addr);
01453 }
01454
01455 return new;
01456 }
01457
01458
01459
01460 void
01461 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
01462 {
01463 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
01464
01465 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
01466 operands[1] = force_reg (SImode, operands[1]);
01467 else
01468 operands[1] = legitimize_pic_address (operands[1], temp);
01469 }
01470
01471
01472
01473 void
01474 expand_move (rtx *operands, enum machine_mode mode)
01475 {
01476 if (flag_pic && SYMBOLIC_CONST (operands[1]))
01477 emit_pic_move (operands, mode);
01478
01479
01480
01481 else if ((reload_in_progress | reload_completed) == 0
01482 && GET_CODE (operands[0]) == MEM
01483 && GET_CODE (operands[1]) != REG)
01484 operands[1] = force_reg (mode, operands[1]);
01485 }
01486
01487
01488
01489
01490
01491
01492
01493 void
01494 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
01495 {
01496 while (num--)
01497 {
01498 rtx op = operands[num];
01499
01500
01501
01502 if (GET_CODE (op) == MEM)
01503 {
01504 lo_half[num] = adjust_address (op, SImode, 0);
01505 hi_half[num] = adjust_address (op, SImode, 4);
01506 }
01507 else
01508 {
01509 lo_half[num] = simplify_gen_subreg (SImode, op,
01510 GET_MODE (op) == VOIDmode
01511 ? DImode : GET_MODE (op), 0);
01512 hi_half[num] = simplify_gen_subreg (SImode, op,
01513 GET_MODE (op) == VOIDmode
01514 ? DImode : GET_MODE (op), 4);
01515 }
01516 }
01517 }
01518
01519 bool
01520 bfin_longcall_p (rtx op, int call_cookie)
01521 {
01522 gcc_assert (GET_CODE (op) == SYMBOL_REF);
01523 if (call_cookie & CALL_SHORT)
01524 return 0;
01525 if (call_cookie & CALL_LONG)
01526 return 1;
01527 if (TARGET_LONG_CALLS)
01528 return 1;
01529 return 0;
01530 }
01531
01532
01533
01534
01535
01536 void
01537 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
01538 {
01539 rtx use = NULL, call;
01540 rtx callee = XEXP (fnaddr, 0);
01541 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (sibcall ? 3 : 2));
01542
01543
01544 if (cookie == NULL_RTX)
01545 cookie = const0_rtx;
01546
01547
01548 if (flag_pic
01549 && GET_CODE (callee) == SYMBOL_REF
01550 && !SYMBOL_REF_LOCAL_P (callee))
01551 use_reg (&use, pic_offset_table_rtx);
01552
01553 if ((!register_no_elim_operand (callee, Pmode)
01554 && GET_CODE (callee) != SYMBOL_REF)
01555 || (GET_CODE (callee) == SYMBOL_REF
01556 && (flag_pic
01557 || bfin_longcall_p (callee, INTVAL (cookie)))))
01558 {
01559 callee = copy_to_mode_reg (Pmode, callee);
01560 fnaddr = gen_rtx_MEM (Pmode, callee);
01561 }
01562 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
01563
01564 if (retval)
01565 call = gen_rtx_SET (VOIDmode, retval, call);
01566
01567 XVECEXP (pat, 0, 0) = call;
01568 XVECEXP (pat, 0, 1) = gen_rtx_USE (VOIDmode, cookie);
01569 if (sibcall)
01570 XVECEXP (pat, 0, 2) = gen_rtx_RETURN (VOIDmode);
01571 call = emit_call_insn (pat);
01572 if (use)
01573 CALL_INSN_FUNCTION_USAGE (call) = use;
01574 }
01575
01576
01577
01578 int
01579 hard_regno_mode_ok (int regno, enum machine_mode mode)
01580 {
01581
01582 enum reg_class class = REGNO_REG_CLASS (regno);
01583
01584 if (mode == CCmode)
01585 return 0;
01586
01587 if (mode == V2HImode)
01588 return D_REGNO_P (regno);
01589 if (class == CCREGS)
01590 return mode == BImode;
01591 if (mode == PDImode)
01592 return regno == REG_A0 || regno == REG_A1;
01593 if (mode == SImode
01594 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
01595 return 1;
01596
01597 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
01598 }
01599
01600
01601
01602 static bool
01603 bfin_vector_mode_supported_p (enum machine_mode mode)
01604 {
01605 return mode == V2HImode;
01606 }
01607
01608
01609
01610
01611 int
01612 bfin_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
01613 enum reg_class class1, enum reg_class class2)
01614 {
01615
01616 if (optimize_size)
01617 return 2;
01618
01619
01620
01621
01622 if (class1 == DREGS && class2 != DREGS)
01623 return 2 * 2;
01624
01625 return 2;
01626 }
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636 int
01637 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
01638 enum reg_class class,
01639 int in ATTRIBUTE_UNUSED)
01640 {
01641
01642
01643
01644 if (! reg_class_subset_p (class, DPREGS))
01645 return 10;
01646
01647 return 8;
01648 }
01649
01650
01651
01652
01653
01654 enum reg_class
01655 secondary_input_reload_class (enum reg_class class, enum machine_mode mode,
01656 rtx x)
01657 {
01658
01659
01660 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
01661 enum reg_class x_class = NO_REGS;
01662 enum rtx_code code = GET_CODE (x);
01663
01664 if (code == SUBREG)
01665 x = SUBREG_REG (x), code = GET_CODE (x);
01666 if (REG_P (x))
01667 {
01668 int regno = REGNO (x);
01669 if (regno >= FIRST_PSEUDO_REGISTER)
01670 regno = reg_renumber[regno];
01671
01672 if (regno == -1)
01673 code = MEM;
01674 else
01675 x_class = REGNO_REG_CLASS (regno);
01676 }
01677
01678
01679
01680
01681 if (fp_plus_const_operand (x, mode))
01682 {
01683 rtx op2 = XEXP (x, 1);
01684 int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2));
01685
01686 if (class == PREGS || class == PREGS_CLOBBERED)
01687 return NO_REGS;
01688
01689
01690 if (class == DREGS || class == DPREGS)
01691 return large_constant_p ? PREGS : NO_REGS;
01692
01693
01694 return PREGS;
01695 }
01696
01697
01698
01699
01700 if (x_class == AREGS)
01701 return class == DREGS || class == AREGS ? NO_REGS : DREGS;
01702
01703 if (class == AREGS)
01704 {
01705 if (x != const0_rtx && x_class != DREGS)
01706 return DREGS;
01707 else
01708 return NO_REGS;
01709 }
01710
01711
01712 if (class == CCREGS && x_class != DREGS)
01713 return DREGS;
01714 if (x_class == CCREGS && class != DREGS)
01715 return DREGS;
01716
01717
01718 if (code == MEM)
01719 if (! reg_class_subset_p (class, default_class))
01720 return default_class;
01721 return NO_REGS;
01722 }
01723
01724
01725
01726 enum reg_class
01727 secondary_output_reload_class (enum reg_class class, enum machine_mode mode,
01728 rtx x)
01729 {
01730 return secondary_input_reload_class (class, mode, x);
01731 }
01732
01733
01734
01735 void
01736 override_options (void)
01737 {
01738 if (TARGET_OMIT_LEAF_FRAME_POINTER)
01739 flag_omit_frame_pointer = 1;
01740
01741
01742 if (bfin_library_id_string)
01743 {
01744 int id;
01745
01746 if (! TARGET_ID_SHARED_LIBRARY)
01747 error ("-mshared-library-id= specified without -mid-shared-library");
01748 id = atoi (bfin_library_id_string);
01749 if (id < 0 || id > MAX_LIBRARY_ID)
01750 error ("-mshared-library-id=%d is not between 0 and %d", id, MAX_LIBRARY_ID);
01751
01752
01753 asprintf ((char **)&bfin_library_id_string, "%d", (id * -4) - 4);
01754 }
01755
01756 if (TARGET_ID_SHARED_LIBRARY)
01757
01758 flag_pic = 1;
01759
01760 flag_schedule_insns = 0;
01761 }
01762
01763
01764
01765
01766
01767
01768 static int
01769 branch_dest (rtx branch)
01770 {
01771 rtx dest;
01772 int dest_uid;
01773 rtx pat = PATTERN (branch);
01774 if (GET_CODE (pat) == PARALLEL)
01775 pat = XVECEXP (pat, 0, 0);
01776 dest = SET_SRC (pat);
01777 if (GET_CODE (dest) == IF_THEN_ELSE)
01778 dest = XEXP (dest, 1);
01779 dest = XEXP (dest, 0);
01780 dest_uid = INSN_UID (dest);
01781 return INSN_ADDRESSES (dest_uid);
01782 }
01783
01784
01785
01786
01787 static int
01788 cbranch_predicted_taken_p (rtx insn)
01789 {
01790 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
01791
01792 if (x)
01793 {
01794 int pred_val = INTVAL (XEXP (x, 0));
01795
01796 return pred_val >= REG_BR_PROB_BASE / 2;
01797 }
01798
01799 return 0;
01800 }
01801
01802
01803
01804 static const char *ccbranch_templates[][3] = {
01805 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
01806 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
01807 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
01808 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
01809 };
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822 void
01823 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
01824 {
01825 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
01826
01827
01828
01829
01830 int len = (offset >= -1024 && offset <= 1022 ? 0
01831 : offset >= -4094 && offset <= 4096 ? 1
01832 : 2);
01833 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
01834 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
01835 output_asm_insn (ccbranch_templates[idx][len], operands);
01836 if (n_nops > 0 && bp)
01837 abort ();
01838 if (len == 0)
01839 while (n_nops-- > 0)
01840 output_asm_insn ("nop;", NULL);
01841 }
01842
01843
01844
01845
01846 rtx
01847 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
01848 {
01849 enum rtx_code code1, code2;
01850 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
01851 rtx tem = bfin_cc_rtx;
01852 enum rtx_code code = GET_CODE (cmp);
01853
01854
01855
01856 if (GET_MODE (op0) == BImode)
01857 {
01858 if ((code == NE || code == EQ) && op1 == const0_rtx)
01859 tem = op0, code2 = code;
01860 else
01861 abort ();
01862 }
01863 else
01864 {
01865 switch (code) {
01866
01867 case EQ:
01868 case LT:
01869 case LE:
01870 case LEU:
01871 case LTU:
01872 code1 = code;
01873 code2 = NE;
01874 break;
01875 default:
01876 code1 = reverse_condition (code);
01877 code2 = EQ;
01878 break;
01879 }
01880 emit_insn (gen_rtx_SET (BImode, tem,
01881 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
01882 }
01883
01884 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
01885 }
01886
01887
01888
01889
01890 int
01891 log2constp (unsigned HOST_WIDE_INT c)
01892 {
01893 c &= 0xFFFFFFFF;
01894 return c != 0 && (c & (c-1)) == 0;
01895 }
01896
01897
01898
01899
01900
01901
01902 static int
01903 shiftr_zero (HOST_WIDE_INT *v)
01904 {
01905 unsigned HOST_WIDE_INT tmp = *v;
01906 unsigned HOST_WIDE_INT sgn;
01907 int n = 0;
01908
01909 if (tmp == 0)
01910 return 0;
01911
01912 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
01913 while ((tmp & 0x1) == 0 && n <= 32)
01914 {
01915 tmp = (tmp >> 1) | sgn;
01916 n++;
01917 }
01918 *v = tmp;
01919 return n;
01920 }
01921
01922
01923
01924
01925
01926
01927 int
01928 split_load_immediate (rtx operands[])
01929 {
01930 HOST_WIDE_INT val = INTVAL (operands[1]);
01931 HOST_WIDE_INT tmp;
01932 HOST_WIDE_INT shifted = val;
01933 HOST_WIDE_INT shifted_compl = ~val;
01934 int num_zero = shiftr_zero (&shifted);
01935 int num_compl_zero = shiftr_zero (&shifted_compl);
01936 unsigned int regno = REGNO (operands[0]);
01937 enum reg_class class1 = REGNO_REG_CLASS (regno);
01938
01939
01940
01941 if (num_zero
01942 && shifted >= -32768 && shifted < 65536
01943 && (D_REGNO_P (regno)
01944 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
01945 {
01946 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
01947 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
01948 return 1;
01949 }
01950
01951 tmp = val & 0xFFFF;
01952 tmp |= -(tmp & 0x8000);
01953
01954
01955 if (D_REGNO_P (regno))
01956 {
01957 if (log2constp (val & 0xFFFF0000))
01958 {
01959 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
01960 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
01961 return 1;
01962 }
01963 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
01964 {
01965 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
01966 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
01967 }
01968 }
01969
01970 if (D_REGNO_P (regno))
01971 {
01972 if (CONST_7BIT_IMM_P (tmp))
01973 {
01974 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
01975 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
01976 return 1;
01977 }
01978
01979 if ((val & 0xFFFF0000) == 0)
01980 {
01981 emit_insn (gen_movsi (operands[0], const0_rtx));
01982 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
01983 return 1;
01984 }
01985
01986 if ((val & 0xFFFF0000) == 0xFFFF0000)
01987 {
01988 emit_insn (gen_movsi (operands[0], constm1_rtx));
01989 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
01990 return 1;
01991 }
01992 }
01993
01994
01995 if (regno > REG_R7)
01996 return 0;
01997
01998 if (optimize_size
01999 && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl))
02000 {
02001
02002
02003 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
02004 emit_insn (gen_ashlsi3 (operands[0], operands[0],
02005 GEN_INT (num_compl_zero)));
02006 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
02007 return 1;
02008 }
02009 return 0;
02010 }
02011
02012
02013
02014
02015 static bool
02016 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
02017 {
02018 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
02019 int sz = GET_MODE_SIZE (mode);
02020 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
02021
02022
02023 unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff;
02024 return (v & ~(mask << shift)) == 0;
02025 }
02026
02027 static bool
02028 bfin_valid_reg_p (unsigned int regno, int strict)
02029 {
02030 return ((strict && REGNO_OK_FOR_BASE_STRICT_P (regno))
02031 || (!strict && REGNO_OK_FOR_BASE_NONSTRICT_P (regno)));
02032 }
02033
02034 bool
02035 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
02036 {
02037 switch (GET_CODE (x)) {
02038 case REG:
02039 if (bfin_valid_reg_p (REGNO (x), strict))
02040 return true;
02041 break;
02042 case PLUS:
02043 if (REG_P (XEXP (x, 0))
02044 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict)
02045 && (GET_CODE (XEXP (x, 1)) == UNSPEC
02046 || (GET_CODE (XEXP (x, 1)) == CONST_INT
02047 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
02048 return true;
02049 break;
02050 case POST_INC:
02051 case POST_DEC:
02052 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
02053 && REG_P (XEXP (x, 0))
02054 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
02055 return true;
02056 case PRE_DEC:
02057 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
02058 && XEXP (x, 0) == stack_pointer_rtx
02059 && REG_P (XEXP (x, 0))
02060 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
02061 return true;
02062 break;
02063 default:
02064 break;
02065 }
02066 return false;
02067 }
02068
02069 static bool
02070 bfin_rtx_costs (rtx x, int code, int outer_code, int *total)
02071 {
02072 int cost2 = COSTS_N_INSNS (1);
02073
02074 switch (code)
02075 {
02076 case CONST_INT:
02077 if (outer_code == SET || outer_code == PLUS)
02078 *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2;
02079 else if (outer_code == AND)
02080 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
02081 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
02082 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
02083 else if (outer_code == LEU || outer_code == LTU)
02084 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
02085 else if (outer_code == MULT)
02086 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
02087 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
02088 *total = 0;
02089 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
02090 || outer_code == LSHIFTRT)
02091 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
02092 else if (outer_code == IOR || outer_code == XOR)
02093 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
02094 else
02095 *total = cost2;
02096 return true;
02097
02098 case CONST:
02099 case LABEL_REF:
02100 case SYMBOL_REF:
02101 case CONST_DOUBLE:
02102 *total = COSTS_N_INSNS (2);
02103 return true;
02104
02105 case PLUS:
02106 if (GET_MODE (x) == Pmode)
02107 {
02108 if (GET_CODE (XEXP (x, 0)) == MULT
02109 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
02110 {
02111 HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
02112 if (val == 2 || val == 4)
02113 {
02114 *total = cost2;
02115 *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
02116 *total += rtx_cost (XEXP (x, 1), outer_code);
02117 return true;
02118 }
02119 }
02120 }
02121
02122
02123
02124 case MINUS:
02125 case ASHIFT:
02126 case ASHIFTRT:
02127 case LSHIFTRT:
02128 if (GET_MODE (x) == DImode)
02129 *total = 6 * cost2;
02130 return false;
02131
02132 case AND:
02133 case IOR:
02134 case XOR:
02135 if (GET_MODE (x) == DImode)
02136 *total = 2 * cost2;
02137 return false;
02138
02139 case MULT:
02140 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD)
02141 *total = COSTS_N_INSNS (3);
02142 return false;
02143
02144 default:
02145 return false;
02146 }
02147 }
02148
02149 static void
02150 bfin_internal_label (FILE *stream, const char *prefix, unsigned long num)
02151 {
02152 fprintf (stream, "%s%s$%ld:\n", LOCAL_LABEL_PREFIX, prefix, num);
02153 }
02154
02155
02156
02157 static int first_preg_to_save, first_dreg_to_save;
02158
02159 int
02160 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
02161 {
02162 int lastdreg = 8, lastpreg = 6;
02163 int i, group;
02164
02165 first_preg_to_save = lastpreg;
02166 first_dreg_to_save = lastdreg;
02167 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
02168 {
02169 rtx t = XVECEXP (op, 0, i);
02170 rtx src, dest;
02171 int regno;
02172
02173 if (GET_CODE (t) != SET)
02174 return 0;
02175
02176 src = SET_SRC (t);
02177 dest = SET_DEST (t);
02178 if (GET_CODE (dest) != MEM || ! REG_P (src))
02179 return 0;
02180 dest = XEXP (dest, 0);
02181 if (GET_CODE (dest) != PLUS
02182 || ! REG_P (XEXP (dest, 0))
02183 || REGNO (XEXP (dest, 0)) != REG_SP
02184 || GET_CODE (XEXP (dest, 1)) != CONST_INT
02185 || INTVAL (XEXP (dest, 1)) != -i * 4)
02186 return 0;
02187
02188 regno = REGNO (src);
02189 if (group == 0)
02190 {
02191 if (D_REGNO_P (regno))
02192 {
02193 group = 1;
02194 first_dreg_to_save = lastdreg = regno - REG_R0;
02195 }
02196 else if (regno >= REG_P0 && regno <= REG_P7)
02197 {
02198 group = 2;
02199 first_preg_to_save = lastpreg = regno - REG_P0;
02200 }
02201 else
02202 return 0;
02203
02204 continue;
02205 }
02206
02207 if (group == 1)
02208 {
02209 if (regno >= REG_P0 && regno <= REG_P7)
02210 {
02211 group = 2;
02212 first_preg_to_save = lastpreg = regno - REG_P0;
02213 }
02214 else if (regno != REG_R0 + lastdreg + 1)
02215 return 0;
02216 else
02217 lastdreg++;
02218 }
02219 else if (group == 2)
02220 {
02221 if (regno != REG_P0 + lastpreg + 1)
02222 return 0;
02223 lastpreg++;
02224 }
02225 }
02226 return 1;
02227 }
02228
02229 int
02230 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
02231 {
02232 int lastdreg = 8, lastpreg = 6;
02233 int i, group;
02234
02235 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
02236 {
02237 rtx t = XVECEXP (op, 0, i);
02238 rtx src, dest;
02239 int regno;
02240
02241 if (GET_CODE (t) != SET)
02242 return 0;
02243
02244 src = SET_SRC (t);
02245 dest = SET_DEST (t);
02246 if (GET_CODE (src) != MEM || ! REG_P (dest))
02247 return 0;
02248 src = XEXP (src, 0);
02249
02250 if (i == 1)
02251 {
02252 if (! REG_P (src) || REGNO (src) != REG_SP)
02253 return 0;
02254 }
02255 else if (GET_CODE (src) != PLUS
02256 || ! REG_P (XEXP (src, 0))
02257 || REGNO (XEXP (src, 0)) != REG_SP
02258 || GET_CODE (XEXP (src, 1)) != CONST_INT
02259 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
02260 return 0;
02261
02262 regno = REGNO (dest);
02263 if (group == 0)
02264 {
02265 if (regno == REG_R7)
02266 {
02267 group = 1;
02268 lastdreg = 7;
02269 }
02270 else if (regno != REG_P0 + lastpreg - 1)
02271 return 0;
02272 else
02273 lastpreg--;
02274 }
02275 else if (group == 1)
02276 {
02277 if (regno != REG_R0 + lastdreg - 1)
02278 return 0;
02279 else
02280 lastdreg--;
02281 }
02282 }
02283 first_dreg_to_save = lastdreg;
02284 first_preg_to_save = lastpreg;
02285 return 1;
02286 }
02287
02288
02289
02290
02291 void
02292 output_push_multiple (rtx insn, rtx *operands)
02293 {
02294 char buf[80];
02295
02296 if (! push_multiple_operation (PATTERN (insn), VOIDmode))
02297 abort ();
02298 if (first_dreg_to_save == 8)
02299 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
02300 else if (first_preg_to_save == 6)
02301 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
02302 else
02303 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n", first_dreg_to_save, first_preg_to_save);
02304
02305 output_asm_insn (buf, operands);
02306 }
02307
02308
02309
02310
02311 void
02312 output_pop_multiple (rtx insn, rtx *operands)
02313 {
02314 char buf[80];
02315
02316 if (! pop_multiple_operation (PATTERN (insn), VOIDmode))
02317 abort ();
02318
02319 if (first_dreg_to_save == 8)
02320 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
02321 else if (first_preg_to_save == 6)
02322 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
02323 else
02324 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n", first_dreg_to_save, first_preg_to_save);
02325
02326 output_asm_insn (buf, operands);
02327 }
02328
02329
02330
02331 static void
02332 single_move_for_strmov (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
02333 {
02334 rtx scratch = gen_reg_rtx (mode);
02335 rtx srcmem, dstmem;
02336
02337 srcmem = adjust_address_nv (src, mode, offset);
02338 dstmem = adjust_address_nv (dst, mode, offset);
02339 emit_move_insn (scratch, srcmem);
02340 emit_move_insn (dstmem, scratch);
02341 }
02342
02343
02344
02345
02346
02347 bool
02348 bfin_expand_strmov (rtx dst, rtx src, rtx count_exp, rtx align_exp)
02349 {
02350 rtx srcreg, destreg, countreg;
02351 HOST_WIDE_INT align = 0;
02352 unsigned HOST_WIDE_INT count = 0;
02353
02354 if (GET_CODE (align_exp) == CONST_INT)
02355 align = INTVAL (align_exp);
02356 if (GET_CODE (count_exp) == CONST_INT)
02357 {
02358 count = INTVAL (count_exp);
02359 #if 0
02360 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
02361 return false;
02362 #endif
02363 }
02364
02365
02366 if (optimize_size)
02367 {
02368 if (count == 2 && align < 2)
02369 return false;
02370 if (count == 4 && align < 4)
02371 return false;
02372 if (count != 1 && count != 2 && count != 4)
02373 return false;
02374 }
02375 if (align < 2 && count != 1)
02376 return false;
02377
02378 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
02379 if (destreg != XEXP (dst, 0))
02380 dst = replace_equiv_address_nv (dst, destreg);
02381 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
02382 if (srcreg != XEXP (src, 0))
02383 src = replace_equiv_address_nv (src, srcreg);
02384
02385 if (count != 0 && align >= 2)
02386 {
02387 unsigned HOST_WIDE_INT offset = 0;
02388
02389 if (align >= 4)
02390 {
02391 if ((count & ~3) == 4)
02392 {
02393 single_move_for_strmov (dst, src, SImode, offset);
02394 offset = 4;
02395 }
02396 else if (count & ~3)
02397 {
02398 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
02399 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
02400
02401 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
02402 }
02403 }
02404 else
02405 {
02406 if ((count & ~1) == 2)
02407 {
02408 single_move_for_strmov (dst, src, HImode, offset);
02409 offset = 2;
02410 }
02411 else if (count & ~1)
02412 {
02413 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
02414 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
02415
02416 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
02417 }
02418 }
02419 if (count & 2)
02420 {
02421 single_move_for_strmov (dst, src, HImode, offset);
02422 offset += 2;
02423 }
02424 if (count & 1)
02425 {
02426 single_move_for_strmov (dst, src, QImode, offset);
02427 }
02428 return true;
02429 }
02430 return false;
02431 }
02432
02433
02434 static int
02435 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
02436 {
02437 enum attr_type insn_type, dep_insn_type;
02438 int dep_insn_code_number;
02439
02440
02441 if (REG_NOTE_KIND (link) != 0)
02442 return 0;
02443
02444 dep_insn_code_number = recog_memoized (dep_insn);
02445
02446
02447 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
02448 return cost;
02449
02450 insn_type = get_attr_type (insn);
02451 dep_insn_type = get_attr_type (dep_insn);
02452
02453 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
02454 {
02455 rtx pat = PATTERN (dep_insn);
02456 rtx dest = SET_DEST (pat);
02457 rtx src = SET_SRC (pat);
02458 if (! ADDRESS_REGNO_P (REGNO (dest)) || ! D_REGNO_P (REGNO (src)))
02459 return cost;
02460 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
02461 }
02462
02463 return cost;
02464 }
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486 static void
02487 bfin_reorg (void)
02488 {
02489 rtx insn, last_condjump = NULL_RTX;
02490 int cycles_since_jump = INT_MAX;
02491
02492 if (! TARGET_SPECLD_ANOMALY || ! TARGET_CSYNC_ANOMALY)
02493 return;
02494
02495
02496
02497 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
02498 {
02499 rtx pat;
02500
02501 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
02502 continue;
02503
02504 pat = PATTERN (insn);
02505 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
02506 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
02507 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
02508 continue;
02509
02510 if (JUMP_P (insn))
02511 {
02512 if (any_condjump_p (insn)
02513 && ! cbranch_predicted_taken_p (insn))
02514 {
02515 last_condjump = insn;
02516 cycles_since_jump = 0;
02517 }
02518 else
02519 cycles_since_jump = INT_MAX;
02520 }
02521 else if (INSN_P (insn))
02522 {
02523 enum attr_type type = get_attr_type (insn);
02524 int delay_needed = 0;
02525 if (cycles_since_jump < INT_MAX)
02526 cycles_since_jump++;
02527
02528 if (type == TYPE_MCLD && TARGET_SPECLD_ANOMALY)
02529 {
02530 rtx pat = single_set (insn);
02531 if (may_trap_p (SET_SRC (pat)))
02532 delay_needed = 3;
02533 }
02534 else if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
02535 delay_needed = 4;
02536
02537 if (delay_needed > cycles_since_jump)
02538 {
02539 rtx pat;
02540 int num_clobbers;
02541 rtx *op = recog_data.operand;
02542
02543 delay_needed -= cycles_since_jump;
02544
02545 extract_insn (last_condjump);
02546 if (optimize_size)
02547 {
02548 pat = gen_cbranch_predicted_taken (op[0], op[1], op[2],
02549 op[3]);
02550 cycles_since_jump = INT_MAX;
02551 }
02552 else
02553
02554
02555
02556 pat = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
02557 GEN_INT (delay_needed));
02558 PATTERN (last_condjump) = pat;
02559 INSN_CODE (last_condjump) = recog (pat, insn, &num_clobbers);
02560 }
02561 }
02562 }
02563
02564
02565 if (! TARGET_CSYNC_ANOMALY)
02566 return;
02567
02568 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
02569 {
02570 if (JUMP_P (insn)
02571 && any_condjump_p (insn)
02572 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
02573 || cbranch_predicted_taken_p (insn)))
02574 {
02575 rtx target = JUMP_LABEL (insn);
02576 rtx label = target;
02577 cycles_since_jump = 0;
02578 for (; target && cycles_since_jump < 3; target = NEXT_INSN (target))
02579 {
02580 rtx pat;
02581
02582 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
02583 continue;
02584
02585 pat = PATTERN (target);
02586 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
02587 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
02588 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
02589 continue;
02590
02591 if (INSN_P (target))
02592 {
02593 enum attr_type type = get_attr_type (target);
02594 int delay_needed = 0;
02595 if (cycles_since_jump < INT_MAX)
02596 cycles_since_jump++;
02597
02598 if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
02599 delay_needed = 2;
02600
02601 if (delay_needed > cycles_since_jump)
02602 {
02603 rtx prev = prev_real_insn (label);
02604 delay_needed -= cycles_since_jump;
02605 if (dump_file)
02606 fprintf (dump_file, "Adding %d nops after %d\n",
02607 delay_needed, INSN_UID (label));
02608 if (JUMP_P (prev)
02609 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
02610 {
02611 rtx x;
02612 HOST_WIDE_INT v;
02613
02614 if (dump_file)
02615 fprintf (dump_file,
02616 "Reducing nops on insn %d.\n",
02617 INSN_UID (prev));
02618 x = PATTERN (prev);
02619 x = XVECEXP (x, 0, 1);
02620 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
02621 XVECEXP (x, 0, 0) = GEN_INT (v);
02622 }
02623 while (delay_needed-- > 0)
02624 emit_insn_after (gen_nop (), label);
02625 break;
02626 }
02627 }
02628 }
02629 }
02630 }
02631 }
02632
02633
02634
02635
02636 static tree
02637 handle_int_attribute (tree *node, tree name,
02638 tree args ATTRIBUTE_UNUSED,
02639 int flags ATTRIBUTE_UNUSED,
02640 bool *no_add_attrs)
02641 {
02642 tree x = *node;
02643 if (TREE_CODE (x) == FUNCTION_DECL)
02644 x = TREE_TYPE (x);
02645
02646 if (TREE_CODE (x) != FUNCTION_TYPE)
02647 {
02648 warning ("%qs attribute only applies to functions",
02649 IDENTIFIER_POINTER (name));
02650 *no_add_attrs = true;
02651 }
02652 else if (funkind (x) != SUBROUTINE)
02653 error ("multiple function type attributes specified");
02654
02655 return NULL_TREE;
02656 }
02657
02658
02659
02660
02661
02662 static int
02663 bfin_comp_type_attributes (tree type1, tree type2)
02664 {
02665 e_funkind kind1, kind2;
02666
02667 if (TREE_CODE (type1) != FUNCTION_TYPE)
02668 return 1;
02669
02670 kind1 = funkind (type1);
02671 kind2 = funkind (type2);
02672
02673 if (kind1 != kind2)
02674 return 0;
02675
02676
02677 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
02678 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
02679 return 0;
02680
02681 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
02682 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
02683 return 0;
02684
02685 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
02686 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
02687 return 0;
02688
02689 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
02690 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
02691 return 0;
02692
02693 return 1;
02694 }
02695
02696
02697
02698
02699 static tree
02700 bfin_handle_longcall_attribute (tree *node, tree name,
02701 tree args ATTRIBUTE_UNUSED,
02702 int flags ATTRIBUTE_UNUSED,
02703 bool *no_add_attrs)
02704 {
02705 if (TREE_CODE (*node) != FUNCTION_TYPE
02706 && TREE_CODE (*node) != FIELD_DECL
02707 && TREE_CODE (*node) != TYPE_DECL)
02708 {
02709 warning ("`%s' attribute only applies to functions",
02710 IDENTIFIER_POINTER (name));
02711 *no_add_attrs = true;
02712 }
02713
02714 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
02715 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
02716 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
02717 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
02718 {
02719 warning ("can't apply both longcall and shortcall attributes to the same function");
02720 *no_add_attrs = true;
02721 }
02722
02723 return NULL_TREE;
02724 }
02725
02726
02727 const struct attribute_spec bfin_attribute_table[] =
02728 {
02729
02730 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
02731 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
02732 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
02733 { "nesting", 0, 0, false, true, true, NULL },
02734 { "kspisusp", 0, 0, false, true, true, NULL },
02735 { "saveall", 0, 0, false, true, true, NULL },
02736 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
02737 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
02738 { NULL, 0, 0, false, false, false, NULL }
02739 };
02740
02741
02742
02743
02744
02745
02746
02747 static void
02748 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
02749 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
02750 HOST_WIDE_INT vcall_offset, tree function)
02751 {
02752 rtx xops[3];
02753
02754 rtx this = gen_rtx_REG (Pmode, REG_R0);
02755
02756
02757 if (delta)
02758 {
02759 xops[1] = this;
02760 if (delta >= -64 && delta <= 63)
02761 {
02762 xops[0] = GEN_INT (delta);
02763 output_asm_insn ("%1 += %0;", xops);
02764 }
02765 else if (delta >= -128 && delta < -64)
02766 {
02767 xops[0] = GEN_INT (delta + 64);
02768 output_asm_insn ("%1 += -64; %1 += %0;", xops);
02769 }
02770 else if (delta > 63 && delta <= 126)
02771 {
02772 xops[0] = GEN_INT (delta - 63);
02773 output_asm_insn ("%1 += 63; %1 += %0;", xops);
02774 }
02775 else
02776 {
02777 xops[0] = GEN_INT (delta);
02778 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
02779 }
02780 }
02781
02782
02783 if (vcall_offset)
02784 {
02785 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
02786 rtx tmp = gen_rtx_REG (Pmode, REG_R2);
02787
02788 xops[1] = tmp;
02789 xops[2] = p2tmp;
02790 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
02791
02792
02793 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
02794 if (!memory_operand (xops[0], Pmode))
02795 {
02796 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
02797 xops[0] = GEN_INT (vcall_offset);
02798 xops[1] = tmp2;
02799 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
02800 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
02801 }
02802 xops[2] = this;
02803 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
02804 }
02805
02806 xops[0] = XEXP (DECL_RTL (function), 0);
02807 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
02808 output_asm_insn ("jump.l\t%P0", xops);
02809 }
02810
02811
02812 enum bfin_builtins
02813 {
02814 BFIN_BUILTIN_CSYNC,
02815 BFIN_BUILTIN_SSYNC,
02816 BFIN_BUILTIN_MAX
02817 };
02818
02819 #define def_builtin(NAME, TYPE, CODE) \
02820 do { \
02821 lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
02822 NULL, NULL_TREE); \
02823 } while (0)
02824
02825
02826 static void
02827 bfin_init_builtins (void)
02828 {
02829 tree void_ftype_void
02830 = build_function_type (void_type_node, void_list_node);
02831
02832
02833 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
02834 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
02835 }
02836
02837
02838
02839
02840
02841
02842
02843 static rtx
02844 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
02845 rtx subtarget ATTRIBUTE_UNUSED,
02846 enum machine_mode mode ATTRIBUTE_UNUSED,
02847 int ignore ATTRIBUTE_UNUSED)
02848 {
02849 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
02850 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
02851
02852 switch (fcode)
02853 {
02854 case BFIN_BUILTIN_CSYNC:
02855 emit_insn (gen_csync ());
02856 return 0;
02857 case BFIN_BUILTIN_SSYNC:
02858 emit_insn (gen_ssync ());
02859 return 0;
02860
02861 default:
02862 gcc_unreachable ();
02863 }
02864 }
02865
02866 #undef TARGET_INIT_BUILTINS
02867 #define TARGET_INIT_BUILTINS bfin_init_builtins
02868
02869 #undef TARGET_EXPAND_BUILTIN
02870 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
02871
02872 #undef TARGET_ASM_GLOBALIZE_LABEL
02873 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
02874
02875 #undef TARGET_ASM_FILE_START
02876 #define TARGET_ASM_FILE_START output_file_start
02877
02878 #undef TARGET_ATTRIBUTE_TABLE
02879 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
02880
02881 #undef TARGET_COMP_TYPE_ATTRIBUTES
02882 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
02883
02884 #undef TARGET_RTX_COSTS
02885 #define TARGET_RTX_COSTS bfin_rtx_costs
02886
02887 #undef TARGET_ADDRESS_COST
02888 #define TARGET_ADDRESS_COST bfin_address_cost
02889
02890 #undef TARGET_ASM_INTERNAL_LABEL
02891 #define TARGET_ASM_INTERNAL_LABEL bfin_internal_label
02892
02893 #undef TARGET_MACHINE_DEPENDENT_REORG
02894 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
02895
02896 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
02897 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
02898
02899 #undef TARGET_ASM_OUTPUT_MI_THUNK
02900 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
02901 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
02902 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
02903
02904 #undef TARGET_SCHED_ADJUST_COST
02905 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
02906
02907 #undef TARGET_PROMOTE_PROTOTYPES
02908 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
02909 #undef TARGET_PROMOTE_FUNCTION_ARGS
02910 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
02911 #undef TARGET_PROMOTE_FUNCTION_RETURN
02912 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
02913
02914 #undef TARGET_ARG_PARTIAL_BYTES
02915 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
02916
02917 #undef TARGET_PASS_BY_REFERENCE
02918 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
02919
02920 #undef TARGET_SETUP_INCOMING_VARARGS
02921 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
02922
02923 #undef TARGET_STRUCT_VALUE_RTX
02924 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
02925
02926 #undef TARGET_VECTOR_MODE_SUPPORTED_P
02927 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
02928
02929 struct gcc_target targetm = TARGET_INITIALIZER;