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 "optabs.h"
00047 #include "ggc.h"
00048 #include "integrate.h"
00049 #include "cgraph.h"
00050 #include "langhooks.h"
00051 #include "bfin-protos.h"
00052 #include "tm-preds.h"
00053 #include "gt-bfin.h"
00054 #include "basic-block.h"
00055
00056
00057
00058 struct machine_function GTY(())
00059 {
00060 int has_hardware_loops;
00061 };
00062
00063
00064
00065 rtx bfin_compare_op0, bfin_compare_op1;
00066
00067
00068 extern GTY(()) rtx bfin_cc_rtx;
00069 extern GTY(()) rtx bfin_rets_rtx;
00070 rtx bfin_cc_rtx, bfin_rets_rtx;
00071
00072 int max_arg_registers = 0;
00073
00074
00075 const char *short_reg_names[] = SHORT_REGISTER_NAMES;
00076 const char *high_reg_names[] = HIGH_REGISTER_NAMES;
00077 const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
00078 const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
00079
00080 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
00081
00082
00083 static int bfin_lib_id_given;
00084
00085 static void
00086 bfin_globalize_label (FILE *stream, const char *name)
00087 {
00088 fputs (".global ", stream);
00089 assemble_name (stream, name);
00090 fputc (';',stream);
00091 fputc ('\n',stream);
00092 }
00093
00094 static void
00095 output_file_start (void)
00096 {
00097 FILE *file = asm_out_file;
00098 int i;
00099
00100 fprintf (file, ".file \"%s\";\n", input_filename);
00101
00102 for (i = 0; arg_regs[i] >= 0; i++)
00103 ;
00104 max_arg_registers = i;
00105 }
00106
00107
00108
00109
00110 void
00111 conditional_register_usage (void)
00112 {
00113
00114 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
00115 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
00116 }
00117
00118
00119
00120
00121 static e_funkind funkind (tree funtype)
00122 {
00123 tree attrs = TYPE_ATTRIBUTES (funtype);
00124 if (lookup_attribute ("interrupt_handler", attrs))
00125 return INTERRUPT_HANDLER;
00126 else if (lookup_attribute ("exception_handler", attrs))
00127 return EXCPT_HANDLER;
00128 else if (lookup_attribute ("nmi_handler", attrs))
00129 return NMI_HANDLER;
00130 else
00131 return SUBROUTINE;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140 static rtx
00141 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
00142 {
00143 rtx addr = orig;
00144 rtx new = orig;
00145
00146 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
00147 {
00148 if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
00149 reg = new = orig;
00150 else
00151 {
00152 int unspec;
00153 rtx tmp;
00154
00155 if (TARGET_ID_SHARED_LIBRARY)
00156 unspec = UNSPEC_MOVE_PIC;
00157 else if (GET_CODE (addr) == SYMBOL_REF
00158 && SYMBOL_REF_FUNCTION_P (addr))
00159 {
00160 unspec = UNSPEC_FUNCDESC_GOT17M4;
00161 }
00162 else
00163 {
00164 unspec = UNSPEC_MOVE_FDPIC;
00165 }
00166
00167 if (reg == 0)
00168 {
00169 gcc_assert (!no_new_pseudos);
00170 reg = gen_reg_rtx (Pmode);
00171 }
00172
00173 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
00174 new = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
00175
00176 emit_move_insn (reg, new);
00177 }
00178 if (picreg == pic_offset_table_rtx)
00179 current_function_uses_pic_offset_table = 1;
00180 return reg;
00181 }
00182
00183 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
00184 {
00185 rtx base;
00186
00187 if (GET_CODE (addr) == CONST)
00188 {
00189 addr = XEXP (addr, 0);
00190 gcc_assert (GET_CODE (addr) == PLUS);
00191 }
00192
00193 if (XEXP (addr, 0) == picreg)
00194 return orig;
00195
00196 if (reg == 0)
00197 {
00198 gcc_assert (!no_new_pseudos);
00199 reg = gen_reg_rtx (Pmode);
00200 }
00201
00202 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
00203 addr = legitimize_pic_address (XEXP (addr, 1),
00204 base == reg ? NULL_RTX : reg,
00205 picreg);
00206
00207 if (GET_CODE (addr) == CONST_INT)
00208 {
00209 gcc_assert (! reload_in_progress && ! reload_completed);
00210 addr = force_reg (Pmode, addr);
00211 }
00212
00213 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
00214 {
00215 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
00216 addr = XEXP (addr, 1);
00217 }
00218
00219 return gen_rtx_PLUS (Pmode, base, addr);
00220 }
00221
00222 return new;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 static int
00234 n_dregs_to_save (bool is_inthandler)
00235 {
00236 unsigned i;
00237
00238 for (i = REG_R0; i <= REG_R7; i++)
00239 {
00240 if (regs_ever_live[i] && (is_inthandler || ! call_used_regs[i]))
00241 return REG_R7 - i + 1;
00242
00243 if (current_function_calls_eh_return)
00244 {
00245 unsigned j;
00246 for (j = 0; ; j++)
00247 {
00248 unsigned test = EH_RETURN_DATA_REGNO (j);
00249 if (test == INVALID_REGNUM)
00250 break;
00251 if (test == i)
00252 return REG_R7 - i + 1;
00253 }
00254 }
00255
00256 }
00257 return 0;
00258 }
00259
00260
00261
00262 static int
00263 n_pregs_to_save (bool is_inthandler)
00264 {
00265 unsigned i;
00266
00267 for (i = REG_P0; i <= REG_P5; i++)
00268 if ((regs_ever_live[i] && (is_inthandler || ! call_used_regs[i]))
00269 || (!TARGET_FDPIC
00270 && i == PIC_OFFSET_TABLE_REGNUM
00271 && (current_function_uses_pic_offset_table
00272 || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))
00273 return REG_P5 - i + 1;
00274 return 0;
00275 }
00276
00277
00278
00279 static bool
00280 must_save_fp_p (void)
00281 {
00282 return frame_pointer_needed || regs_ever_live[REG_FP];
00283 }
00284
00285 static bool
00286 stack_frame_needed_p (void)
00287 {
00288
00289
00290 if (current_function_calls_eh_return)
00291 return true;
00292 return frame_pointer_needed;
00293 }
00294
00295
00296
00297
00298
00299
00300 static void
00301 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
00302 {
00303 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
00304 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
00305 int dregno = REG_R7 + 1 - ndregs;
00306 int pregno = REG_P5 + 1 - npregs;
00307 int total = ndregs + npregs;
00308 int i;
00309 rtx pat, insn, val;
00310
00311 if (total == 0)
00312 return;
00313
00314 val = GEN_INT (-total * 4);
00315 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));
00316 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
00317 UNSPEC_PUSH_MULTIPLE);
00318 XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,
00319 gen_rtx_PLUS (Pmode, spreg,
00320 val));
00321 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;
00322 for (i = 0; i < total; i++)
00323 {
00324 rtx memref = gen_rtx_MEM (word_mode,
00325 gen_rtx_PLUS (Pmode, spreg,
00326 GEN_INT (- i * 4 - 4)));
00327 rtx subpat;
00328 if (ndregs > 0)
00329 {
00330 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
00331 dregno++));
00332 ndregs--;
00333 }
00334 else
00335 {
00336 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
00337 pregno++));
00338 npregs++;
00339 }
00340 XVECEXP (pat, 0, i + 1) = subpat;
00341 RTX_FRAME_RELATED_P (subpat) = 1;
00342 }
00343 insn = emit_insn (pat);
00344 RTX_FRAME_RELATED_P (insn) = 1;
00345 }
00346
00347
00348
00349
00350
00351
00352 static void
00353 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
00354 {
00355 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
00356 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
00357 int total = ndregs + npregs;
00358 int i, regno;
00359 rtx pat, insn;
00360
00361 if (total == 0)
00362 return;
00363
00364 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));
00365 XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,
00366 gen_rtx_PLUS (Pmode, spreg,
00367 GEN_INT (total * 4)));
00368
00369 if (npregs > 0)
00370 regno = REG_P5 + 1;
00371 else
00372 regno = REG_R7 + 1;
00373
00374 for (i = 0; i < total; i++)
00375 {
00376 rtx addr = (i > 0
00377 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
00378 : spreg);
00379 rtx memref = gen_rtx_MEM (word_mode, addr);
00380
00381 regno--;
00382 XVECEXP (pat, 0, i + 1)
00383 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
00384
00385 if (npregs > 0)
00386 {
00387 if (--npregs == 0)
00388 regno = REG_R7 + 1;
00389 }
00390 }
00391
00392 insn = emit_insn (pat);
00393 RTX_FRAME_RELATED_P (insn) = 1;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 static void
00419 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
00420 enum machine_mode mode ATTRIBUTE_UNUSED,
00421 tree type ATTRIBUTE_UNUSED, int *pretend_size,
00422 int no_rtl)
00423 {
00424 rtx mem;
00425 int i;
00426
00427 if (no_rtl)
00428 return;
00429
00430
00431
00432
00433
00434
00435 for (i = cum->words + 1; i < max_arg_registers; i++)
00436 {
00437 mem = gen_rtx_MEM (Pmode,
00438 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
00439 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
00440 }
00441
00442 *pretend_size = 0;
00443 }
00444
00445
00446
00447
00448
00449 int
00450 bfin_frame_pointer_required (void)
00451 {
00452 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00453
00454 if (fkind != SUBROUTINE)
00455 return 1;
00456
00457
00458
00459 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
00460 return 1;
00461
00462 return 0;
00463 }
00464
00465
00466
00467 static int
00468 n_regs_saved_by_prologue (void)
00469 {
00470 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00471 bool is_inthandler = fkind != SUBROUTINE;
00472 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00473 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
00474 || (is_inthandler && !current_function_is_leaf));
00475 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler);
00476 int npregs = all ? 6 : n_pregs_to_save (is_inthandler);
00477 int n = ndregs + npregs;
00478
00479 if (all || stack_frame_needed_p ())
00480
00481 n += 2;
00482 else
00483 {
00484 if (must_save_fp_p ())
00485 n++;
00486 if (! current_function_is_leaf)
00487 n++;
00488 }
00489
00490 if (fkind != SUBROUTINE)
00491 {
00492 int i;
00493
00494
00495 n++;
00496
00497
00498 if (lookup_attribute ("nesting", attrs))
00499 n++;
00500
00501 for (i = REG_P7 + 1; i < REG_CC; i++)
00502 if (all
00503 || regs_ever_live[i]
00504 || (!leaf_function_p () && call_used_regs[i]))
00505 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
00506 }
00507 return n;
00508 }
00509
00510
00511
00512
00513 HOST_WIDE_INT
00514 bfin_initial_elimination_offset (int from, int to)
00515 {
00516 HOST_WIDE_INT offset = 0;
00517
00518 if (from == ARG_POINTER_REGNUM)
00519 offset = n_regs_saved_by_prologue () * 4;
00520
00521 if (to == STACK_POINTER_REGNUM)
00522 {
00523 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
00524 offset += current_function_outgoing_args_size;
00525 else if (current_function_outgoing_args_size)
00526 offset += FIXED_STACK_AREA;
00527
00528 offset += get_frame_size ();
00529 }
00530
00531 return offset;
00532 }
00533
00534
00535
00536
00537
00538 static void
00539 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
00540 {
00541 rtx insn;
00542 rtx cst = GEN_INT (constant);
00543
00544 if (constant >= -32768 && constant < 65536)
00545 insn = emit_move_insn (reg, cst);
00546 else
00547 {
00548
00549
00550 insn = emit_insn (gen_movsi_high (reg, cst));
00551 if (related)
00552 RTX_FRAME_RELATED_P (insn) = 1;
00553 insn = emit_insn (gen_movsi_low (reg, reg, cst));
00554 }
00555 if (related)
00556 RTX_FRAME_RELATED_P (insn) = 1;
00557 }
00558
00559
00560
00561
00562
00563 static void
00564 add_to_sp (rtx spreg, HOST_WIDE_INT value, int frame)
00565 {
00566 if (value == 0)
00567 return;
00568
00569
00570
00571
00572 if (value > 120 || value < -120)
00573 {
00574 rtx tmpreg = gen_rtx_REG (SImode, REG_P1);
00575 rtx insn;
00576
00577 if (frame)
00578 frame_related_constant_load (tmpreg, value, TRUE);
00579 else
00580 {
00581 insn = emit_move_insn (tmpreg, GEN_INT (value));
00582 if (frame)
00583 RTX_FRAME_RELATED_P (insn) = 1;
00584 }
00585
00586 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
00587 if (frame)
00588 RTX_FRAME_RELATED_P (insn) = 1;
00589 }
00590 else
00591 do
00592 {
00593 int size = value;
00594 rtx insn;
00595
00596 if (size > 60)
00597 size = 60;
00598 else if (size < -60)
00599
00600
00601 size = -60;
00602
00603 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size)));
00604 if (frame)
00605 RTX_FRAME_RELATED_P (insn) = 1;
00606 value -= size;
00607 }
00608 while (value != 0);
00609 }
00610
00611
00612
00613
00614
00615 static void
00616 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
00617 {
00618 HOST_WIDE_INT link_size = frame_size;
00619 rtx insn;
00620 int i;
00621
00622 if (link_size > 262140)
00623 link_size = 262140;
00624
00625
00626
00627 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
00628 RTX_FRAME_RELATED_P (insn) = 1;
00629
00630 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
00631 {
00632 rtx set = XVECEXP (PATTERN (insn), 0, i);
00633 gcc_assert (GET_CODE (set) == SET);
00634 RTX_FRAME_RELATED_P (set) = 1;
00635 }
00636
00637 frame_size -= link_size;
00638
00639 if (frame_size > 0)
00640 {
00641
00642 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
00643
00644 frame_related_constant_load (tmpreg, -frame_size, TRUE);
00645 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
00646 RTX_FRAME_RELATED_P (insn) = 1;
00647 }
00648 }
00649
00650
00651
00652
00653 static HOST_WIDE_INT
00654 arg_area_size (void)
00655 {
00656 if (current_function_outgoing_args_size)
00657 {
00658 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
00659 return current_function_outgoing_args_size;
00660 else
00661 return FIXED_STACK_AREA;
00662 }
00663 return 0;
00664 }
00665
00666
00667
00668
00669
00670 static void
00671 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
00672 {
00673 frame_size += arg_area_size ();
00674
00675 if (all || stack_frame_needed_p ()
00676 || (must_save_fp_p () && ! current_function_is_leaf))
00677 emit_link_insn (spreg, frame_size);
00678 else
00679 {
00680 if (! current_function_is_leaf)
00681 {
00682 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
00683 gen_rtx_PRE_DEC (Pmode, spreg)),
00684 bfin_rets_rtx);
00685 rtx insn = emit_insn (pat);
00686 RTX_FRAME_RELATED_P (insn) = 1;
00687 }
00688 if (must_save_fp_p ())
00689 {
00690 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
00691 gen_rtx_PRE_DEC (Pmode, spreg)),
00692 gen_rtx_REG (Pmode, REG_FP));
00693 rtx insn = emit_insn (pat);
00694 RTX_FRAME_RELATED_P (insn) = 1;
00695 }
00696 add_to_sp (spreg, -frame_size, 1);
00697 }
00698 }
00699
00700
00701
00702 static void
00703 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all)
00704 {
00705 frame_size += arg_area_size ();
00706
00707 if (all || stack_frame_needed_p ())
00708 emit_insn (gen_unlink ());
00709 else
00710 {
00711 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
00712
00713 add_to_sp (spreg, frame_size, 0);
00714 if (must_save_fp_p ())
00715 {
00716 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
00717 emit_move_insn (fpreg, postinc);
00718 emit_insn (gen_rtx_USE (VOIDmode, fpreg));
00719 }
00720 if (! current_function_is_leaf)
00721 {
00722 emit_move_insn (bfin_rets_rtx, postinc);
00723 emit_insn (gen_rtx_USE (VOIDmode, bfin_rets_rtx));
00724 }
00725 }
00726 }
00727
00728
00729
00730
00731
00732 static void
00733 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind)
00734 {
00735 int i;
00736 HOST_WIDE_INT frame_size = get_frame_size ();
00737 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
00738 rtx predec = gen_rtx_MEM (SImode, predec1);
00739 rtx insn;
00740 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00741 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
00742 tree kspisusp = lookup_attribute ("kspisusp", attrs);
00743
00744 if (kspisusp)
00745 {
00746 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
00747 RTX_FRAME_RELATED_P (insn) = 1;
00748 }
00749
00750
00751
00752 if (fkind == EXCPT_HANDLER)
00753 {
00754 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
00755 RTX_FRAME_RELATED_P (insn) = 1;
00756 }
00757
00758 insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
00759 RTX_FRAME_RELATED_P (insn) = 1;
00760
00761
00762
00763 if (!current_function_is_leaf)
00764 all = true;
00765 expand_prologue_reg_save (spreg, all, true);
00766
00767 for (i = REG_P7 + 1; i < REG_CC; i++)
00768 if (all
00769 || regs_ever_live[i]
00770 || (!leaf_function_p () && call_used_regs[i]))
00771 {
00772 if (i == REG_A0 || i == REG_A1)
00773 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
00774 gen_rtx_REG (PDImode, i));
00775 else
00776 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
00777 RTX_FRAME_RELATED_P (insn) = 1;
00778 }
00779
00780 if (lookup_attribute ("nesting", attrs))
00781 {
00782 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
00783 : fkind == NMI_HANDLER ? REG_RETN
00784 : REG_RETI));
00785 insn = emit_move_insn (predec, srcreg);
00786 RTX_FRAME_RELATED_P (insn) = 1;
00787 }
00788
00789 do_link (spreg, frame_size, all);
00790
00791 if (fkind == EXCPT_HANDLER)
00792 {
00793 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
00794 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
00795 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
00796 rtx insn;
00797
00798 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
00799 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00800 NULL_RTX);
00801 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
00802 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00803 NULL_RTX);
00804 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
00805 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00806 NULL_RTX);
00807 insn = emit_move_insn (r1reg, spreg);
00808 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00809 NULL_RTX);
00810 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
00811 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00812 NULL_RTX);
00813 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
00814 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
00815 NULL_RTX);
00816 }
00817 }
00818
00819
00820
00821
00822
00823 static void
00824 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind)
00825 {
00826 int i;
00827 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
00828 rtx postinc = gen_rtx_MEM (SImode, postinc1);
00829 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00830 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
00831
00832
00833
00834 MEM_VOLATILE_P (postinc) = 1;
00835
00836 do_unlink (spreg, get_frame_size (), all);
00837
00838 if (lookup_attribute ("nesting", attrs))
00839 {
00840 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
00841 : fkind == NMI_HANDLER ? REG_RETN
00842 : REG_RETI));
00843 emit_move_insn (srcreg, postinc);
00844 }
00845
00846
00847
00848 if (!current_function_is_leaf)
00849 all = true;
00850
00851 for (i = REG_CC - 1; i > REG_P7; i--)
00852 if (all
00853 || regs_ever_live[i]
00854 || (!leaf_function_p () && call_used_regs[i]))
00855 {
00856 if (i == REG_A0 || i == REG_A1)
00857 {
00858 rtx mem = gen_rtx_MEM (PDImode, postinc1);
00859 MEM_VOLATILE_P (mem) = 1;
00860 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
00861 }
00862 else
00863 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
00864 }
00865
00866 expand_epilogue_reg_restore (spreg, all, true);
00867
00868 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
00869
00870
00871
00872 if (fkind == EXCPT_HANDLER)
00873 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
00874
00875 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
00876 }
00877
00878
00879
00880
00881 static rtx
00882 bfin_load_pic_reg (rtx dest)
00883 {
00884 struct cgraph_local_info *i = NULL;
00885 rtx addr, insn;
00886
00887 if (flag_unit_at_a_time)
00888 i = cgraph_local_info (current_function_decl);
00889
00890
00891
00892 if (i && i->local)
00893 return pic_offset_table_rtx;
00894
00895 if (bfin_lib_id_given)
00896 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
00897 else
00898 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
00899 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
00900 UNSPEC_LIBRARY_OFFSET));
00901 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
00902 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
00903 return dest;
00904 }
00905
00906
00907
00908 void
00909 bfin_expand_prologue (void)
00910 {
00911 rtx insn;
00912 HOST_WIDE_INT frame_size = get_frame_size ();
00913 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
00914 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00915 rtx pic_reg_loaded = NULL_RTX;
00916
00917 if (fkind != SUBROUTINE)
00918 {
00919 expand_interrupt_handler_prologue (spreg, fkind);
00920 return;
00921 }
00922
00923 if (current_function_limit_stack)
00924 {
00925 HOST_WIDE_INT offset
00926 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
00927 STACK_POINTER_REGNUM);
00928 rtx lim = stack_limit_rtx;
00929
00930 if (GET_CODE (lim) == SYMBOL_REF)
00931 {
00932 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
00933 if (TARGET_ID_SHARED_LIBRARY)
00934 {
00935 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
00936 rtx val;
00937 pic_reg_loaded = bfin_load_pic_reg (p2reg);
00938 val = legitimize_pic_address (stack_limit_rtx, p1reg,
00939 pic_reg_loaded);
00940 emit_move_insn (p1reg, val);
00941 frame_related_constant_load (p2reg, offset, FALSE);
00942 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
00943 lim = p2reg;
00944 }
00945 else
00946 {
00947 rtx limit = plus_constant (stack_limit_rtx, offset);
00948 emit_move_insn (p2reg, limit);
00949 lim = p2reg;
00950 }
00951 }
00952 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
00953 emit_insn (gen_trapifcc ());
00954 }
00955 expand_prologue_reg_save (spreg, 0, false);
00956
00957 do_link (spreg, frame_size, false);
00958
00959 if (TARGET_ID_SHARED_LIBRARY
00960 && (current_function_uses_pic_offset_table
00961 || !current_function_is_leaf))
00962 bfin_load_pic_reg (pic_offset_table_rtx);
00963 }
00964
00965
00966
00967
00968
00969 void
00970 bfin_expand_epilogue (int need_return, int eh_return)
00971 {
00972 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
00973 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
00974
00975 if (fkind != SUBROUTINE)
00976 {
00977 expand_interrupt_handler_epilogue (spreg, fkind);
00978 return;
00979 }
00980
00981 do_unlink (spreg, get_frame_size (), false);
00982
00983 expand_epilogue_reg_restore (spreg, false, false);
00984
00985
00986 if (! need_return)
00987 return;
00988
00989 if (eh_return)
00990 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
00991
00992 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
00993 }
00994
00995
00996
00997 int
00998 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
00999 unsigned int new_reg)
01000 {
01001
01002
01003
01004
01005 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
01006 && !regs_ever_live[new_reg])
01007 return 0;
01008
01009 return 1;
01010 }
01011
01012
01013
01014
01015
01016 rtx
01017 bfin_return_addr_rtx (int count)
01018 {
01019 if (count != 0)
01020 return const0_rtx;
01021
01022 return get_hard_reg_initial_val (Pmode, REG_RETS);
01023 }
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034 rtx
01035 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
01036 enum machine_mode mode ATTRIBUTE_UNUSED)
01037 {
01038 return NULL_RTX;
01039 }
01040
01041 static rtx
01042 bfin_delegitimize_address (rtx orig_x)
01043 {
01044 rtx x = orig_x, y;
01045
01046 if (GET_CODE (x) != MEM)
01047 return orig_x;
01048
01049 x = XEXP (x, 0);
01050 if (GET_CODE (x) == PLUS
01051 && GET_CODE (XEXP (x, 1)) == UNSPEC
01052 && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
01053 && GET_CODE (XEXP (x, 0)) == REG
01054 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
01055 return XVECEXP (XEXP (x, 1), 0, 0);
01056
01057 return orig_x;
01058 }
01059
01060
01061
01062
01063
01064 int
01065 effective_address_32bit_p (rtx op, enum machine_mode mode)
01066 {
01067 HOST_WIDE_INT offset;
01068
01069 mode = GET_MODE (op);
01070 op = XEXP (op, 0);
01071
01072 if (GET_CODE (op) != PLUS)
01073 {
01074 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
01075 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
01076 return 0;
01077 }
01078
01079 offset = INTVAL (XEXP (op, 1));
01080
01081
01082 if (GET_MODE_SIZE (mode) == 1)
01083 return 1;
01084
01085 if (GET_MODE_SIZE (mode) == 4)
01086 {
01087
01088
01089 if (XEXP (op, 0) == frame_pointer_rtx)
01090 return offset < -128 || offset > 60;
01091 return offset < 0 || offset > 60;
01092 }
01093
01094
01095 return offset < 0 || offset > 30;
01096 }
01097
01098
01099 bool
01100 bfin_dsp_memref_p (rtx x)
01101 {
01102 if (! MEM_P (x))
01103 return false;
01104 x = XEXP (x, 0);
01105 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
01106 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
01107 x = XEXP (x, 0);
01108 return IREG_P (x);
01109 }
01110
01111
01112
01113
01114 static int
01115 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED)
01116 {
01117 return 1;
01118 }
01119
01120
01121
01122 void
01123 print_address_operand (FILE *file, rtx x)
01124 {
01125 switch (GET_CODE (x))
01126 {
01127 case PLUS:
01128 output_address (XEXP (x, 0));
01129 fprintf (file, "+");
01130 output_address (XEXP (x, 1));
01131 break;
01132
01133 case PRE_DEC:
01134 fprintf (file, "--");
01135 output_address (XEXP (x, 0));
01136 break;
01137 case POST_INC:
01138 output_address (XEXP (x, 0));
01139 fprintf (file, "++");
01140 break;
01141 case POST_DEC:
01142 output_address (XEXP (x, 0));
01143 fprintf (file, "--");
01144 break;
01145
01146 default:
01147 gcc_assert (GET_CODE (x) != MEM);
01148 print_operand (file, x, 0);
01149 break;
01150 }
01151 }
01152
01153
01154
01155
01156
01157
01158 void
01159 print_operand (FILE *file, rtx x, char code)
01160 {
01161 enum machine_mode mode = GET_MODE (x);
01162
01163 switch (code)
01164 {
01165 case 'j':
01166 switch (GET_CODE (x))
01167 {
01168 case EQ:
01169 fprintf (file, "e");
01170 break;
01171 case NE:
01172 fprintf (file, "ne");
01173 break;
01174 case GT:
01175 fprintf (file, "g");
01176 break;
01177 case LT:
01178 fprintf (file, "l");
01179 break;
01180 case GE:
01181 fprintf (file, "ge");
01182 break;
01183 case LE:
01184 fprintf (file, "le");
01185 break;
01186 case GTU:
01187 fprintf (file, "g");
01188 break;
01189 case LTU:
01190 fprintf (file, "l");
01191 break;
01192 case GEU:
01193 fprintf (file, "ge");
01194 break;
01195 case LEU:
01196 fprintf (file, "le");
01197 break;
01198 default:
01199 output_operand_lossage ("invalid %%j value");
01200 }
01201 break;
01202
01203 case 'J':
01204 switch (GET_CODE(x))
01205 {
01206 case EQ:
01207 fprintf (file, "ne");
01208 break;
01209 case NE:
01210 fprintf (file, "e");
01211 break;
01212 case GT:
01213 fprintf (file, "le");
01214 break;
01215 case LT:
01216 fprintf (file, "ge");
01217 break;
01218 case GE:
01219 fprintf (file, "l");
01220 break;
01221 case LE:
01222 fprintf (file, "g");
01223 break;
01224 case GTU:
01225 fprintf (file, "le");
01226 break;
01227 case LTU:
01228 fprintf (file, "ge");
01229 break;
01230 case GEU:
01231 fprintf (file, "l");
01232 break;
01233 case LEU:
01234 fprintf (file, "g");
01235 break;
01236 default:
01237 output_operand_lossage ("invalid %%J value");
01238 }
01239 break;
01240
01241 default:
01242 switch (GET_CODE (x))
01243 {
01244 case REG:
01245 if (code == 'h')
01246 {
01247 gcc_assert (REGNO (x) < 32);
01248 fprintf (file, "%s", short_reg_names[REGNO (x)]);
01249
01250 break;
01251 }
01252 else if (code == 'd')
01253 {
01254 gcc_assert (REGNO (x) < 32);
01255 fprintf (file, "%s", high_reg_names[REGNO (x)]);
01256 break;
01257 }
01258 else if (code == 'w')
01259 {
01260 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
01261 fprintf (file, "%s.w", reg_names[REGNO (x)]);
01262 }
01263 else if (code == 'x')
01264 {
01265 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
01266 fprintf (file, "%s.x", reg_names[REGNO (x)]);
01267 }
01268 else if (code == 'D')
01269 {
01270 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
01271 }
01272 else if (code == 'H')
01273 {
01274 gcc_assert (mode == DImode || mode == DFmode);
01275 gcc_assert (REG_P (x));
01276 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
01277 }
01278 else if (code == 'T')
01279 {
01280 gcc_assert (D_REGNO_P (REGNO (x)));
01281 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
01282 }
01283 else
01284 fprintf (file, "%s", reg_names[REGNO (x)]);
01285 break;
01286
01287 case MEM:
01288 fputc ('[', file);
01289 x = XEXP (x,0);
01290 print_address_operand (file, x);
01291 fputc (']', file);
01292 break;
01293
01294 case CONST_INT:
01295 if (code == 'M')
01296 {
01297 switch (INTVAL (x))
01298 {
01299 case MACFLAG_NONE:
01300 break;
01301 case MACFLAG_FU:
01302 fputs ("(FU)", file);
01303 break;
01304 case MACFLAG_T:
01305 fputs ("(T)", file);
01306 break;
01307 case MACFLAG_TFU:
01308 fputs ("(TFU)", file);
01309 break;
01310 case MACFLAG_W32:
01311 fputs ("(W32)", file);
01312 break;
01313 case MACFLAG_IS:
01314 fputs ("(IS)", file);
01315 break;
01316 case MACFLAG_IU:
01317 fputs ("(IU)", file);
01318 break;
01319 case MACFLAG_IH:
01320 fputs ("(IH)", file);
01321 break;
01322 case MACFLAG_M:
01323 fputs ("(M)", file);
01324 break;
01325 case MACFLAG_ISS2:
01326 fputs ("(ISS2)", file);
01327 break;
01328 case MACFLAG_S2RND:
01329 fputs ("(S2RND)", file);
01330 break;
01331 default:
01332 gcc_unreachable ();
01333 }
01334 break;
01335 }
01336 else if (code == 'b')
01337 {
01338 if (INTVAL (x) == 0)
01339 fputs ("+=", file);
01340 else if (INTVAL (x) == 1)
01341 fputs ("-=", file);
01342 else
01343 gcc_unreachable ();
01344 break;
01345 }
01346
01347
01348 else if (code == 'd')
01349 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
01350 else if (code == 'h')
01351 x = GEN_INT (INTVAL (x) & 0xffff);
01352 else if (code == 'X')
01353 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
01354 else if (code == 'Y')
01355 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
01356 else if (code == 'Z')
01357
01358 x = GEN_INT (-8 - INTVAL (x));
01359
01360
01361
01362 case SYMBOL_REF:
01363 output_addr_const (file, x);
01364 break;
01365
01366 case CONST_DOUBLE:
01367 output_operand_lossage ("invalid const_double operand");
01368 break;
01369
01370 case UNSPEC:
01371 switch (XINT (x, 1))
01372 {
01373 case UNSPEC_MOVE_PIC:
01374 output_addr_const (file, XVECEXP (x, 0, 0));
01375 fprintf (file, "@GOT");
01376 break;
01377
01378 case UNSPEC_MOVE_FDPIC:
01379 output_addr_const (file, XVECEXP (x, 0, 0));
01380 fprintf (file, "@GOT17M4");
01381 break;
01382
01383 case UNSPEC_FUNCDESC_GOT17M4:
01384 output_addr_const (file, XVECEXP (x, 0, 0));
01385 fprintf (file, "@FUNCDESC_GOT17M4");
01386 break;
01387
01388 case UNSPEC_LIBRARY_OFFSET:
01389 fprintf (file, "_current_shared_library_p5_offset_");
01390 break;
01391
01392 default:
01393 gcc_unreachable ();
01394 }
01395 break;
01396
01397 default:
01398 output_addr_const (file, x);
01399 }
01400 }
01401 }
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412 void
01413 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
01414 rtx libname ATTRIBUTE_UNUSED)
01415 {
01416 static CUMULATIVE_ARGS zero_cum;
01417
01418 *cum = zero_cum;
01419
01420
01421
01422 cum->nregs = max_arg_registers;
01423 cum->arg_regs = arg_regs;
01424
01425 cum->call_cookie = CALL_NORMAL;
01426
01427 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
01428 cum->call_cookie |= CALL_SHORT;
01429 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
01430 cum->call_cookie |= CALL_LONG;
01431
01432 return;
01433 }
01434
01435
01436
01437
01438
01439 void
01440 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
01441 int named ATTRIBUTE_UNUSED)
01442 {
01443 int count, bytes, words;
01444
01445 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
01446 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
01447
01448 cum->words += words;
01449 cum->nregs -= words;
01450
01451 if (cum->nregs <= 0)
01452 {
01453 cum->nregs = 0;
01454 cum->arg_regs = NULL;
01455 }
01456 else
01457 {
01458 for (count = 1; count <= words; count++)
01459 cum->arg_regs++;
01460 }
01461
01462 return;
01463 }
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478 struct rtx_def *
01479 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
01480 int named ATTRIBUTE_UNUSED)
01481 {
01482 int bytes
01483 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
01484
01485 if (mode == VOIDmode)
01486
01487 return GEN_INT (cum->call_cookie);
01488
01489 if (bytes == -1)
01490 return NULL_RTX;
01491
01492 if (cum->nregs)
01493 return gen_rtx_REG (mode, *(cum->arg_regs));
01494
01495 return NULL_RTX;
01496 }
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507 static int
01508 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
01509 tree type ATTRIBUTE_UNUSED,
01510 bool named ATTRIBUTE_UNUSED)
01511 {
01512 int bytes
01513 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
01514 int bytes_left = cum->nregs * UNITS_PER_WORD;
01515
01516 if (bytes == -1)
01517 return 0;
01518
01519 if (bytes_left == 0)
01520 return 0;
01521 if (bytes > bytes_left)
01522 return bytes_left;
01523 return 0;
01524 }
01525
01526
01527
01528 static bool
01529 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
01530 enum machine_mode mode ATTRIBUTE_UNUSED,
01531 tree type, bool named ATTRIBUTE_UNUSED)
01532 {
01533 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
01534 }
01535
01536
01537
01538
01539
01540 int
01541 bfin_return_in_memory (tree type)
01542 {
01543 int size = int_size_in_bytes (type);
01544 return size > 2 * UNITS_PER_WORD || size == -1;
01545 }
01546
01547
01548
01549 static rtx
01550 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
01551 int incoming ATTRIBUTE_UNUSED)
01552 {
01553 return gen_rtx_REG (Pmode, REG_P0);
01554 }
01555
01556
01557
01558 bool
01559 function_arg_regno_p (int n)
01560 {
01561 int i;
01562 for (i = 0; arg_regs[i] != -1; i++)
01563 if (n == arg_regs[i])
01564 return true;
01565 return false;
01566 }
01567
01568
01569
01570 int
01571 symbolic_reference_mentioned_p (rtx op)
01572 {
01573 register const char *fmt;
01574 register int i;
01575
01576 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
01577 return 1;
01578
01579 fmt = GET_RTX_FORMAT (GET_CODE (op));
01580 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
01581 {
01582 if (fmt[i] == 'E')
01583 {
01584 register int j;
01585
01586 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
01587 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
01588 return 1;
01589 }
01590
01591 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
01592 return 1;
01593 }
01594
01595 return 0;
01596 }
01597
01598
01599
01600
01601
01602 static bool
01603 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
01604 tree exp ATTRIBUTE_UNUSED)
01605 {
01606 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
01607 return fkind == SUBROUTINE;
01608 }
01609
01610
01611
01612
01613
01614 void
01615 initialize_trampoline (tramp, fnaddr, cxt)
01616 rtx tramp, fnaddr, cxt;
01617 {
01618 rtx t1 = copy_to_reg (fnaddr);
01619 rtx t2 = copy_to_reg (cxt);
01620 rtx addr;
01621 int i = 0;
01622
01623 if (TARGET_FDPIC)
01624 {
01625 rtx a = memory_address (Pmode, plus_constant (tramp, 8));
01626 addr = memory_address (Pmode, tramp);
01627 emit_move_insn (gen_rtx_MEM (SImode, addr), a);
01628 i = 8;
01629 }
01630
01631 addr = memory_address (Pmode, plus_constant (tramp, i + 2));
01632 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
01633 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
01634 addr = memory_address (Pmode, plus_constant (tramp, i + 6));
01635 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
01636
01637 addr = memory_address (Pmode, plus_constant (tramp, i + 10));
01638 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
01639 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
01640 addr = memory_address (Pmode, plus_constant (tramp, i + 14));
01641 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
01642 }
01643
01644
01645
01646 void
01647 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
01648 {
01649 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
01650
01651 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
01652 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
01653 operands[1] = force_reg (SImode, operands[1]);
01654 else
01655 operands[1] = legitimize_pic_address (operands[1], temp,
01656 TARGET_FDPIC ? OUR_FDPIC_REG
01657 : pic_offset_table_rtx);
01658 }
01659
01660
01661
01662 void
01663 expand_move (rtx *operands, enum machine_mode mode)
01664 {
01665 rtx op = operands[1];
01666 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
01667 && SYMBOLIC_CONST (op))
01668 emit_pic_move (operands, mode);
01669
01670
01671 else if ((reload_in_progress | reload_completed) == 0
01672 && GET_CODE (operands[0]) == MEM
01673 && GET_CODE (operands[1]) != REG)
01674 operands[1] = force_reg (mode, operands[1]);
01675 }
01676
01677
01678
01679
01680
01681
01682
01683 void
01684 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
01685 {
01686 while (num--)
01687 {
01688 rtx op = operands[num];
01689
01690
01691
01692 if (GET_CODE (op) == MEM)
01693 {
01694 lo_half[num] = adjust_address (op, SImode, 0);
01695 hi_half[num] = adjust_address (op, SImode, 4);
01696 }
01697 else
01698 {
01699 lo_half[num] = simplify_gen_subreg (SImode, op,
01700 GET_MODE (op) == VOIDmode
01701 ? DImode : GET_MODE (op), 0);
01702 hi_half[num] = simplify_gen_subreg (SImode, op,
01703 GET_MODE (op) == VOIDmode
01704 ? DImode : GET_MODE (op), 4);
01705 }
01706 }
01707 }
01708
01709 bool
01710 bfin_longcall_p (rtx op, int call_cookie)
01711 {
01712 gcc_assert (GET_CODE (op) == SYMBOL_REF);
01713 if (call_cookie & CALL_SHORT)
01714 return 0;
01715 if (call_cookie & CALL_LONG)
01716 return 1;
01717 if (TARGET_LONG_CALLS)
01718 return 1;
01719 return 0;
01720 }
01721
01722
01723
01724
01725
01726 void
01727 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
01728 {
01729 rtx use = NULL, call;
01730 rtx callee = XEXP (fnaddr, 0);
01731 int nelts = 2 + !!sibcall;
01732 rtx pat;
01733 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
01734 int n;
01735
01736
01737 if (cookie == NULL_RTX)
01738 cookie = const0_rtx;
01739
01740
01741 if (!TARGET_FDPIC && flag_pic
01742 && GET_CODE (callee) == SYMBOL_REF
01743 && !SYMBOL_REF_LOCAL_P (callee))
01744 use_reg (&use, pic_offset_table_rtx);
01745
01746 if (TARGET_FDPIC)
01747 {
01748 if (GET_CODE (callee) != SYMBOL_REF
01749 || bfin_longcall_p (callee, INTVAL (cookie)))
01750 {
01751 rtx addr = callee;
01752 if (! address_operand (addr, Pmode))
01753 addr = force_reg (Pmode, addr);
01754
01755 fnaddr = gen_reg_rtx (SImode);
01756 emit_insn (gen_load_funcdescsi (fnaddr, addr));
01757 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
01758
01759 picreg = gen_reg_rtx (SImode);
01760 emit_insn (gen_load_funcdescsi (picreg,
01761 plus_constant (addr, 4)));
01762 }
01763
01764 nelts++;
01765 }
01766 else if ((!register_no_elim_operand (callee, Pmode)
01767 && GET_CODE (callee) != SYMBOL_REF)
01768 || (GET_CODE (callee) == SYMBOL_REF
01769 && (flag_pic
01770 || bfin_longcall_p (callee, INTVAL (cookie)))))
01771 {
01772 callee = copy_to_mode_reg (Pmode, callee);
01773 fnaddr = gen_rtx_MEM (Pmode, callee);
01774 }
01775 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
01776
01777 if (retval)
01778 call = gen_rtx_SET (VOIDmode, retval, call);
01779
01780 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
01781 n = 0;
01782 XVECEXP (pat, 0, n++) = call;
01783 if (TARGET_FDPIC)
01784 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
01785 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
01786 if (sibcall)
01787 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
01788 call = emit_call_insn (pat);
01789 if (use)
01790 CALL_INSN_FUNCTION_USAGE (call) = use;
01791 }
01792
01793
01794
01795 int
01796 hard_regno_mode_ok (int regno, enum machine_mode mode)
01797 {
01798
01799 enum reg_class class = REGNO_REG_CLASS (regno);
01800
01801 if (mode == CCmode)
01802 return 0;
01803
01804 if (mode == V2HImode)
01805 return D_REGNO_P (regno);
01806 if (class == CCREGS)
01807 return mode == BImode;
01808 if (mode == PDImode || mode == V2PDImode)
01809 return regno == REG_A0 || regno == REG_A1;
01810 if (mode == SImode
01811 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
01812 return 1;
01813
01814 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
01815 }
01816
01817
01818
01819 static bool
01820 bfin_vector_mode_supported_p (enum machine_mode mode)
01821 {
01822 return mode == V2HImode;
01823 }
01824
01825
01826
01827
01828 int
01829 bfin_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
01830 enum reg_class class1, enum reg_class class2)
01831 {
01832
01833 if ((class1 == CCREGS && class2 != DREGS)
01834 || (class1 != DREGS && class2 == CCREGS))
01835 return 4;
01836
01837
01838 if (optimize_size)
01839 return 2;
01840
01841
01842
01843
01844 if (class1 == DREGS && class2 != DREGS)
01845 return 2 * 2;
01846
01847 return 2;
01848 }
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858 int
01859 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
01860 enum reg_class class,
01861 int in ATTRIBUTE_UNUSED)
01862 {
01863
01864
01865
01866 if (! reg_class_subset_p (class, DPREGS))
01867 return 10;
01868
01869 return 8;
01870 }
01871
01872
01873
01874
01875
01876 static enum reg_class
01877 bfin_secondary_reload (bool in_p, rtx x, enum reg_class class,
01878 enum machine_mode mode, secondary_reload_info *sri)
01879 {
01880
01881
01882 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
01883 enum reg_class x_class = NO_REGS;
01884 enum rtx_code code = GET_CODE (x);
01885
01886 if (code == SUBREG)
01887 x = SUBREG_REG (x), code = GET_CODE (x);
01888 if (REG_P (x))
01889 {
01890 int regno = REGNO (x);
01891 if (regno >= FIRST_PSEUDO_REGISTER)
01892 regno = reg_renumber[regno];
01893
01894 if (regno == -1)
01895 code = MEM;
01896 else
01897 x_class = REGNO_REG_CLASS (regno);
01898 }
01899
01900
01901
01902
01903 if (fp_plus_const_operand (x, mode))
01904 {
01905 rtx op2 = XEXP (x, 1);
01906 int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2));
01907
01908 if (class == PREGS || class == PREGS_CLOBBERED)
01909 return NO_REGS;
01910
01911
01912 if ((class == DREGS || class == DPREGS)
01913 && ! large_constant_p)
01914 return NO_REGS;
01915
01916
01917 sri->icode = CODE_FOR_reload_insi;
01918 return NO_REGS;
01919 }
01920
01921
01922
01923
01924 if (x_class == AREGS)
01925 return class == DREGS || class == AREGS ? NO_REGS : DREGS;
01926
01927 if (class == AREGS)
01928 {
01929 if (x != const0_rtx && x_class != DREGS)
01930 return DREGS;
01931 else
01932 return NO_REGS;
01933 }
01934
01935
01936 if (class == CCREGS && x_class != DREGS)
01937 return DREGS;
01938 if (x_class == CCREGS && class != DREGS)
01939 return DREGS;
01940
01941
01942
01943 if (code == MEM)
01944 if (! reg_class_subset_p (class, default_class))
01945 return default_class;
01946 return NO_REGS;
01947 }
01948
01949
01950
01951 static bool
01952 bfin_handle_option (size_t code, const char *arg, int value)
01953 {
01954 switch (code)
01955 {
01956 case OPT_mshared_library_id_:
01957 if (value > MAX_LIBRARY_ID)
01958 error ("-mshared-library-id=%s is not between 0 and %d",
01959 arg, MAX_LIBRARY_ID);
01960 bfin_lib_id_given = 1;
01961 return true;
01962
01963 default:
01964 return true;
01965 }
01966 }
01967
01968 static struct machine_function *
01969 bfin_init_machine_status (void)
01970 {
01971 struct machine_function *f;
01972
01973 f = ggc_alloc_cleared (sizeof (struct machine_function));
01974
01975 return f;
01976 }
01977
01978
01979
01980 void
01981 override_options (void)
01982 {
01983 if (TARGET_OMIT_LEAF_FRAME_POINTER)
01984 flag_omit_frame_pointer = 1;
01985
01986
01987 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
01988 error ("-mshared-library-id= specified without -mid-shared-library");
01989
01990 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
01991 flag_pic = 1;
01992
01993 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
01994 error ("ID shared libraries and FD-PIC mode can't be used together.");
01995
01996
01997
01998
01999 if (TARGET_FDPIC)
02000 targetm.asm_out.unaligned_op.si = 0;
02001
02002
02003
02004 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
02005 flag_pic = 0;
02006
02007 flag_schedule_insns = 0;
02008
02009 init_machine_status = bfin_init_machine_status;
02010 }
02011
02012
02013
02014
02015
02016
02017 static int
02018 branch_dest (rtx branch)
02019 {
02020 rtx dest;
02021 int dest_uid;
02022 rtx pat = PATTERN (branch);
02023 if (GET_CODE (pat) == PARALLEL)
02024 pat = XVECEXP (pat, 0, 0);
02025 dest = SET_SRC (pat);
02026 if (GET_CODE (dest) == IF_THEN_ELSE)
02027 dest = XEXP (dest, 1);
02028 dest = XEXP (dest, 0);
02029 dest_uid = INSN_UID (dest);
02030 return INSN_ADDRESSES (dest_uid);
02031 }
02032
02033
02034
02035
02036 static int
02037 cbranch_predicted_taken_p (rtx insn)
02038 {
02039 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
02040
02041 if (x)
02042 {
02043 int pred_val = INTVAL (XEXP (x, 0));
02044
02045 return pred_val >= REG_BR_PROB_BASE / 2;
02046 }
02047
02048 return 0;
02049 }
02050
02051
02052
02053 static const char *ccbranch_templates[][3] = {
02054 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
02055 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
02056 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
02057 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
02058 };
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071 void
02072 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
02073 {
02074 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
02075
02076
02077
02078
02079 int len = (offset >= -1024 && offset <= 1022 ? 0
02080 : offset >= -4094 && offset <= 4096 ? 1
02081 : 2);
02082 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
02083 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
02084 output_asm_insn (ccbranch_templates[idx][len], operands);
02085 gcc_assert (n_nops == 0 || !bp);
02086 if (len == 0)
02087 while (n_nops-- > 0)
02088 output_asm_insn ("nop;", NULL);
02089 }
02090
02091
02092
02093
02094 rtx
02095 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
02096 {
02097 enum rtx_code code1, code2;
02098 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
02099 rtx tem = bfin_cc_rtx;
02100 enum rtx_code code = GET_CODE (cmp);
02101
02102
02103
02104 if (GET_MODE (op0) == BImode)
02105 {
02106 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
02107 tem = op0, code2 = code;
02108 }
02109 else
02110 {
02111 switch (code) {
02112
02113 case EQ:
02114 case LT:
02115 case LE:
02116 case LEU:
02117 case LTU:
02118 code1 = code;
02119 code2 = NE;
02120 break;
02121 default:
02122 code1 = reverse_condition (code);
02123 code2 = EQ;
02124 break;
02125 }
02126 emit_insn (gen_rtx_SET (BImode, tem,
02127 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
02128 }
02129
02130 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
02131 }
02132
02133
02134
02135
02136 int
02137 log2constp (unsigned HOST_WIDE_INT c)
02138 {
02139 c &= 0xFFFFFFFF;
02140 return c != 0 && (c & (c-1)) == 0;
02141 }
02142
02143
02144
02145
02146
02147
02148 static int
02149 shiftr_zero (HOST_WIDE_INT *v)
02150 {
02151 unsigned HOST_WIDE_INT tmp = *v;
02152 unsigned HOST_WIDE_INT sgn;
02153 int n = 0;
02154
02155 if (tmp == 0)
02156 return 0;
02157
02158 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
02159 while ((tmp & 0x1) == 0 && n <= 32)
02160 {
02161 tmp = (tmp >> 1) | sgn;
02162 n++;
02163 }
02164 *v = tmp;
02165 return n;
02166 }
02167
02168
02169
02170
02171
02172
02173 int
02174 split_load_immediate (rtx operands[])
02175 {
02176 HOST_WIDE_INT val = INTVAL (operands[1]);
02177 HOST_WIDE_INT tmp;
02178 HOST_WIDE_INT shifted = val;
02179 HOST_WIDE_INT shifted_compl = ~val;
02180 int num_zero = shiftr_zero (&shifted);
02181 int num_compl_zero = shiftr_zero (&shifted_compl);
02182 unsigned int regno = REGNO (operands[0]);
02183 enum reg_class class1 = REGNO_REG_CLASS (regno);
02184
02185
02186
02187 if (num_zero
02188 && shifted >= -32768 && shifted < 65536
02189 && (D_REGNO_P (regno)
02190 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
02191 {
02192 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
02193 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
02194 return 1;
02195 }
02196
02197 tmp = val & 0xFFFF;
02198 tmp |= -(tmp & 0x8000);
02199
02200
02201 if (D_REGNO_P (regno))
02202 {
02203 if (log2constp (val & 0xFFFF0000))
02204 {
02205 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
02206 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
02207 return 1;
02208 }
02209 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
02210 {
02211 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
02212 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
02213 }
02214 }
02215
02216 if (D_REGNO_P (regno))
02217 {
02218 if (CONST_7BIT_IMM_P (tmp))
02219 {
02220 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
02221 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
02222 return 1;
02223 }
02224
02225 if ((val & 0xFFFF0000) == 0)
02226 {
02227 emit_insn (gen_movsi (operands[0], const0_rtx));
02228 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
02229 return 1;
02230 }
02231
02232 if ((val & 0xFFFF0000) == 0xFFFF0000)
02233 {
02234 emit_insn (gen_movsi (operands[0], constm1_rtx));
02235 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
02236 return 1;
02237 }
02238 }
02239
02240
02241 if (regno > REG_R7)
02242 return 0;
02243
02244 if (optimize_size
02245 && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl))
02246 {
02247
02248
02249 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
02250 emit_insn (gen_ashlsi3 (operands[0], operands[0],
02251 GEN_INT (num_compl_zero)));
02252 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
02253 return 1;
02254 }
02255 return 0;
02256 }
02257
02258
02259
02260
02261 static bool
02262 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
02263 {
02264 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
02265 int sz = GET_MODE_SIZE (mode);
02266 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
02267
02268
02269 unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff;
02270 return (v & ~(mask << shift)) == 0;
02271 }
02272
02273 static bool
02274 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
02275 enum rtx_code outer_code)
02276 {
02277 if (strict)
02278 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
02279 else
02280 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
02281 }
02282
02283 bool
02284 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
02285 {
02286 switch (GET_CODE (x)) {
02287 case REG:
02288 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
02289 return true;
02290 break;
02291 case PLUS:
02292 if (REG_P (XEXP (x, 0))
02293 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
02294 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
02295 || (GET_CODE (XEXP (x, 1)) == CONST_INT
02296 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
02297 return true;
02298 break;
02299 case POST_INC:
02300 case POST_DEC:
02301 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
02302 && REG_P (XEXP (x, 0))
02303 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
02304 return true;
02305 case PRE_DEC:
02306 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
02307 && XEXP (x, 0) == stack_pointer_rtx
02308 && REG_P (XEXP (x, 0))
02309 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
02310 return true;
02311 break;
02312 default:
02313 break;
02314 }
02315 return false;
02316 }
02317
02318 static bool
02319 bfin_rtx_costs (rtx x, int code, int outer_code, int *total)
02320 {
02321 int cost2 = COSTS_N_INSNS (1);
02322
02323 switch (code)
02324 {
02325 case CONST_INT:
02326 if (outer_code == SET || outer_code == PLUS)
02327 *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2;
02328 else if (outer_code == AND)
02329 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
02330 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
02331 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
02332 else if (outer_code == LEU || outer_code == LTU)
02333 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
02334 else if (outer_code == MULT)
02335 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
02336 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
02337 *total = 0;
02338 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
02339 || outer_code == LSHIFTRT)
02340 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
02341 else if (outer_code == IOR || outer_code == XOR)
02342 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
02343 else
02344 *total = cost2;
02345 return true;
02346
02347 case CONST:
02348 case LABEL_REF:
02349 case SYMBOL_REF:
02350 case CONST_DOUBLE:
02351 *total = COSTS_N_INSNS (2);
02352 return true;
02353
02354 case PLUS:
02355 if (GET_MODE (x) == Pmode)
02356 {
02357 if (GET_CODE (XEXP (x, 0)) == MULT
02358 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
02359 {
02360 HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
02361 if (val == 2 || val == 4)
02362 {
02363 *total = cost2;
02364 *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
02365 *total += rtx_cost (XEXP (x, 1), outer_code);
02366 return true;
02367 }
02368 }
02369 }
02370
02371
02372
02373 case MINUS:
02374 case ASHIFT:
02375 case ASHIFTRT:
02376 case LSHIFTRT:
02377 if (GET_MODE (x) == DImode)
02378 *total = 6 * cost2;
02379 return false;
02380
02381 case AND:
02382 case IOR:
02383 case XOR:
02384 if (GET_MODE (x) == DImode)
02385 *total = 2 * cost2;
02386 return false;
02387
02388 case MULT:
02389 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD)
02390 *total = COSTS_N_INSNS (3);
02391 return false;
02392
02393 case UDIV:
02394 case UMOD:
02395 *total = COSTS_N_INSNS (32);
02396 return true;
02397
02398 case VEC_CONCAT:
02399 case VEC_SELECT:
02400 if (outer_code == SET)
02401 *total = cost2;
02402 return true;
02403
02404 default:
02405 return false;
02406 }
02407 }
02408
02409 static void
02410 bfin_internal_label (FILE *stream, const char *prefix, unsigned long num)
02411 {
02412 fprintf (stream, "%s%s$%ld:\n", LOCAL_LABEL_PREFIX, prefix, num);
02413 }
02414
02415
02416
02417 static int first_preg_to_save, first_dreg_to_save;
02418
02419 int
02420 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
02421 {
02422 int lastdreg = 8, lastpreg = 6;
02423 int i, group;
02424
02425 first_preg_to_save = lastpreg;
02426 first_dreg_to_save = lastdreg;
02427 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
02428 {
02429 rtx t = XVECEXP (op, 0, i);
02430 rtx src, dest;
02431 int regno;
02432
02433 if (GET_CODE (t) != SET)
02434 return 0;
02435
02436 src = SET_SRC (t);
02437 dest = SET_DEST (t);
02438 if (GET_CODE (dest) != MEM || ! REG_P (src))
02439 return 0;
02440 dest = XEXP (dest, 0);
02441 if (GET_CODE (dest) != PLUS
02442 || ! REG_P (XEXP (dest, 0))
02443 || REGNO (XEXP (dest, 0)) != REG_SP
02444 || GET_CODE (XEXP (dest, 1)) != CONST_INT
02445 || INTVAL (XEXP (dest, 1)) != -i * 4)
02446 return 0;
02447
02448 regno = REGNO (src);
02449 if (group == 0)
02450 {
02451 if (D_REGNO_P (regno))
02452 {
02453 group = 1;
02454 first_dreg_to_save = lastdreg = regno - REG_R0;
02455 }
02456 else if (regno >= REG_P0 && regno <= REG_P7)
02457 {
02458 group = 2;
02459 first_preg_to_save = lastpreg = regno - REG_P0;
02460 }
02461 else
02462 return 0;
02463
02464 continue;
02465 }
02466
02467 if (group == 1)
02468 {
02469 if (regno >= REG_P0 && regno <= REG_P7)
02470 {
02471 group = 2;
02472 first_preg_to_save = lastpreg = regno - REG_P0;
02473 }
02474 else if (regno != REG_R0 + lastdreg + 1)
02475 return 0;
02476 else
02477 lastdreg++;
02478 }
02479 else if (group == 2)
02480 {
02481 if (regno != REG_P0 + lastpreg + 1)
02482 return 0;
02483 lastpreg++;
02484 }
02485 }
02486 return 1;
02487 }
02488
02489 int
02490 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
02491 {
02492 int lastdreg = 8, lastpreg = 6;
02493 int i, group;
02494
02495 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
02496 {
02497 rtx t = XVECEXP (op, 0, i);
02498 rtx src, dest;
02499 int regno;
02500
02501 if (GET_CODE (t) != SET)
02502 return 0;
02503
02504 src = SET_SRC (t);
02505 dest = SET_DEST (t);
02506 if (GET_CODE (src) != MEM || ! REG_P (dest))
02507 return 0;
02508 src = XEXP (src, 0);
02509
02510 if (i == 1)
02511 {
02512 if (! REG_P (src) || REGNO (src) != REG_SP)
02513 return 0;
02514 }
02515 else if (GET_CODE (src) != PLUS
02516 || ! REG_P (XEXP (src, 0))
02517 || REGNO (XEXP (src, 0)) != REG_SP
02518 || GET_CODE (XEXP (src, 1)) != CONST_INT
02519 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
02520 return 0;
02521
02522 regno = REGNO (dest);
02523 if (group == 0)
02524 {
02525 if (regno == REG_R7)
02526 {
02527 group = 1;
02528 lastdreg = 7;
02529 }
02530 else if (regno != REG_P0 + lastpreg - 1)
02531 return 0;
02532 else
02533 lastpreg--;
02534 }
02535 else if (group == 1)
02536 {
02537 if (regno != REG_R0 + lastdreg - 1)
02538 return 0;
02539 else
02540 lastdreg--;
02541 }
02542 }
02543 first_dreg_to_save = lastdreg;
02544 first_preg_to_save = lastpreg;
02545 return 1;
02546 }
02547
02548
02549
02550
02551 void
02552 output_push_multiple (rtx insn, rtx *operands)
02553 {
02554 char buf[80];
02555 int ok;
02556
02557
02558 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
02559 gcc_assert (ok);
02560
02561 if (first_dreg_to_save == 8)
02562 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
02563 else if (first_preg_to_save == 6)
02564 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
02565 else
02566 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
02567 first_dreg_to_save, first_preg_to_save);
02568
02569 output_asm_insn (buf, operands);
02570 }
02571
02572
02573
02574
02575 void
02576 output_pop_multiple (rtx insn, rtx *operands)
02577 {
02578 char buf[80];
02579 int ok;
02580
02581
02582 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
02583 gcc_assert (ok);
02584
02585 if (first_dreg_to_save == 8)
02586 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
02587 else if (first_preg_to_save == 6)
02588 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
02589 else
02590 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
02591 first_dreg_to_save, first_preg_to_save);
02592
02593 output_asm_insn (buf, operands);
02594 }
02595
02596
02597
02598 static void
02599 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
02600 {
02601 rtx scratch = gen_reg_rtx (mode);
02602 rtx srcmem, dstmem;
02603
02604 srcmem = adjust_address_nv (src, mode, offset);
02605 dstmem = adjust_address_nv (dst, mode, offset);
02606 emit_move_insn (scratch, srcmem);
02607 emit_move_insn (dstmem, scratch);
02608 }
02609
02610
02611
02612
02613
02614 bool
02615 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
02616 {
02617 rtx srcreg, destreg, countreg;
02618 HOST_WIDE_INT align = 0;
02619 unsigned HOST_WIDE_INT count = 0;
02620
02621 if (GET_CODE (align_exp) == CONST_INT)
02622 align = INTVAL (align_exp);
02623 if (GET_CODE (count_exp) == CONST_INT)
02624 {
02625 count = INTVAL (count_exp);
02626 #if 0
02627 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
02628 return false;
02629 #endif
02630 }
02631
02632
02633 if (optimize_size)
02634 {
02635 if (count == 2 && align < 2)
02636 return false;
02637 if (count == 4 && align < 4)
02638 return false;
02639 if (count != 1 && count != 2 && count != 4)
02640 return false;
02641 }
02642 if (align < 2 && count != 1)
02643 return false;
02644
02645 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
02646 if (destreg != XEXP (dst, 0))
02647 dst = replace_equiv_address_nv (dst, destreg);
02648 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
02649 if (srcreg != XEXP (src, 0))
02650 src = replace_equiv_address_nv (src, srcreg);
02651
02652 if (count != 0 && align >= 2)
02653 {
02654 unsigned HOST_WIDE_INT offset = 0;
02655
02656 if (align >= 4)
02657 {
02658 if ((count & ~3) == 4)
02659 {
02660 single_move_for_movmem (dst, src, SImode, offset);
02661 offset = 4;
02662 }
02663 else if (count & ~3)
02664 {
02665 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
02666 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
02667
02668 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
02669 }
02670 if (count & 2)
02671 {
02672 single_move_for_movmem (dst, src, HImode, offset);
02673 offset += 2;
02674 }
02675 }
02676 else
02677 {
02678 if ((count & ~1) == 2)
02679 {
02680 single_move_for_movmem (dst, src, HImode, offset);
02681 offset = 2;
02682 }
02683 else if (count & ~1)
02684 {
02685 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
02686 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
02687
02688 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
02689 }
02690 }
02691 if (count & 1)
02692 {
02693 single_move_for_movmem (dst, src, QImode, offset);
02694 }
02695 return true;
02696 }
02697 return false;
02698 }
02699
02700
02701 static int
02702 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
02703 {
02704 enum attr_type insn_type, dep_insn_type;
02705 int dep_insn_code_number;
02706
02707
02708 if (REG_NOTE_KIND (link) != 0)
02709 return 0;
02710
02711 dep_insn_code_number = recog_memoized (dep_insn);
02712
02713
02714 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
02715 return cost;
02716
02717 insn_type = get_attr_type (insn);
02718 dep_insn_type = get_attr_type (dep_insn);
02719
02720 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
02721 {
02722 rtx pat = PATTERN (dep_insn);
02723 rtx dest = SET_DEST (pat);
02724 rtx src = SET_SRC (pat);
02725 if (! ADDRESS_REGNO_P (REGNO (dest)) || ! D_REGNO_P (REGNO (src)))
02726 return cost;
02727 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
02728 }
02729
02730 return cost;
02731 }
02732
02733
02734
02735
02736
02737 void
02738 bfin_hardware_loop (void)
02739 {
02740 cfun->machine->has_hardware_loops++;
02741 }
02742
02743
02744 #define MAX_LOOP_DEPTH 2
02745
02746
02747 #define MAX_LOOP_LENGTH 2042
02748
02749
02750 typedef struct loop_info *loop_info;
02751 DEF_VEC_P (loop_info);
02752 DEF_VEC_ALLOC_P (loop_info,heap);
02753
02754
02755
02756 struct loop_info GTY (())
02757 {
02758
02759 int loop_no;
02760
02761
02762
02763 basic_block predecessor;
02764
02765
02766
02767 basic_block head;
02768
02769
02770 basic_block tail;
02771
02772
02773
02774 basic_block successor;
02775
02776
02777 rtx last_insn;
02778
02779
02780 rtx loop_end;
02781
02782
02783 rtx iter_reg;
02784
02785
02786 rtx init;
02787
02788
02789 rtx loop_init;
02790
02791
02792 rtx start_label;
02793
02794
02795 rtx end_label;
02796
02797
02798 int length;
02799
02800
02801 int depth;
02802
02803
02804 int bad;
02805
02806
02807 int visited;
02808
02809
02810 int clobber_loop0;
02811
02812
02813 int clobber_loop1;
02814
02815
02816 struct loop_info *next;
02817
02818
02819 struct loop_info *outer;
02820
02821
02822
02823 VEC (basic_block,heap) *blocks;
02824
02825
02826 bitmap block_bitmap;
02827
02828
02829 VEC (loop_info,heap) *loops;
02830 };
02831
02832 static void
02833 bfin_dump_loops (loop_info loops)
02834 {
02835 loop_info loop;
02836
02837 for (loop = loops; loop; loop = loop->next)
02838 {
02839 loop_info i;
02840 basic_block b;
02841 unsigned ix;
02842
02843 fprintf (dump_file, ";; loop %d: ", loop->loop_no);
02844 if (loop->bad)
02845 fprintf (dump_file, "(bad) ");
02846 fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
02847
02848 fprintf (dump_file, " blocks: [ ");
02849 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
02850 fprintf (dump_file, "%d ", b->index);
02851 fprintf (dump_file, "] ");
02852
02853 fprintf (dump_file, " inner loops: [ ");
02854 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
02855 fprintf (dump_file, "%d ", i->loop_no);
02856 fprintf (dump_file, "]\n");
02857 }
02858 fprintf (dump_file, "\n");
02859 }
02860
02861
02862
02863
02864 static bool
02865 bfin_bb_in_loop (loop_info loop, basic_block bb)
02866 {
02867 return bitmap_bit_p (loop->block_bitmap, bb->index);
02868 }
02869
02870
02871
02872
02873
02874 static bool
02875 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
02876 {
02877 unsigned ix;
02878 basic_block bb;
02879
02880 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
02881 {
02882 rtx insn;
02883
02884 for (insn = BB_HEAD (bb);
02885 insn != NEXT_INSN (BB_END (bb));
02886 insn = NEXT_INSN (insn))
02887 {
02888 if (!INSN_P (insn))
02889 continue;
02890 if (insn == loop_end)
02891 continue;
02892 if (reg_mentioned_p (reg, PATTERN (insn)))
02893 return true;
02894 }
02895 }
02896 return false;
02897 }
02898
02899
02900
02901 static void
02902 bfin_optimize_loop (loop_info loop)
02903 {
02904 basic_block bb;
02905 loop_info inner;
02906 rtx insn, init_insn, last_insn, nop_insn;
02907 rtx loop_init, start_label, end_label;
02908 rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
02909 rtx iter_reg;
02910 rtx lc_reg, lt_reg, lb_reg;
02911 rtx seq;
02912 int length;
02913 unsigned ix;
02914 int inner_depth = 0;
02915
02916 if (loop->visited)
02917 return;
02918
02919 loop->visited = 1;
02920
02921 if (loop->bad)
02922 {
02923 if (dump_file)
02924 fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
02925 goto bad_loop;
02926 }
02927
02928
02929
02930
02931 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
02932 {
02933 bfin_optimize_loop (inner);
02934
02935 if (!inner->bad && inner_depth < inner->depth)
02936 {
02937 inner_depth = inner->depth;
02938
02939 loop->clobber_loop0 |= inner->clobber_loop0;
02940 loop->clobber_loop1 |= inner->clobber_loop1;
02941 }
02942 }
02943
02944 loop->depth = inner_depth + 1;
02945 if (loop->depth > MAX_LOOP_DEPTH)
02946 {
02947 if (dump_file)
02948 fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
02949 goto bad_loop;
02950 }
02951
02952
02953 iter_reg = loop->iter_reg;
02954
02955 if (!DPREG_P (iter_reg))
02956 {
02957 if (dump_file)
02958 fprintf (dump_file, ";; loop %d iteration count NOT in PREG or DREG\n",
02959 loop->loop_no);
02960 goto bad_loop;
02961 }
02962
02963
02964
02965
02966 length = 0;
02967 for (insn = loop->start_label;
02968 insn && insn != loop->loop_end;
02969 insn = NEXT_INSN (insn))
02970 {
02971 if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
02972 {
02973 if (TARGET_CSYNC_ANOMALY)
02974 length += 8;
02975 else if (TARGET_SPECLD_ANOMALY)
02976 length += 6;
02977 }
02978 else if (LABEL_P (insn))
02979 {
02980 if (TARGET_CSYNC_ANOMALY)
02981 length += 4;
02982 }
02983
02984 if (INSN_P (insn))
02985 length += get_attr_length (insn);
02986 }
02987
02988 if (!insn)
02989 {
02990 if (dump_file)
02991 fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
02992 loop->loop_no);
02993 goto bad_loop;
02994 }
02995
02996 loop->length = length;
02997 if (loop->length > MAX_LOOP_LENGTH)
02998 {
02999 if (dump_file)
03000 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
03001 goto bad_loop;
03002 }
03003
03004
03005 if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
03006 {
03007 if (dump_file)
03008 fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
03009 goto bad_loop;
03010 }
03011
03012
03013
03014
03015 reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
03016 reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
03017 reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
03018 reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
03019 reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
03020 reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
03021
03022 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
03023 {
03024 rtx insn;
03025
03026 for (insn = BB_HEAD (bb);
03027 insn != NEXT_INSN (BB_END (bb));
03028 insn = NEXT_INSN (insn))
03029 {
03030 if (!INSN_P (insn))
03031 continue;
03032
03033 if (reg_set_p (reg_lc0, insn)
03034 || reg_set_p (reg_lt0, insn)
03035 || reg_set_p (reg_lb0, insn))
03036 loop->clobber_loop0 = 1;
03037
03038 if (reg_set_p (reg_lc1, insn)
03039 || reg_set_p (reg_lt1, insn)
03040 || reg_set_p (reg_lb1, insn))
03041 loop->clobber_loop1 |= 1;
03042 }
03043 }
03044
03045 if ((loop->clobber_loop0 && loop->clobber_loop1)
03046 || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
03047 {
03048 loop->depth = MAX_LOOP_DEPTH + 1;
03049 if (dump_file)
03050 fprintf (dump_file, ";; loop %d no loop reg available\n",
03051 loop->loop_no);
03052 goto bad_loop;
03053 }
03054
03055
03056
03057
03058
03059
03060
03061
03062
03063
03064 bb = loop->tail;
03065 last_insn = PREV_INSN (loop->loop_end);
03066
03067 while (1)
03068 {
03069 for (; last_insn != PREV_INSN (BB_HEAD (bb));
03070 last_insn = PREV_INSN (last_insn))
03071 if (INSN_P (last_insn))
03072 break;
03073
03074 if (last_insn != PREV_INSN (BB_HEAD (bb)))
03075 break;
03076
03077 if (single_pred_p (bb)
03078 && single_pred (bb) != ENTRY_BLOCK_PTR)
03079 {
03080 bb = single_pred (bb);
03081 last_insn = BB_END (bb);
03082 continue;
03083 }
03084 else
03085 {
03086 last_insn = NULL_RTX;
03087 break;
03088 }
03089 }
03090
03091 if (!last_insn)
03092 {
03093 if (dump_file)
03094 fprintf (dump_file, ";; loop %d has no last instruction\n",
03095 loop->loop_no);
03096 goto bad_loop;
03097 }
03098
03099 if (JUMP_P (last_insn))
03100 {
03101 loop_info inner = bb->aux;
03102 if (inner
03103 && inner->outer == loop
03104 && inner->loop_end == last_insn
03105 && inner->depth == 1)
03106
03107
03108 last_insn = inner->last_insn;
03109 else
03110 {
03111 if (dump_file)
03112 fprintf (dump_file, ";; loop %d has bad last instruction\n",
03113 loop->loop_no);
03114 goto bad_loop;
03115 }
03116 }
03117 else if (CALL_P (last_insn)
03118 || get_attr_type (last_insn) == TYPE_SYNC
03119 || recog_memoized (last_insn) == CODE_FOR_return_internal)
03120 {
03121 if (dump_file)
03122 fprintf (dump_file, ";; loop %d has bad last instruction\n",
03123 loop->loop_no);
03124 goto bad_loop;
03125 }
03126
03127 if (GET_CODE (PATTERN (last_insn)) == ASM_INPUT
03128 || asm_noperands (PATTERN (last_insn)) >= 0
03129 || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI)
03130 {
03131 nop_insn = emit_insn_after (gen_nop (), last_insn);
03132 last_insn = nop_insn;
03133 }
03134
03135 loop->last_insn = last_insn;
03136
03137
03138 start_label = loop->start_label;
03139 end_label = gen_label_rtx ();
03140 iter_reg = loop->iter_reg;
03141
03142 if (loop->depth == 1 && !loop->clobber_loop1)
03143 {
03144 lc_reg = reg_lc1;
03145 lt_reg = reg_lt1;
03146 lb_reg = reg_lb1;
03147 loop->clobber_loop1 = 1;
03148 }
03149 else
03150 {
03151 lc_reg = reg_lc0;
03152 lt_reg = reg_lt0;
03153 lb_reg = reg_lb0;
03154 loop->clobber_loop0 = 1;
03155 }
03156
03157
03158
03159 if (D_REGNO_P (REGNO (iter_reg)))
03160 {
03161 init_insn = gen_movsi (lc_reg, iter_reg);
03162 loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
03163 lb_reg, end_label,
03164 lc_reg);
03165 }
03166 else if (P_REGNO_P (REGNO (iter_reg)))
03167 {
03168 init_insn = NULL_RTX;
03169 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
03170 lb_reg, end_label,
03171 lc_reg, iter_reg);
03172 }
03173 else
03174 gcc_unreachable ();
03175
03176 loop->init = init_insn;
03177 loop->end_label = end_label;
03178 loop->loop_init = loop_init;
03179
03180 if (dump_file)
03181 {
03182 fprintf (dump_file, ";; replacing loop %d initializer with\n",
03183 loop->loop_no);
03184 print_rtl_single (dump_file, loop->loop_init);
03185 fprintf (dump_file, ";; replacing loop %d terminator with\n",
03186 loop->loop_no);
03187 print_rtl_single (dump_file, loop->loop_end);
03188 }
03189
03190 start_sequence ();
03191
03192 if (loop->init != NULL_RTX)
03193 emit_insn (loop->init);
03194 emit_insn(loop->loop_init);
03195 emit_label (loop->start_label);
03196
03197 seq = get_insns ();
03198 end_sequence ();
03199
03200 emit_insn_after (seq, BB_END (loop->predecessor));
03201 delete_insn (loop->loop_end);
03202
03203
03204 emit_label_before (loop->end_label, loop->last_insn);
03205
03206 return;
03207
03208 bad_loop:
03209
03210 if (dump_file)
03211 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
03212
03213 loop->bad = 1;
03214
03215 if (DPREG_P (loop->iter_reg))
03216 {
03217
03218
03219 rtx insn;
03220
03221 emit_insn_before (gen_addsi3 (loop->iter_reg,
03222 loop->iter_reg,
03223 constm1_rtx),
03224 loop->loop_end);
03225
03226 emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
03227 loop->loop_end);
03228
03229 insn = emit_jump_insn_before (gen_bne (loop->start_label),
03230 loop->loop_end);
03231
03232 JUMP_LABEL (insn) = loop->start_label;
03233 LABEL_NUSES (loop->start_label)++;
03234 delete_insn (loop->loop_end);
03235 }
03236 }
03237
03238
03239
03240
03241
03242
03243 static void
03244 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
03245 {
03246 unsigned dwork = 0;
03247 basic_block bb;
03248 VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
03249
03250 loop->tail = tail_bb;
03251 loop->head = BRANCH_EDGE (tail_bb)->dest;
03252 loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
03253 loop->predecessor = NULL;
03254 loop->loop_end = tail_insn;
03255 loop->last_insn = NULL_RTX;
03256 loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
03257 loop->depth = loop->length = 0;
03258 loop->visited = 0;
03259 loop->clobber_loop0 = loop->clobber_loop1 = 0;
03260 loop->outer = NULL;
03261 loop->loops = NULL;
03262
03263 loop->init = loop->loop_init = NULL_RTX;
03264 loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
03265 loop->end_label = NULL_RTX;
03266 loop->bad = 0;
03267
03268 VEC_safe_push (basic_block, heap, works, loop->head);
03269
03270 while (VEC_iterate (basic_block, works, dwork++, bb))
03271 {
03272 edge e;
03273 edge_iterator ei;
03274 if (bb == EXIT_BLOCK_PTR)
03275 {
03276
03277 if (dump_file)
03278 fprintf (dump_file,
03279 ";; Loop is bad - reached exit block while scanning\n");
03280 loop->bad = 1;
03281 break;
03282 }
03283
03284 if (bitmap_bit_p (loop->block_bitmap, bb->index))
03285 continue;
03286
03287
03288
03289
03290 VEC_safe_push (basic_block, heap, loop->blocks, bb);
03291 bitmap_set_bit (loop->block_bitmap, bb->index);
03292
03293 if (bb != tail_bb)
03294 {
03295 FOR_EACH_EDGE (e, ei, bb->succs)
03296 {
03297 basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
03298 if (!REGNO_REG_SET_P (succ->il.rtl->global_live_at_start,
03299 REGNO (loop->iter_reg)))
03300 continue;
03301 if (!VEC_space (basic_block, works, 1))
03302 {
03303 if (dwork)
03304 {
03305 VEC_block_remove (basic_block, works, 0, dwork);
03306 dwork = 0;
03307 }
03308 else
03309 VEC_reserve (basic_block, heap, works, 1);
03310 }
03311 VEC_quick_push (basic_block, works, succ);
03312 }
03313 }
03314 }
03315
03316 if (!loop->bad)
03317 {
03318
03319 if (EDGE_COUNT (loop->head->preds) == 2)
03320 {
03321 loop->predecessor = EDGE_PRED (loop->head, 0)->src;
03322 if (loop->predecessor == loop->tail)
03323
03324 loop->predecessor = EDGE_PRED (loop->head, 1)->src;
03325
03326
03327
03328 if (EDGE_COUNT (loop->predecessor->succs) != 1
03329 || !(EDGE_SUCC (loop->predecessor, 0)->flags & EDGE_FALLTHRU)
03330
03331
03332 || bfin_bb_in_loop (loop, loop->predecessor))
03333 loop->predecessor = NULL;
03334 }
03335
03336 if (loop->predecessor == NULL)
03337 {
03338 if (dump_file)
03339 fprintf (dump_file, ";; loop has bad predecessor\n");
03340 loop->bad = 1;
03341 }
03342 }
03343
03344 #ifdef ENABLE_CHECKING
03345
03346
03347
03348
03349 if (!loop->bad)
03350 for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
03351 {
03352 edge e;
03353 edge_iterator ei;
03354 if (bb == loop->head)
03355 continue;
03356 FOR_EACH_EDGE (e, ei, bb->preds)
03357 {
03358 basic_block pred = EDGE_PRED (bb, ei.index)->src;
03359 if (!bfin_bb_in_loop (loop, pred))
03360 abort ();
03361 }
03362 }
03363 #endif
03364 VEC_free (basic_block, heap, works);
03365 }
03366
03367 static void
03368 bfin_reorg_loops (FILE *dump_file)
03369 {
03370 bitmap_obstack stack;
03371 bitmap tmp_bitmap;
03372 basic_block bb;
03373 loop_info loops = NULL;
03374 loop_info loop;
03375 int nloops = 0;
03376
03377 bitmap_obstack_initialize (&stack);
03378
03379
03380
03381
03382 FOR_EACH_BB (bb)
03383 {
03384 rtx tail = BB_END (bb);
03385
03386 while (GET_CODE (tail) == NOTE)
03387 tail = PREV_INSN (tail);
03388
03389 bb->aux = NULL;
03390
03391 if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
03392 {
03393
03394
03395 loop = XNEW (struct loop_info);
03396 loop->next = loops;
03397 loops = loop;
03398 loop->loop_no = nloops++;
03399 loop->blocks = VEC_alloc (basic_block, heap, 20);
03400 loop->block_bitmap = BITMAP_ALLOC (&stack);
03401 bb->aux = loop;
03402
03403 if (dump_file)
03404 {
03405 fprintf (dump_file, ";; potential loop %d ending at\n",
03406 loop->loop_no);
03407 print_rtl_single (dump_file, tail);
03408 }
03409
03410 bfin_discover_loop (loop, bb, tail);
03411 }
03412 }
03413
03414 tmp_bitmap = BITMAP_ALLOC (&stack);
03415
03416 for (loop = loops; loop; loop = loop->next)
03417 {
03418 loop_info other;
03419 if (loop->bad)
03420 continue;
03421
03422 for (other = loop->next; other; other = other->next)
03423 {
03424 if (other->bad)
03425 continue;
03426
03427 bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
03428 if (bitmap_empty_p (tmp_bitmap))
03429 continue;
03430 if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
03431 {
03432 other->outer = loop;
03433 VEC_safe_push (loop_info, heap, loop->loops, other);
03434 }
03435 else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
03436 {
03437 loop->outer = other;
03438 VEC_safe_push (loop_info, heap, other->loops, loop);
03439 }
03440 else
03441 {
03442 loop->bad = other->bad = 1;
03443 }
03444 }
03445 }
03446 BITMAP_FREE (tmp_bitmap);
03447
03448 if (dump_file)
03449 {
03450 fprintf (dump_file, ";; All loops found:\n\n");
03451 bfin_dump_loops (loops);
03452 }
03453
03454
03455 for (loop = loops; loop; loop = loop->next)
03456 bfin_optimize_loop (loop);
03457
03458 if (dump_file)
03459 {
03460 fprintf (dump_file, ";; After hardware loops optimization:\n\n");
03461 bfin_dump_loops (loops);
03462 }
03463
03464
03465 while (loops)
03466 {
03467 loop = loops;
03468 loops = loop->next;
03469 VEC_free (loop_info, heap, loop->loops);
03470 VEC_free (basic_block, heap, loop->blocks);
03471 BITMAP_FREE (loop->block_bitmap);
03472 XDELETE (loop);
03473 }
03474
03475 if (dump_file)
03476 print_rtl (dump_file, get_insns ());
03477 }
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500 static void
03501 bfin_reorg (void)
03502 {
03503 rtx insn, last_condjump = NULL_RTX;
03504 int cycles_since_jump = INT_MAX;
03505
03506
03507 if (cfun->machine->has_hardware_loops)
03508 bfin_reorg_loops (dump_file);
03509
03510 if (! TARGET_SPECLD_ANOMALY && ! TARGET_CSYNC_ANOMALY)
03511 return;
03512
03513
03514
03515 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
03516 {
03517 rtx pat;
03518
03519 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
03520 continue;
03521
03522 pat = PATTERN (insn);
03523 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
03524 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
03525 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
03526 continue;
03527
03528 if (JUMP_P (insn))
03529 {
03530 if (any_condjump_p (insn)
03531 && ! cbranch_predicted_taken_p (insn))
03532 {
03533 last_condjump = insn;
03534 cycles_since_jump = 0;
03535 }
03536 else
03537 cycles_since_jump = INT_MAX;
03538 }
03539 else if (INSN_P (insn))
03540 {
03541 enum attr_type type = get_attr_type (insn);
03542 int delay_needed = 0;
03543 if (cycles_since_jump < INT_MAX)
03544 cycles_since_jump++;
03545
03546 if (type == TYPE_MCLD && TARGET_SPECLD_ANOMALY)
03547 {
03548 rtx pat = single_set (insn);
03549 if (may_trap_p (SET_SRC (pat)))
03550 delay_needed = 3;
03551 }
03552 else if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
03553 delay_needed = 4;
03554
03555 if (delay_needed > cycles_since_jump)
03556 {
03557 rtx pat;
03558 int num_clobbers;
03559 rtx *op = recog_data.operand;
03560
03561 delay_needed -= cycles_since_jump;
03562
03563 extract_insn (last_condjump);
03564 if (optimize_size)
03565 {
03566 pat = gen_cbranch_predicted_taken (op[0], op[1], op[2],
03567 op[3]);
03568 cycles_since_jump = INT_MAX;
03569 }
03570 else
03571
03572
03573
03574 pat = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
03575 GEN_INT (delay_needed));
03576 PATTERN (last_condjump) = pat;
03577 INSN_CODE (last_condjump) = recog (pat, insn, &num_clobbers);
03578 }
03579 }
03580 }
03581
03582
03583 if (! TARGET_CSYNC_ANOMALY)
03584 return;
03585
03586 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
03587 {
03588 if (JUMP_P (insn)
03589 && any_condjump_p (insn)
03590 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
03591 || cbranch_predicted_taken_p (insn)))
03592 {
03593 rtx target = JUMP_LABEL (insn);
03594 rtx label = target;
03595 cycles_since_jump = 0;
03596 for (; target && cycles_since_jump < 3; target = NEXT_INSN (target))
03597 {
03598 rtx pat;
03599
03600 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
03601 continue;
03602
03603 pat = PATTERN (target);
03604 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
03605 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
03606 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
03607 continue;
03608
03609 if (INSN_P (target))
03610 {
03611 enum attr_type type = get_attr_type (target);
03612 int delay_needed = 0;
03613 if (cycles_since_jump < INT_MAX)
03614 cycles_since_jump++;
03615
03616 if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
03617 delay_needed = 2;
03618
03619 if (delay_needed > cycles_since_jump)
03620 {
03621 rtx prev = prev_real_insn (label);
03622 delay_needed -= cycles_since_jump;
03623 if (dump_file)
03624 fprintf (dump_file, "Adding %d nops after %d\n",
03625 delay_needed, INSN_UID (label));
03626 if (JUMP_P (prev)
03627 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
03628 {
03629 rtx x;
03630 HOST_WIDE_INT v;
03631
03632 if (dump_file)
03633 fprintf (dump_file,
03634 "Reducing nops on insn %d.\n",
03635 INSN_UID (prev));
03636 x = PATTERN (prev);
03637 x = XVECEXP (x, 0, 1);
03638 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
03639 XVECEXP (x, 0, 0) = GEN_INT (v);
03640 }
03641 while (delay_needed-- > 0)
03642 emit_insn_after (gen_nop (), label);
03643 break;
03644 }
03645 }
03646 }
03647 }
03648 }
03649 }
03650
03651
03652
03653
03654 static tree
03655 handle_int_attribute (tree *node, tree name,
03656 tree args ATTRIBUTE_UNUSED,
03657 int flags ATTRIBUTE_UNUSED,
03658 bool *no_add_attrs)
03659 {
03660 tree x = *node;
03661 if (TREE_CODE (x) == FUNCTION_DECL)
03662 x = TREE_TYPE (x);
03663
03664 if (TREE_CODE (x) != FUNCTION_TYPE)
03665 {
03666 warning (OPT_Wattributes, "%qs attribute only applies to functions",
03667 IDENTIFIER_POINTER (name));
03668 *no_add_attrs = true;
03669 }
03670 else if (funkind (x) != SUBROUTINE)
03671 error ("multiple function type attributes specified");
03672
03673 return NULL_TREE;
03674 }
03675
03676
03677
03678
03679
03680 static int
03681 bfin_comp_type_attributes (tree type1, tree type2)
03682 {
03683 e_funkind kind1, kind2;
03684
03685 if (TREE_CODE (type1) != FUNCTION_TYPE)
03686 return 1;
03687
03688 kind1 = funkind (type1);
03689 kind2 = funkind (type2);
03690
03691 if (kind1 != kind2)
03692 return 0;
03693
03694
03695 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
03696 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
03697 return 0;
03698
03699 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
03700 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
03701 return 0;
03702
03703 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
03704 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
03705 return 0;
03706
03707 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
03708 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
03709 return 0;
03710
03711 return 1;
03712 }
03713
03714
03715
03716
03717 static tree
03718 bfin_handle_longcall_attribute (tree *node, tree name,
03719 tree args ATTRIBUTE_UNUSED,
03720 int flags ATTRIBUTE_UNUSED,
03721 bool *no_add_attrs)
03722 {
03723 if (TREE_CODE (*node) != FUNCTION_TYPE
03724 && TREE_CODE (*node) != FIELD_DECL
03725 && TREE_CODE (*node) != TYPE_DECL)
03726 {
03727 warning (OPT_Wattributes, "`%s' attribute only applies to functions",
03728 IDENTIFIER_POINTER (name));
03729 *no_add_attrs = true;
03730 }
03731
03732 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
03733 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
03734 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
03735 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
03736 {
03737 warning (OPT_Wattributes,
03738 "can't apply both longcall and shortcall attributes to the same function");
03739 *no_add_attrs = true;
03740 }
03741
03742 return NULL_TREE;
03743 }
03744
03745
03746 const struct attribute_spec bfin_attribute_table[] =
03747 {
03748
03749 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
03750 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
03751 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
03752 { "nesting", 0, 0, false, true, true, NULL },
03753 { "kspisusp", 0, 0, false, true, true, NULL },
03754 { "saveall", 0, 0, false, true, true, NULL },
03755 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
03756 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
03757 { NULL, 0, 0, false, false, false, NULL }
03758 };
03759
03760
03761
03762
03763
03764 static bool
03765 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
03766 {
03767 if (TARGET_FDPIC && size == UNITS_PER_WORD)
03768 {
03769 if (GET_CODE (value) == SYMBOL_REF
03770 && SYMBOL_REF_FUNCTION_P (value))
03771 {
03772 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
03773 output_addr_const (asm_out_file, value);
03774 fputs (")\n", asm_out_file);
03775 return true;
03776 }
03777 if (!aligned_p)
03778 {
03779
03780
03781 assemble_integer_with_op ("\t.4byte\t", value);
03782 return true;
03783 }
03784 }
03785 return default_assemble_integer (value, size, aligned_p);
03786 }
03787
03788
03789
03790
03791
03792
03793
03794 static void
03795 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
03796 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
03797 HOST_WIDE_INT vcall_offset, tree function)
03798 {
03799 rtx xops[3];
03800
03801 rtx this = gen_rtx_REG (Pmode, REG_R0);
03802
03803
03804 if (delta)
03805 {
03806 xops[1] = this;
03807 if (delta >= -64 && delta <= 63)
03808 {
03809 xops[0] = GEN_INT (delta);
03810 output_asm_insn ("%1 += %0;", xops);
03811 }
03812 else if (delta >= -128 && delta < -64)
03813 {
03814 xops[0] = GEN_INT (delta + 64);
03815 output_asm_insn ("%1 += -64; %1 += %0;", xops);
03816 }
03817 else if (delta > 63 && delta <= 126)
03818 {
03819 xops[0] = GEN_INT (delta - 63);
03820 output_asm_insn ("%1 += 63; %1 += %0;", xops);
03821 }
03822 else
03823 {
03824 xops[0] = GEN_INT (delta);
03825 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
03826 }
03827 }
03828
03829
03830 if (vcall_offset)
03831 {
03832 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
03833 rtx tmp = gen_rtx_REG (Pmode, REG_R2);
03834
03835 xops[1] = tmp;
03836 xops[2] = p2tmp;
03837 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
03838
03839
03840 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
03841 if (!memory_operand (xops[0], Pmode))
03842 {
03843 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
03844 xops[0] = GEN_INT (vcall_offset);
03845 xops[1] = tmp2;
03846 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
03847 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
03848 }
03849 xops[2] = this;
03850 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
03851 }
03852
03853 xops[0] = XEXP (DECL_RTL (function), 0);
03854 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
03855 output_asm_insn ("jump.l\t%P0", xops);
03856 }
03857
03858
03859 enum bfin_builtins
03860 {
03861 BFIN_BUILTIN_CSYNC,
03862 BFIN_BUILTIN_SSYNC,
03863 BFIN_BUILTIN_COMPOSE_2X16,
03864 BFIN_BUILTIN_EXTRACTLO,
03865 BFIN_BUILTIN_EXTRACTHI,
03866
03867 BFIN_BUILTIN_SSADD_2X16,
03868 BFIN_BUILTIN_SSSUB_2X16,
03869 BFIN_BUILTIN_SSADDSUB_2X16,
03870 BFIN_BUILTIN_SSSUBADD_2X16,
03871 BFIN_BUILTIN_MULT_2X16,
03872 BFIN_BUILTIN_MULTR_2X16,
03873 BFIN_BUILTIN_NEG_2X16,
03874 BFIN_BUILTIN_ABS_2X16,
03875 BFIN_BUILTIN_MIN_2X16,
03876 BFIN_BUILTIN_MAX_2X16,
03877
03878 BFIN_BUILTIN_SSADD_1X16,
03879 BFIN_BUILTIN_SSSUB_1X16,
03880 BFIN_BUILTIN_MULT_1X16,
03881 BFIN_BUILTIN_MULTR_1X16,
03882 BFIN_BUILTIN_NORM_1X16,
03883 BFIN_BUILTIN_NEG_1X16,
03884 BFIN_BUILTIN_ABS_1X16,
03885 BFIN_BUILTIN_MIN_1X16,
03886 BFIN_BUILTIN_MAX_1X16,
03887
03888 BFIN_BUILTIN_DIFFHL_2X16,
03889 BFIN_BUILTIN_DIFFLH_2X16,
03890
03891 BFIN_BUILTIN_SSADD_1X32,
03892 BFIN_BUILTIN_SSSUB_1X32,
03893 BFIN_BUILTIN_NORM_1X32,
03894 BFIN_BUILTIN_NEG_1X32,
03895 BFIN_BUILTIN_MIN_1X32,
03896 BFIN_BUILTIN_MAX_1X32,
03897 BFIN_BUILTIN_MULT_1X32,
03898
03899 BFIN_BUILTIN_MULHISILL,
03900 BFIN_BUILTIN_MULHISILH,
03901 BFIN_BUILTIN_MULHISIHL,
03902 BFIN_BUILTIN_MULHISIHH,
03903
03904 BFIN_BUILTIN_LSHIFT_1X16,
03905 BFIN_BUILTIN_LSHIFT_2X16,
03906 BFIN_BUILTIN_SSASHIFT_1X16,
03907 BFIN_BUILTIN_SSASHIFT_2X16,
03908
03909 BFIN_BUILTIN_CPLX_MUL_16,
03910 BFIN_BUILTIN_CPLX_MAC_16,
03911 BFIN_BUILTIN_CPLX_MSU_16,
03912
03913 BFIN_BUILTIN_MAX
03914 };
03915
03916 #define def_builtin(NAME, TYPE, CODE) \
03917 do { \
03918 lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
03919 NULL, NULL_TREE); \
03920 } while (0)
03921
03922
03923 static void
03924 bfin_init_builtins (void)
03925 {
03926 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
03927 tree void_ftype_void
03928 = build_function_type (void_type_node, void_list_node);
03929 tree short_ftype_short
03930 = build_function_type_list (short_integer_type_node, short_integer_type_node,
03931 NULL_TREE);
03932 tree short_ftype_int_int
03933 = build_function_type_list (short_integer_type_node, integer_type_node,
03934 integer_type_node, NULL_TREE);
03935 tree int_ftype_int_int
03936 = build_function_type_list (integer_type_node, integer_type_node,
03937 integer_type_node, NULL_TREE);
03938 tree int_ftype_int
03939 = build_function_type_list (integer_type_node, integer_type_node,
03940 NULL_TREE);
03941 tree short_ftype_int
03942 = build_function_type_list (short_integer_type_node, integer_type_node,
03943 NULL_TREE);
03944 tree int_ftype_v2hi_v2hi
03945 = build_function_type_list (integer_type_node, V2HI_type_node,
03946 V2HI_type_node, NULL_TREE);
03947 tree v2hi_ftype_v2hi_v2hi
03948 = build_function_type_list (V2HI_type_node, V2HI_type_node,
03949 V2HI_type_node, NULL_TREE);
03950 tree v2hi_ftype_v2hi_v2hi_v2hi
03951 = build_function_type_list (V2HI_type_node, V2HI_type_node,
03952 V2HI_type_node, V2HI_type_node, NULL_TREE);
03953 tree v2hi_ftype_int_int
03954 = build_function_type_list (V2HI_type_node, integer_type_node,
03955 integer_type_node, NULL_TREE);
03956 tree v2hi_ftype_v2hi_int
03957 = build_function_type_list (V2HI_type_node, V2HI_type_node,
03958 integer_type_node, NULL_TREE);
03959 tree int_ftype_short_short
03960 = build_function_type_list (integer_type_node, short_integer_type_node,
03961 short_integer_type_node, NULL_TREE);
03962 tree v2hi_ftype_v2hi
03963 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
03964 tree short_ftype_v2hi
03965 = build_function_type_list (short_integer_type_node, V2HI_type_node,
03966 NULL_TREE);
03967
03968
03969 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
03970 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
03971
03972 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
03973 BFIN_BUILTIN_COMPOSE_2X16);
03974 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
03975 BFIN_BUILTIN_EXTRACTHI);
03976 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
03977 BFIN_BUILTIN_EXTRACTLO);
03978
03979 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
03980 BFIN_BUILTIN_MIN_2X16);
03981 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
03982 BFIN_BUILTIN_MAX_2X16);
03983
03984 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
03985 BFIN_BUILTIN_SSADD_2X16);
03986 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
03987 BFIN_BUILTIN_SSSUB_2X16);
03988 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
03989 BFIN_BUILTIN_SSADDSUB_2X16);
03990 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
03991 BFIN_BUILTIN_SSSUBADD_2X16);
03992 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
03993 BFIN_BUILTIN_MULT_2X16);
03994 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
03995 BFIN_BUILTIN_MULTR_2X16);
03996 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
03997 BFIN_BUILTIN_NEG_2X16);
03998 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
03999 BFIN_BUILTIN_ABS_2X16);
04000
04001 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
04002 BFIN_BUILTIN_SSADD_1X16);
04003 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
04004 BFIN_BUILTIN_SSSUB_1X16);
04005 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
04006 BFIN_BUILTIN_MULT_1X16);
04007 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
04008 BFIN_BUILTIN_MULTR_1X16);
04009 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
04010 BFIN_BUILTIN_NEG_1X16);
04011 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
04012 BFIN_BUILTIN_ABS_1X16);
04013 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
04014 BFIN_BUILTIN_NORM_1X16);
04015
04016 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
04017 BFIN_BUILTIN_DIFFHL_2X16);
04018 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
04019 BFIN_BUILTIN_DIFFLH_2X16);
04020
04021 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
04022 BFIN_BUILTIN_MULHISILL);
04023 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
04024 BFIN_BUILTIN_MULHISIHL);
04025 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
04026 BFIN_BUILTIN_MULHISILH);
04027 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
04028 BFIN_BUILTIN_MULHISIHH);
04029
04030 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
04031 BFIN_BUILTIN_SSADD_1X32);
04032 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
04033 BFIN_BUILTIN_SSSUB_1X32);
04034 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
04035 BFIN_BUILTIN_NEG_1X32);
04036 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
04037 BFIN_BUILTIN_NORM_1X32);
04038 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
04039 BFIN_BUILTIN_MULT_1X32);
04040
04041
04042 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
04043 BFIN_BUILTIN_SSASHIFT_1X16);
04044 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
04045 BFIN_BUILTIN_SSASHIFT_2X16);
04046 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
04047 BFIN_BUILTIN_LSHIFT_1X16);
04048 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
04049 BFIN_BUILTIN_LSHIFT_2X16);
04050
04051
04052 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
04053 BFIN_BUILTIN_CPLX_MUL_16);
04054 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
04055 BFIN_BUILTIN_CPLX_MAC_16);
04056 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
04057 BFIN_BUILTIN_CPLX_MSU_16);
04058 }
04059
04060
04061 struct builtin_description
04062 {
04063 const enum insn_code icode;
04064 const char *const name;
04065 const enum bfin_builtins code;
04066 int macflag;
04067 };
04068
04069 static const struct builtin_description bdesc_2arg[] =
04070 {
04071 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
04072
04073 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
04074 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
04075 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
04076 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
04077
04078 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
04079 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
04080 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
04081 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
04082
04083 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
04084 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
04085 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
04086 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
04087
04088 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
04089 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
04090 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
04091 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
04092 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
04093 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
04094
04095 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
04096 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
04097 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
04098 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
04099 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE }
04100 };
04101
04102 static const struct builtin_description bdesc_1arg[] =
04103 {
04104 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
04105 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
04106 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
04107
04108 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
04109 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
04110
04111 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
04112 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
04113 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
04114 { CODE_FOR_absv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
04115 };
04116
04117
04118
04119
04120 static rtx
04121 safe_vector_operand (rtx x, enum machine_mode mode)
04122 {
04123 if (x != const0_rtx)
04124 return x;
04125 x = gen_reg_rtx (SImode);
04126
04127 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
04128 return gen_lowpart (mode, x);
04129 }
04130
04131
04132
04133
04134 static rtx
04135 bfin_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target,
04136 int macflag)
04137 {
04138 rtx pat;
04139 tree arg0 = TREE_VALUE (arglist);
04140 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
04141 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
04142 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
04143 enum machine_mode op0mode = GET_MODE (op0);
04144 enum machine_mode op1mode = GET_MODE (op1);
04145 enum machine_mode tmode = insn_data[icode].operand[0].mode;
04146 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
04147 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
04148
04149 if (VECTOR_MODE_P (mode0))
04150 op0 = safe_vector_operand (op0, mode0);
04151 if (VECTOR_MODE_P (mode1))
04152 op1 = safe_vector_operand (op1, mode1);
04153
04154 if (! target
04155 || GET_MODE (target) != tmode
04156 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
04157 target = gen_reg_rtx (tmode);
04158
04159 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
04160 {
04161 op0mode = HImode;
04162 op0 = gen_lowpart (HImode, op0);
04163 }
04164 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
04165 {
04166 op1mode = HImode;
04167 op1 = gen_lowpart (HImode, op1);
04168 }
04169
04170
04171 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
04172 && (op1mode == mode1 || op1mode == VOIDmode));
04173
04174 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
04175 op0 = copy_to_mode_reg (mode0, op0);
04176 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
04177 op1 = copy_to_mode_reg (mode1, op1);
04178
04179 if (macflag == -1)
04180 pat = GEN_FCN (icode) (target, op0, op1);
04181 else
04182 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
04183 if (! pat)
04184 return 0;
04185
04186 emit_insn (pat);
04187 return target;
04188 }
04189
04190
04191
04192 static rtx
04193 bfin_expand_unop_builtin (enum insn_code icode, tree arglist,
04194 rtx target)
04195 {
04196 rtx pat;
04197 tree arg0 = TREE_VALUE (arglist);
04198 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
04199 enum machine_mode op0mode = GET_MODE (op0);
04200 enum machine_mode tmode = insn_data[icode].operand[0].mode;
04201 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
04202
04203 if (! target
04204 || GET_MODE (target) != tmode
04205 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
04206 target = gen_reg_rtx (tmode);
04207
04208 if (VECTOR_MODE_P (mode0))
04209 op0 = safe_vector_operand (op0, mode0);
04210
04211 if (op0mode == SImode && mode0 == HImode)
04212 {
04213 op0mode = HImode;
04214 op0 = gen_lowpart (HImode, op0);
04215 }
04216 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
04217
04218 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
04219 op0 = copy_to_mode_reg (mode0, op0);
04220
04221 pat = GEN_FCN (icode) (target, op0);
04222 if (! pat)
04223 return 0;
04224 emit_insn (pat);
04225 return target;
04226 }
04227
04228
04229
04230
04231
04232
04233
04234 static rtx
04235 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
04236 rtx subtarget ATTRIBUTE_UNUSED,
04237 enum machine_mode mode ATTRIBUTE_UNUSED,
04238 int ignore ATTRIBUTE_UNUSED)
04239 {
04240 size_t i;
04241 enum insn_code icode;
04242 const struct builtin_description *d;
04243 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
04244 tree arglist = TREE_OPERAND (exp, 1);
04245 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
04246 tree arg0, arg1, arg2;
04247 rtx op0, op1, op2, accvec, pat, tmp1, tmp2;
04248 enum machine_mode tmode, mode0;
04249
04250 switch (fcode)
04251 {
04252 case BFIN_BUILTIN_CSYNC:
04253 emit_insn (gen_csync ());
04254 return 0;
04255 case BFIN_BUILTIN_SSYNC:
04256 emit_insn (gen_ssync ());
04257 return 0;
04258
04259 case BFIN_BUILTIN_DIFFHL_2X16:
04260 case BFIN_BUILTIN_DIFFLH_2X16:
04261 arg0 = TREE_VALUE (arglist);
04262 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
04263 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16
04264 ? CODE_FOR_subhilov2hi3 : CODE_FOR_sublohiv2hi3);
04265 tmode = insn_data[icode].operand[0].mode;
04266 mode0 = insn_data[icode].operand[1].mode;
04267
04268 if (! target
04269 || GET_MODE (target) != tmode
04270 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
04271 target = gen_reg_rtx (tmode);
04272
04273 if (VECTOR_MODE_P (mode0))
04274 op0 = safe_vector_operand (op0, mode0);
04275
04276 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
04277 op0 = copy_to_mode_reg (mode0, op0);
04278
04279 pat = GEN_FCN (icode) (target, op0, op0);
04280 if (! pat)
04281 return 0;
04282 emit_insn (pat);
04283 return target;
04284
04285 case BFIN_BUILTIN_CPLX_MUL_16:
04286 arg0 = TREE_VALUE (arglist);
04287 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
04288 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
04289 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
04290 accvec = gen_reg_rtx (V2PDImode);
04291
04292 if (! target
04293 || GET_MODE (target) != V2HImode
04294 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
04295 target = gen_reg_rtx (tmode);
04296 if (! register_operand (op0, GET_MODE (op0)))
04297 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
04298 if (! register_operand (op1, GET_MODE (op1)))
04299 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
04300
04301 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
04302 const0_rtx, const0_rtx,
04303 const1_rtx, GEN_INT (MACFLAG_NONE)));
04304 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
04305 const1_rtx, const1_rtx,
04306 const0_rtx, accvec, const1_rtx, const0_rtx,
04307 GEN_INT (MACFLAG_NONE), accvec));
04308
04309 return target;
04310
04311 case BFIN_BUILTIN_CPLX_MAC_16:
04312 case BFIN_BUILTIN_CPLX_MSU_16:
04313 arg0 = TREE_VALUE (arglist);
04314 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
04315 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
04316 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
04317 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
04318 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
04319 accvec = gen_reg_rtx (V2PDImode);
04320
04321 if (! target
04322 || GET_MODE (target) != V2HImode
04323 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
04324 target = gen_reg_rtx (tmode);
04325 if (! register_operand (op0, GET_MODE (op0)))
04326 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
04327 if (! register_operand (op1, GET_MODE (op1)))
04328 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
04329
04330 tmp1 = gen_reg_rtx (SImode);
04331 tmp2 = gen_reg_rtx (SImode);
04332 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op2), GEN_INT (16)));
04333 emit_move_insn (tmp2, gen_lowpart (SImode, op2));
04334 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
04335 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
04336 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op0, op1, const0_rtx,
04337 const0_rtx, const0_rtx,
04338 const1_rtx, accvec, const0_rtx,
04339 const0_rtx,
04340 GEN_INT (MACFLAG_W32)));
04341 tmp1 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const1_rtx : const0_rtx);
04342 tmp2 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const0_rtx : const1_rtx);
04343 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
04344 const1_rtx, const1_rtx,
04345 const0_rtx, accvec, tmp1, tmp2,
04346 GEN_INT (MACFLAG_NONE), accvec));
04347
04348 return target;
04349
04350 default:
04351 break;
04352 }
04353
04354 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
04355 if (d->code == fcode)
04356 return bfin_expand_binop_builtin (d->icode, arglist, target,
04357 d->macflag);
04358
04359 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
04360 if (d->code == fcode)
04361 return bfin_expand_unop_builtin (d->icode, arglist, target);
04362
04363 gcc_unreachable ();
04364 }
04365
04366 #undef TARGET_INIT_BUILTINS
04367 #define TARGET_INIT_BUILTINS bfin_init_builtins
04368
04369 #undef TARGET_EXPAND_BUILTIN
04370 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
04371
04372 #undef TARGET_ASM_GLOBALIZE_LABEL
04373 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
04374
04375 #undef TARGET_ASM_FILE_START
04376 #define TARGET_ASM_FILE_START output_file_start
04377
04378 #undef TARGET_ATTRIBUTE_TABLE
04379 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
04380
04381 #undef TARGET_COMP_TYPE_ATTRIBUTES
04382 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
04383
04384 #undef TARGET_RTX_COSTS
04385 #define TARGET_RTX_COSTS bfin_rtx_costs
04386
04387 #undef TARGET_ADDRESS_COST
04388 #define TARGET_ADDRESS_COST bfin_address_cost
04389
04390 #undef TARGET_ASM_INTERNAL_LABEL
04391 #define TARGET_ASM_INTERNAL_LABEL bfin_internal_label
04392
04393 #undef TARGET_ASM_INTEGER
04394 #define TARGET_ASM_INTEGER bfin_assemble_integer
04395
04396 #undef TARGET_MACHINE_DEPENDENT_REORG
04397 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
04398
04399 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
04400 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
04401
04402 #undef TARGET_ASM_OUTPUT_MI_THUNK
04403 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
04404 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
04405 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
04406
04407 #undef TARGET_SCHED_ADJUST_COST
04408 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
04409
04410 #undef TARGET_PROMOTE_PROTOTYPES
04411 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
04412 #undef TARGET_PROMOTE_FUNCTION_ARGS
04413 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
04414 #undef TARGET_PROMOTE_FUNCTION_RETURN
04415 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
04416
04417 #undef TARGET_ARG_PARTIAL_BYTES
04418 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
04419
04420 #undef TARGET_PASS_BY_REFERENCE
04421 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
04422
04423 #undef TARGET_SETUP_INCOMING_VARARGS
04424 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
04425
04426 #undef TARGET_STRUCT_VALUE_RTX
04427 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
04428
04429 #undef TARGET_VECTOR_MODE_SUPPORTED_P
04430 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
04431
04432 #undef TARGET_HANDLE_OPTION
04433 #define TARGET_HANDLE_OPTION bfin_handle_option
04434
04435 #undef TARGET_DEFAULT_TARGET_FLAGS
04436 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
04437
04438 #undef TARGET_SECONDARY_RELOAD
04439 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
04440
04441 #undef TARGET_DELEGITIMIZE_ADDRESS
04442 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
04443
04444 struct gcc_target targetm = TARGET_INITIALIZER;