00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "coretypes.h"
00025 #include "tm.h"
00026 #include <signal.h>
00027 #include "rtl.h"
00028 #include "regs.h"
00029 #include "hard-reg-set.h"
00030 #include "real.h"
00031 #include "insn-config.h"
00032 #include "conditions.h"
00033 #include "insn-attr.h"
00034 #include "recog.h"
00035 #include "toplev.h"
00036 #include "output.h"
00037 #include "tree.h"
00038 #include "function.h"
00039 #include "expr.h"
00040 #include "optabs.h"
00041 #include "flags.h"
00042 #include "reload.h"
00043 #include "tm_p.h"
00044 #include "ggc.h"
00045 #include "gstab.h"
00046 #include "hashtab.h"
00047 #include "debug.h"
00048 #include "target.h"
00049 #include "target-def.h"
00050 #include "integrate.h"
00051 #include "langhooks.h"
00052 #include "cfglayout.h"
00053 #include "score-mdaux.h"
00054
00055 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
00056 #define INS_BUF_SZ 100
00057
00058
00059
00060 rtx cmp_op0, cmp_op1;
00061
00062 static char ins[INS_BUF_SZ + 8];
00063
00064
00065
00066 static int
00067 score_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
00068 {
00069 if (GET_CODE (symbol) != SYMBOL_REF)
00070 return 0;
00071
00072 if (CONSTANT_POOL_ADDRESS_P (symbol)
00073 && offset >= 0
00074 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
00075 return 1;
00076
00077 if (SYMBOL_REF_DECL (symbol) != 0
00078 && offset >= 0
00079 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
00080 return 1;
00081
00082 return 0;
00083 }
00084
00085
00086
00087 static void
00088 score_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
00089 {
00090 *offset = 0;
00091
00092 if (GET_CODE (x) == CONST)
00093 x = XEXP (x, 0);
00094
00095 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
00096 {
00097 *offset += INTVAL (XEXP (x, 1));
00098 x = XEXP (x, 0);
00099 }
00100
00101 *base = x;
00102 }
00103
00104
00105 static enum
00106 score_symbol_type score_classify_symbol (rtx x)
00107 {
00108 if (GET_CODE (x) == LABEL_REF)
00109 return SYMBOL_GENERAL;
00110
00111 gcc_assert (GET_CODE (x) == SYMBOL_REF);
00112
00113 if (CONSTANT_POOL_ADDRESS_P (x))
00114 {
00115 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
00116 return SYMBOL_SMALL_DATA;
00117 return SYMBOL_GENERAL;
00118 }
00119 if (SYMBOL_REF_SMALL_P (x))
00120 return SYMBOL_SMALL_DATA;
00121 return SYMBOL_GENERAL;
00122 }
00123
00124
00125 static int
00126 score_save_reg_p (unsigned int regno)
00127 {
00128
00129 if (regs_ever_live[regno] && !call_used_regs[regno])
00130 return 1;
00131
00132
00133 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
00134 return 1;
00135
00136
00137
00138 if (regno == RA_REGNUM && regs_ever_live[regno])
00139 return 1;
00140
00141 return 0;
00142 }
00143
00144
00145
00146
00147 static rtx
00148 subw (rtx op, int high_p)
00149 {
00150 unsigned int byte;
00151 enum machine_mode mode = GET_MODE (op);
00152
00153 if (mode == VOIDmode)
00154 mode = DImode;
00155
00156 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
00157
00158 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
00159 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
00160
00161 if (GET_CODE (op) == MEM)
00162 return adjust_address (op, SImode, byte);
00163
00164 return simplify_gen_subreg (SImode, op, mode, byte);
00165 }
00166
00167 struct score_frame_info *
00168 mda_cached_frame (void)
00169 {
00170 static struct score_frame_info _frame_info;
00171 return &_frame_info;
00172 }
00173
00174
00175
00176 struct score_frame_info *
00177 mda_compute_frame_size (HOST_WIDE_INT size)
00178 {
00179 unsigned int regno;
00180 struct score_frame_info *f = mda_cached_frame ();
00181
00182 memset (f, 0, sizeof (struct score_frame_info));
00183 f->gp_reg_size = 0;
00184 f->mask = 0;
00185 f->var_size = SCORE_STACK_ALIGN (size);
00186 f->args_size = current_function_outgoing_args_size;
00187 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
00188 if (f->var_size == 0 && current_function_is_leaf)
00189 f->args_size = f->cprestore_size = 0;
00190
00191 if (f->args_size == 0 && current_function_calls_alloca)
00192 f->args_size = UNITS_PER_WORD;
00193
00194 f->total_size = f->var_size + f->args_size + f->cprestore_size;
00195 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
00196 {
00197 if (score_save_reg_p (regno))
00198 {
00199 f->gp_reg_size += GET_MODE_SIZE (SImode);
00200 f->mask |= 1 << (regno - GP_REG_FIRST);
00201 }
00202 }
00203
00204 if (current_function_calls_eh_return)
00205 {
00206 unsigned int i;
00207 for (i = 0;; ++i)
00208 {
00209 regno = EH_RETURN_DATA_REGNO (i);
00210 if (regno == INVALID_REGNUM)
00211 break;
00212 f->gp_reg_size += GET_MODE_SIZE (SImode);
00213 f->mask |= 1 << (regno - GP_REG_FIRST);
00214 }
00215 }
00216
00217 f->total_size += f->gp_reg_size;
00218 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
00219
00220 if (f->mask)
00221 {
00222 HOST_WIDE_INT offset;
00223 offset = (f->args_size + f->cprestore_size + f->var_size
00224 + f->gp_reg_size - GET_MODE_SIZE (SImode));
00225 f->gp_sp_offset = offset;
00226 }
00227 else
00228 f->gp_sp_offset = 0;
00229
00230 return f;
00231 }
00232
00233
00234 void
00235 mdx_prologue (void)
00236 {
00237 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
00238
00239 struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
00240 HOST_WIDE_INT size;
00241 int regno;
00242
00243 size = f->total_size - f->gp_reg_size;
00244
00245 if (flag_pic)
00246 emit_insn (gen_cpload ());
00247
00248 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
00249 {
00250 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
00251 {
00252 rtx mem = gen_rtx_MEM (SImode,
00253 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
00254 rtx reg = gen_rtx_REG (SImode, regno);
00255 if (!current_function_calls_eh_return)
00256 MEM_READONLY_P (mem) = 1;
00257 EMIT_PL (emit_insn (gen_pushsi (mem, reg)));
00258 }
00259 }
00260
00261 if (size > 0)
00262 {
00263 rtx insn;
00264
00265 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
00266 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
00267 stack_pointer_rtx,
00268 GEN_INT (-size))));
00269 else
00270 {
00271 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, PROLOGUE_TEMP_REGNUM),
00272 GEN_INT (size)));
00273 EMIT_PL (emit_insn
00274 (gen_sub3_insn (stack_pointer_rtx,
00275 stack_pointer_rtx,
00276 gen_rtx_REG (Pmode,
00277 PROLOGUE_TEMP_REGNUM))));
00278 }
00279 insn = get_last_insn ();
00280 REG_NOTES (insn) =
00281 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
00282 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
00283 plus_constant (stack_pointer_rtx,
00284 -size)),
00285 REG_NOTES (insn));
00286 }
00287
00288 if (frame_pointer_needed)
00289 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
00290
00291 if (flag_pic && f->cprestore_size)
00292 {
00293 if (frame_pointer_needed)
00294 emit_insn (gen_cprestore_use_fp (GEN_INT (size - f->cprestore_size)));
00295 else
00296 emit_insn (gen_cprestore_use_sp (GEN_INT (size - f->cprestore_size)));
00297 }
00298
00299 #undef EMIT_PL
00300 }
00301
00302
00303 void
00304 mdx_epilogue (int sibcall_p)
00305 {
00306 struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
00307 HOST_WIDE_INT size;
00308 int regno;
00309 rtx base;
00310
00311 size = f->total_size - f->gp_reg_size;
00312
00313 if (!frame_pointer_needed)
00314 base = stack_pointer_rtx;
00315 else
00316 base = hard_frame_pointer_rtx;
00317
00318 if (size)
00319 {
00320 if (CONST_OK_FOR_LETTER_P (size, 'L'))
00321 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
00322 else
00323 {
00324 emit_move_insn (gen_rtx_REG (Pmode, EPILOGUE_TEMP_REGNUM),
00325 GEN_INT (size));
00326 emit_insn (gen_add3_insn (base, base,
00327 gen_rtx_REG (Pmode,
00328 EPILOGUE_TEMP_REGNUM)));
00329 }
00330 }
00331
00332 if (base != stack_pointer_rtx)
00333 emit_move_insn (stack_pointer_rtx, base);
00334
00335 if (current_function_calls_eh_return)
00336 emit_insn (gen_add3_insn (stack_pointer_rtx,
00337 stack_pointer_rtx,
00338 EH_RETURN_STACKADJ_RTX));
00339
00340 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
00341 {
00342 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
00343 {
00344 rtx mem = gen_rtx_MEM (SImode,
00345 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
00346 rtx reg = gen_rtx_REG (SImode, regno);
00347
00348 if (!current_function_calls_eh_return)
00349 MEM_READONLY_P (mem) = 1;
00350
00351 emit_insn (gen_popsi (reg, mem));
00352 }
00353 }
00354
00355 if (!sibcall_p)
00356 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, RA_REGNUM)));
00357 }
00358
00359
00360
00361 int
00362 mda_valid_base_register_p (rtx x, int strict)
00363 {
00364 if (!strict && GET_CODE (x) == SUBREG)
00365 x = SUBREG_REG (x);
00366
00367 return (GET_CODE (x) == REG
00368 && score_regno_mode_ok_for_base_p (REGNO (x), strict));
00369 }
00370
00371
00372
00373
00374 int
00375 mda_classify_address (struct score_address_info *info,
00376 enum machine_mode mode, rtx x, int strict)
00377 {
00378 info->code = GET_CODE (x);
00379
00380 switch (info->code)
00381 {
00382 case REG:
00383 case SUBREG:
00384 info->type = ADD_REG;
00385 info->reg = x;
00386 info->offset = const0_rtx;
00387 return mda_valid_base_register_p (info->reg, strict);
00388 case PLUS:
00389 info->type = ADD_REG;
00390 info->reg = XEXP (x, 0);
00391 info->offset = XEXP (x, 1);
00392 return (mda_valid_base_register_p (info->reg, strict)
00393 && GET_CODE (info->offset) == CONST_INT
00394 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
00395 case PRE_DEC:
00396 case POST_DEC:
00397 case PRE_INC:
00398 case POST_INC:
00399 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
00400 return false;
00401 info->type = ADD_REG;
00402 info->reg = XEXP (x, 0);
00403 info->offset = GEN_INT (GET_MODE_SIZE (mode));
00404 return mda_valid_base_register_p (info->reg, strict);
00405 case CONST_INT:
00406 info->type = ADD_CONST_INT;
00407 return IMM_IN_RANGE (INTVAL (x), 15, 1);
00408 case CONST:
00409 case LABEL_REF:
00410 case SYMBOL_REF:
00411 info->type = ADD_SYMBOLIC;
00412 return (mda_symbolic_constant_p (x, &info->symbol_type)
00413 && (info->symbol_type == SYMBOL_GENERAL
00414 || info->symbol_type == SYMBOL_SMALL_DATA));
00415 default:
00416 return 0;
00417 }
00418 }
00419
00420 void
00421 mda_gen_cmp (enum machine_mode mode)
00422 {
00423 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
00424 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
00425 }
00426
00427
00428
00429
00430 int
00431 mda_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
00432 {
00433 HOST_WIDE_INT offset;
00434
00435 score_split_const (x, &x, &offset);
00436 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
00437 *symbol_type = score_classify_symbol (x);
00438 else
00439 return 0;
00440
00441 if (offset == 0)
00442 return 1;
00443
00444
00445 if (!IMM_IN_RANGE (offset, 15, 1))
00446 return 0;
00447
00448 switch (*symbol_type)
00449 {
00450 case SYMBOL_GENERAL:
00451 return 1;
00452 case SYMBOL_SMALL_DATA:
00453 return score_offset_within_object_p (x, offset);
00454 }
00455 gcc_unreachable ();
00456 }
00457
00458 void
00459 mdx_movsicc (rtx *ops)
00460 {
00461 enum machine_mode mode;
00462
00463 mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
00464 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
00465 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
00466 }
00467
00468
00469 void
00470 mdx_call (rtx *ops, bool sib)
00471 {
00472 rtx addr = XEXP (ops[0], 0);
00473 if (!call_insn_operand (addr, VOIDmode))
00474 {
00475 rtx oaddr = addr;
00476 addr = gen_reg_rtx (Pmode);
00477 gen_move_insn (addr, oaddr);
00478 }
00479
00480 if (sib)
00481 emit_call_insn (gen_sibcall_internal (addr, ops[1]));
00482 else
00483 emit_call_insn (gen_call_internal (addr, ops[1]));
00484 }
00485
00486
00487 void
00488 mdx_call_value (rtx *ops, bool sib)
00489 {
00490 rtx result = ops[0];
00491 rtx addr = XEXP (ops[1], 0);
00492 rtx arg = ops[2];
00493
00494 if (!call_insn_operand (addr, VOIDmode))
00495 {
00496 rtx oaddr = addr;
00497 addr = gen_reg_rtx (Pmode);
00498 gen_move_insn (addr, oaddr);
00499 }
00500
00501 if (sib)
00502 emit_call_insn (gen_sibcall_value_internal (result, addr, arg));
00503 else
00504 emit_call_insn (gen_call_value_internal (result, addr, arg));
00505 }
00506
00507
00508 void
00509 mds_movdi (rtx *ops)
00510 {
00511 rtx dst = ops[0];
00512 rtx src = ops[1];
00513 rtx dst0 = subw (dst, 0);
00514 rtx dst1 = subw (dst, 1);
00515 rtx src0 = subw (src, 0);
00516 rtx src1 = subw (src, 1);
00517
00518 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
00519 {
00520 emit_move_insn (dst1, src1);
00521 emit_move_insn (dst0, src0);
00522 }
00523 else
00524 {
00525 emit_move_insn (dst0, src0);
00526 emit_move_insn (dst1, src1);
00527 }
00528 }
00529
00530 void
00531 mds_zero_extract_andi (rtx *ops)
00532 {
00533 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
00534 emit_insn (gen_zero_extract_bittst (ops[0], ops[2]));
00535 else
00536 {
00537 unsigned HOST_WIDE_INT mask;
00538 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
00539 mask = mask << INTVAL (ops[2]);
00540 emit_insn (gen_andsi3_cmp (ops[3], ops[0],
00541 gen_int_mode (mask, SImode)));
00542 }
00543 }
00544
00545
00546 static bool
00547 mda_pindex_mem (rtx addr)
00548 {
00549 if (GET_CODE (addr) == MEM)
00550 {
00551 switch (GET_CODE (XEXP (addr, 0)))
00552 {
00553 case PRE_DEC:
00554 case POST_DEC:
00555 case PRE_INC:
00556 case POST_INC:
00557 return true;
00558 default:
00559 break;
00560 }
00561 }
00562 return false;
00563 }
00564
00565
00566 static int
00567 pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum mda_mem_unit unit)
00568 {
00569 struct score_address_info ai;
00570
00571 gcc_assert (GET_CODE (ops[idata]) == REG);
00572 gcc_assert (mda_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
00573
00574 if (!mda_pindex_mem (ops[iaddr])
00575 && ai.type == ADD_REG
00576 && GET_CODE (ai.offset) == CONST_INT
00577 && G16_REG_P (REGNO (ops[idata]))
00578 && G16_REG_P (REGNO (ai.reg)))
00579 {
00580 if (INTVAL (ai.offset) == 0)
00581 {
00582 ops[iaddr] = ai.reg;
00583 return snprintf (ip, INS_BUF_SZ,
00584 "! %%%d, [%%%d]", idata, iaddr);
00585 }
00586 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
00587 {
00588 HOST_WIDE_INT offset = INTVAL (ai.offset);
00589 if (MDA_ALIGN_UNIT (offset, unit)
00590 && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
00591 {
00592 ops[iaddr] = ai.offset;
00593 return snprintf (ip, INS_BUF_SZ,
00594 "p! %%%d, %%c%d", idata, iaddr);
00595 }
00596 }
00597 }
00598 return snprintf (ip, INS_BUF_SZ, " %%%d, %%a%d", idata, iaddr);
00599 }
00600
00601
00602 const char *
00603 mdp_linsn (rtx *ops, enum mda_mem_unit unit, bool sign)
00604 {
00605 const char *pre_ins[] =
00606 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
00607 char *ip;
00608
00609 strcpy (ins, pre_ins[(sign ? 4 : 0) + unit]);
00610 ip = ins + strlen (ins);
00611
00612 if ((!sign && unit != MDA_HWORD)
00613 || (sign && unit != MDA_BYTE))
00614 pr_addr_post (ops, 0, 1, ip, unit);
00615 else
00616 snprintf (ip, INS_BUF_SZ, " %%0, %%a1");
00617
00618 return ins;
00619 }
00620
00621
00622 const char *
00623 mdp_sinsn (rtx *ops, enum mda_mem_unit unit)
00624 {
00625 const char *pre_ins[] = {"sb", "sh", "sw"};
00626 char *ip;
00627
00628 strcpy (ins, pre_ins[unit]);
00629 ip = ins + strlen (ins);
00630 pr_addr_post (ops, 1, 0, ip, unit);
00631 return ins;
00632 }
00633
00634
00635 const char *
00636 mdp_limm (rtx *ops)
00637 {
00638 HOST_WIDE_INT v;
00639
00640 gcc_assert (GET_CODE (ops[0]) == REG);
00641 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
00642
00643 v = INTVAL (ops[1]);
00644 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
00645 return "ldiu! %0, %c1";
00646 else if (IMM_IN_RANGE (v, 16, 1))
00647 return "ldi %0, %c1";
00648 else if ((v & 0xffff) == 0)
00649 return "ldis %0, %U1";
00650 else
00651 return "li %0, %c1";
00652 }
00653
00654
00655 const char *
00656 mdp_move (rtx *ops)
00657 {
00658 gcc_assert (GET_CODE (ops[0]) == REG);
00659 gcc_assert (GET_CODE (ops[1]) == REG);
00660
00661 if (G16_REG_P (REGNO (ops[0])))
00662 {
00663 if (G16_REG_P (REGNO (ops[1])))
00664 return "mv! %0, %1";
00665 else
00666 return "mlfh! %0, %1";
00667 }
00668 else if (G16_REG_P (REGNO (ops[1])))
00669 return "mhfl! %0, %1";
00670 else
00671 return "mv %0, %1";
00672 }
00673
00674
00675 bool
00676 mdx_unaligned_load (rtx *ops)
00677 {
00678 rtx dst = ops[0];
00679 rtx src = ops[1];
00680 rtx len = ops[2];
00681 rtx off = ops[3];
00682 rtx addr_reg;
00683
00684 if (INTVAL (len) != BITS_PER_WORD
00685 || (INTVAL (off) % BITS_PER_UNIT) != 0)
00686 return false;
00687
00688 gcc_assert (GET_MODE_SIZE (GET_MODE (dst)) == GET_MODE_SIZE (SImode));
00689
00690 addr_reg = copy_addr_to_reg (XEXP (src, 0));
00691 emit_insn (gen_move_lcb (addr_reg, addr_reg));
00692 emit_insn (gen_move_lce (addr_reg, addr_reg, dst));
00693
00694 return true;
00695 }
00696
00697
00698 bool
00699 mdx_unaligned_store (rtx *ops)
00700 {
00701 rtx dst = ops[0];
00702 rtx len = ops[1];
00703 rtx off = ops[2];
00704 rtx src = ops[3];
00705 rtx addr_reg;
00706
00707 if (INTVAL(len) != BITS_PER_WORD
00708 || (INTVAL(off) % BITS_PER_UNIT) != 0)
00709 return false;
00710
00711 gcc_assert (GET_MODE_SIZE (GET_MODE (src)) == GET_MODE_SIZE (SImode));
00712
00713 addr_reg = copy_addr_to_reg (XEXP (dst, 0));
00714 emit_insn (gen_move_scb (addr_reg, addr_reg, src));
00715 emit_insn (gen_move_sce (addr_reg, addr_reg));
00716
00717 return true;
00718 }
00719
00720
00721 static void
00722 mdx_block_move_straight (rtx dst, rtx src, HOST_WIDE_INT length)
00723 {
00724 HOST_WIDE_INT leftover;
00725 int i, reg_count;
00726 rtx *regs;
00727
00728 leftover = length % UNITS_PER_WORD;
00729 length -= leftover;
00730 reg_count = length / UNITS_PER_WORD;
00731
00732 regs = alloca (sizeof (rtx) * reg_count);
00733 for (i = 0; i < reg_count; i++)
00734 regs[i] = gen_reg_rtx (SImode);
00735
00736
00737 if (MEM_ALIGN (src) >= BITS_PER_WORD)
00738 {
00739 HOST_WIDE_INT offset = 0;
00740 for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
00741 emit_move_insn (regs[i], adjust_address (src, SImode, offset));
00742 }
00743 else if (reg_count >= 1)
00744 {
00745 rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
00746
00747 emit_insn (gen_move_lcb (src_reg, src_reg));
00748 for (i = 0; i < (reg_count - 1); i++)
00749 emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
00750 emit_insn (gen_move_lce (src_reg, src_reg, regs[i]));
00751 }
00752
00753
00754 if (MEM_ALIGN (dst) >= BITS_PER_WORD)
00755 {
00756 HOST_WIDE_INT offset = 0;
00757 for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
00758 emit_move_insn (adjust_address (dst, SImode, offset), regs[i]);
00759 }
00760 else if (reg_count >= 1)
00761 {
00762 rtx dst_reg = copy_addr_to_reg (XEXP (dst, 0));
00763
00764 emit_insn (gen_move_scb (dst_reg, dst_reg, regs[0]));
00765 for (i = 1; i < reg_count; i++)
00766 emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
00767 emit_insn (gen_move_sce (dst_reg, dst_reg));
00768 }
00769
00770
00771 if (leftover > 0)
00772 {
00773 src = adjust_address (src, BLKmode, length);
00774 dst = adjust_address (dst, BLKmode, length);
00775 move_by_pieces (dst, src, leftover,
00776 MIN (MEM_ALIGN (src), MEM_ALIGN (dst)), 0);
00777 }
00778 }
00779
00780
00781 static void
00782 mdx_block_move_loop_head (rtx dst_reg, HOST_WIDE_INT dst_align,
00783 rtx src_reg, HOST_WIDE_INT src_align,
00784 HOST_WIDE_INT length)
00785 {
00786 bool src_unaligned = (src_align < BITS_PER_WORD);
00787 bool dst_unaligned = (dst_align < BITS_PER_WORD);
00788
00789 rtx temp = gen_reg_rtx (SImode);
00790
00791 gcc_assert (length == UNITS_PER_WORD);
00792
00793 if (src_unaligned)
00794 {
00795 emit_insn (gen_move_lcb (src_reg, src_reg));
00796 emit_insn (gen_move_lcw (src_reg, src_reg, temp));
00797 }
00798 else
00799 emit_insn (gen_move_lw_a (src_reg,
00800 src_reg, gen_int_mode (4, SImode), temp));
00801
00802 if (dst_unaligned)
00803 emit_insn (gen_move_scb (dst_reg, dst_reg, temp));
00804 else
00805 emit_insn (gen_move_sw_a (dst_reg,
00806 dst_reg, gen_int_mode (4, SImode), temp));
00807 }
00808
00809
00810 static void
00811 mdx_block_move_loop_body (rtx dst_reg, HOST_WIDE_INT dst_align,
00812 rtx src_reg, HOST_WIDE_INT src_align,
00813 HOST_WIDE_INT length)
00814 {
00815 int reg_count = length / UNITS_PER_WORD;
00816 rtx *regs = alloca (sizeof (rtx) * reg_count);
00817 int i;
00818 bool src_unaligned = (src_align < BITS_PER_WORD);
00819 bool dst_unaligned = (dst_align < BITS_PER_WORD);
00820
00821 for (i = 0; i < reg_count; i++)
00822 regs[i] = gen_reg_rtx (SImode);
00823
00824 if (src_unaligned)
00825 {
00826 for (i = 0; i < reg_count; i++)
00827 emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
00828 }
00829 else
00830 {
00831 for (i = 0; i < reg_count; i++)
00832 emit_insn (gen_move_lw_a (src_reg,
00833 src_reg, gen_int_mode (4, SImode), regs[i]));
00834 }
00835
00836 if (dst_unaligned)
00837 {
00838 for (i = 0; i < reg_count; i++)
00839 emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
00840 }
00841 else
00842 {
00843 for (i = 0; i < reg_count; i++)
00844 emit_insn (gen_move_sw_a (dst_reg,
00845 dst_reg, gen_int_mode (4, SImode), regs[i]));
00846 }
00847 }
00848
00849
00850 static void
00851 mdx_block_move_loop_foot (rtx dst_reg, HOST_WIDE_INT dst_align,
00852 rtx src_reg, HOST_WIDE_INT src_align,
00853 HOST_WIDE_INT length)
00854 {
00855 bool src_unaligned = (src_align < BITS_PER_WORD);
00856 bool dst_unaligned = (dst_align < BITS_PER_WORD);
00857
00858 HOST_WIDE_INT leftover;
00859
00860 leftover = length % UNITS_PER_WORD;
00861 length -= leftover;
00862
00863 if (length > 0)
00864 mdx_block_move_loop_body (dst_reg, dst_align,
00865 src_reg, src_align, length);
00866
00867 if (dst_unaligned)
00868 emit_insn (gen_move_sce (dst_reg, dst_reg));
00869
00870 if (leftover > 0)
00871 {
00872 HOST_WIDE_INT src_adj = src_unaligned ? -4 : 0;
00873 HOST_WIDE_INT dst_adj = dst_unaligned ? -4 : 0;
00874 rtx temp;
00875
00876 gcc_assert (leftover < UNITS_PER_WORD);
00877
00878 if (leftover >= UNITS_PER_WORD / 2
00879 && src_align >= BITS_PER_WORD / 2
00880 && dst_align >= BITS_PER_WORD / 2)
00881 {
00882 temp = gen_reg_rtx (HImode);
00883 emit_insn (gen_move_lhu_b (src_reg, src_reg,
00884 gen_int_mode (src_adj, SImode), temp));
00885 emit_insn (gen_move_sh_b (dst_reg, dst_reg,
00886 gen_int_mode (dst_adj, SImode), temp));
00887 leftover -= UNITS_PER_WORD / 2;
00888 src_adj = UNITS_PER_WORD / 2;
00889 dst_adj = UNITS_PER_WORD / 2;
00890 }
00891
00892 while (leftover > 0)
00893 {
00894 temp = gen_reg_rtx (QImode);
00895 emit_insn (gen_move_lbu_b (src_reg, src_reg,
00896 gen_int_mode (src_adj, SImode), temp));
00897 emit_insn (gen_move_sb_b (dst_reg, dst_reg,
00898 gen_int_mode (dst_adj, SImode), temp));
00899 leftover--;
00900 src_adj = 1;
00901 dst_adj = 1;
00902 }
00903 }
00904 }
00905
00906 #define MIN_MOVE_REGS 3
00907 #define MIN_MOVE_BYTES (MIN_MOVE_REGS * UNITS_PER_WORD)
00908 #define MAX_MOVE_REGS 4
00909 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
00910
00911
00912
00913 static void
00914 mdx_block_move_loop (rtx dst, rtx src, HOST_WIDE_INT length)
00915 {
00916 HOST_WIDE_INT src_align = MEM_ALIGN (src);
00917 HOST_WIDE_INT dst_align = MEM_ALIGN (dst);
00918 HOST_WIDE_INT loop_mov_bytes;
00919 HOST_WIDE_INT iteration = 0;
00920 HOST_WIDE_INT head_length = 0, leftover;
00921 rtx label, src_reg, dst_reg, final_dst;
00922
00923 bool gen_loop_head = (src_align < BITS_PER_WORD
00924 || dst_align < BITS_PER_WORD);
00925
00926 if (gen_loop_head)
00927 head_length += UNITS_PER_WORD;
00928
00929 for (loop_mov_bytes = MAX_MOVE_BYTES;
00930 loop_mov_bytes >= MIN_MOVE_BYTES;
00931 loop_mov_bytes -= UNITS_PER_WORD)
00932 {
00933 iteration = (length - head_length) / loop_mov_bytes;
00934 if (iteration > 1)
00935 break;
00936 }
00937 if (iteration <= 1)
00938 {
00939 mdx_block_move_straight (dst, src, length);
00940 return;
00941 }
00942
00943 leftover = (length - head_length) % loop_mov_bytes;
00944 length -= leftover;
00945
00946 src_reg = copy_addr_to_reg (XEXP (src, 0));
00947 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
00948 final_dst = expand_simple_binop (Pmode, PLUS, dst_reg, GEN_INT (length),
00949 0, 0, OPTAB_WIDEN);
00950
00951 if (gen_loop_head)
00952 mdx_block_move_loop_head (dst_reg, dst_align,
00953 src_reg, src_align, head_length);
00954
00955 label = gen_label_rtx ();
00956 emit_label (label);
00957
00958 mdx_block_move_loop_body (dst_reg, dst_align,
00959 src_reg, src_align, loop_mov_bytes);
00960
00961 emit_insn (gen_cmpsi (dst_reg, final_dst));
00962 emit_jump_insn (gen_bne (label));
00963
00964 mdx_block_move_loop_foot (dst_reg, dst_align,
00965 src_reg, src_align, leftover);
00966 }
00967
00968
00969 bool
00970 mdx_block_move (rtx *ops)
00971 {
00972 rtx dst = ops[0];
00973 rtx src = ops[1];
00974 rtx length = ops[2];
00975
00976 if (TARGET_LITTLE_ENDIAN
00977 && (MEM_ALIGN (src) < BITS_PER_WORD || MEM_ALIGN (dst) < BITS_PER_WORD)
00978 && INTVAL (length) >= UNITS_PER_WORD)
00979 return false;
00980
00981 if (GET_CODE (length) == CONST_INT)
00982 {
00983 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
00984 {
00985 mdx_block_move_straight (dst, src, INTVAL (length));
00986 return true;
00987 }
00988 else if (optimize &&
00989 !(flag_unroll_loops || flag_unroll_all_loops))
00990 {
00991 mdx_block_move_loop (dst, src, INTVAL (length));
00992 return true;
00993 }
00994 }
00995 return false;
00996 }
00997
00998
00999 const char *
01000 mdp_select_add_imm (rtx *ops, bool set_cc)
01001 {
01002 HOST_WIDE_INT v = INTVAL (ops[2]);
01003
01004 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
01005 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
01006
01007 if (set_cc && G16_REG_P (REGNO (ops[0])))
01008 {
01009 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
01010 {
01011 ops[2] = GEN_INT (ffs (v) - 1);
01012 return "addei! %0, %c2";
01013 }
01014
01015 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
01016 {
01017 ops[2] = GEN_INT (ffs (-v) - 1);
01018 return "subei! %0, %c2";
01019 }
01020 }
01021
01022 if (set_cc)
01023 return "addi.c %0, %c2";
01024 else
01025 return "addi %0, %c2";
01026 }
01027
01028
01029 const char *
01030 mdp_select (rtx *ops, const char *inst_pre,
01031 bool commu, const char *letter, bool set_cc)
01032 {
01033 gcc_assert (GET_CODE (ops[0]) == REG);
01034 gcc_assert (GET_CODE (ops[1]) == REG);
01035
01036 if (set_cc && G16_REG_P (REGNO (ops[0]))
01037 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
01038 && REGNO (ops[0]) == REGNO (ops[1]))
01039 {
01040 snprintf (ins, INS_BUF_SZ, "%s! %%0, %%%s2", inst_pre, letter);
01041 return ins;
01042 }
01043
01044 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
01045 && G16_REG_P (REGNO (ops[1]))
01046 && REGNO (ops[0]) == REGNO (ops[2]))
01047 {
01048 gcc_assert (GET_CODE (ops[2]) == REG);
01049 snprintf (ins, INS_BUF_SZ, "%s! %%0, %%%s1", inst_pre, letter);
01050 return ins;
01051 }
01052
01053 if (set_cc)
01054 snprintf (ins, INS_BUF_SZ, "%s.c %%0, %%1, %%%s2", inst_pre, letter);
01055 else
01056 snprintf (ins, INS_BUF_SZ, "%s %%0, %%1, %%%s2", inst_pre, letter);
01057 return ins;
01058 }
01059