00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "config.h"
00027 #include "system.h"
00028 #include "coretypes.h"
00029 #include "tm.h"
00030 #include "rtl.h"
00031 #include "tree.h"
00032 #include "tm_p.h"
00033 #include "regs.h"
00034 #include "hard-reg-set.h"
00035 #include "real.h"
00036 #include "insn-config.h"
00037 #include "conditions.h"
00038 #include "output.h"
00039 #include "insn-codes.h"
00040 #include "insn-attr.h"
00041 #include "flags.h"
00042 #include "except.h"
00043 #include "function.h"
00044 #include "recog.h"
00045 #include "expr.h"
00046 #include "optabs.h"
00047 #include "toplev.h"
00048 #include "basic-block.h"
00049 #include "target.h"
00050 #include "target-def.h"
00051
00052
00053
00054
00055
00056
00057 #define MAX_REG_FOR_PASSING_ARGS 6
00058
00059
00060 #define MIN_REG_FOR_PASSING_ARGS 2
00061
00062
00063
00064 #define MAX_COUNT 8
00065
00066
00067
00068 #define FUNC_IS_NORETURN_P(decl) (TREE_THIS_VOLATILE (decl))
00069
00070
00071
00072
00073 #define SCALE_FOR_INDEX_P(X) \
00074 (GET_CODE (X) == CONST_INT ? \
00075 (INTVAL (X) == 1 ? 1 : \
00076 INTVAL (X) == 2 ? 2 : \
00077 INTVAL (X) == 4 ? 4 : \
00078 INTVAL (X) == 8 ? 8 : \
00079 -1) : \
00080 -1)
00081
00082
00083 #define RTX_SIGNED_INT_FITS_N_BITS(X,n) \
00084 ((GET_CODE (X) == CONST_INT \
00085 && SIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
00086
00087
00088 #define RTX_UNSIGNED_INT_FITS_N_BITS(X, n) \
00089 ((GET_CODE (X) == CONST_INT \
00090 && UNSIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
00091
00092
00093
00094
00095
00096
00097 static int last_parm_in_reg;
00098
00099
00100
00101 static int last_reg_to_save;
00102
00103
00104
00105 static int save_regs[FIRST_PSEUDO_REGISTER];
00106
00107
00108 static int sum_regs = 0;
00109
00110
00111 static int local_vars_size;
00112
00113
00114
00115 static int size_for_adjusting_sp;
00116
00117
00118
00119 static enum machine_mode output_memory_reference_mode;
00120
00121
00122
00123
00124
00125
00126 const struct attribute_spec crx_attribute_table[];
00127
00128
00129 rtx crx_compare_op0 = NULL_RTX;
00130 rtx crx_compare_op1 = NULL_RTX;
00131
00132
00133
00134
00135
00136 static bool crx_fixed_condition_code_regs (unsigned int *, unsigned int *);
00137 static rtx crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
00138 int incoming ATTRIBUTE_UNUSED);
00139 static bool crx_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED);
00140 static int crx_address_cost (rtx);
00141
00142
00143
00144
00145
00146 #undef TARGET_FIXED_CONDITION_CODE_REGS
00147 #define TARGET_FIXED_CONDITION_CODE_REGS crx_fixed_condition_code_regs
00148
00149 #undef TARGET_STRUCT_VALUE_RTX
00150 #define TARGET_STRUCT_VALUE_RTX crx_struct_value_rtx
00151
00152 #undef TARGET_RETURN_IN_MEMORY
00153 #define TARGET_RETURN_IN_MEMORY crx_return_in_memory
00154
00155
00156
00157
00158
00159 #undef TARGET_ADDRESS_COST
00160 #define TARGET_ADDRESS_COST crx_address_cost
00161
00162
00163
00164
00165
00166 #undef TARGET_ATTRIBUTE_TABLE
00167 #define TARGET_ATTRIBUTE_TABLE crx_attribute_table
00168
00169 const struct attribute_spec crx_attribute_table[] = {
00170
00171 {"interrupt", 0, 0, false, true, true, NULL},
00172 {NULL, 0, 0, false, false, false, NULL}
00173 };
00174
00175
00176
00177
00178
00179 struct gcc_target targetm = TARGET_INITIALIZER;
00180
00181
00182
00183
00184
00185
00186
00187
00188 static bool
00189 crx_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
00190 {
00191 *p1 = CC_REGNUM;
00192 *p2 = INVALID_REGNUM;
00193 return true;
00194 }
00195
00196
00197
00198 static rtx
00199 crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
00200 int incoming ATTRIBUTE_UNUSED)
00201 {
00202 return gen_rtx_REG (Pmode, CRX_STRUCT_VALUE_REGNUM);
00203 }
00204
00205
00206
00207 static bool
00208 crx_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
00209 {
00210 if (TYPE_MODE (type) == BLKmode)
00211 {
00212 HOST_WIDE_INT size = int_size_in_bytes (type);
00213 return (size == -1 || size > 8);
00214 }
00215 else
00216 return false;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 int
00231 crx_interrupt_function_p (void)
00232 {
00233 tree attributes;
00234
00235 attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00236 return lookup_attribute ("interrupt", attributes) != NULL_TREE;
00237 }
00238
00239
00240
00241
00242
00243
00244 static void
00245 crx_compute_save_regs (void)
00246 {
00247 unsigned int regno;
00248
00249
00250 last_reg_to_save = -1;
00251
00252
00253 if (FUNC_IS_NORETURN_P (current_function_decl))
00254 return;
00255
00256
00257 sum_regs = 0;
00258
00259 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
00260 {
00261 if (fixed_regs[regno])
00262 {
00263 save_regs[regno] = 0;
00264 continue;
00265 }
00266
00267
00268 if (crx_interrupt_function_p ())
00269 {
00270 if (!current_function_is_leaf && call_used_regs[regno])
00271
00272
00273 save_regs[regno] = 1;
00274
00275 else if (regs_ever_live[regno])
00276
00277 save_regs[regno] = 1;
00278 else
00279
00280 save_regs[regno] = 0;
00281 }
00282 else
00283 {
00284
00285 if (regs_ever_live[regno]
00286 && (!call_used_regs[regno] || regno == RETURN_ADDRESS_REGNUM))
00287 save_regs[regno] = 1;
00288 else
00289 save_regs[regno] = 0;
00290 }
00291 }
00292
00293 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
00294 if (save_regs[regno] == 1)
00295 {
00296 last_reg_to_save = regno;
00297 sum_regs += UNITS_PER_WORD;
00298 }
00299 }
00300
00301
00302
00303
00304 static void
00305 crx_compute_frame (void)
00306 {
00307
00308 int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
00309 int padding_locals;
00310
00311
00312 local_vars_size = get_frame_size ();
00313
00314
00315 padding_locals = local_vars_size % stack_alignment;
00316 if (padding_locals)
00317 padding_locals = stack_alignment - padding_locals;
00318
00319 local_vars_size += padding_locals;
00320
00321 size_for_adjusting_sp = local_vars_size + (ACCUMULATE_OUTGOING_ARGS ?
00322 current_function_outgoing_args_size : 0);
00323 }
00324
00325
00326
00327 int
00328 crx_initial_elimination_offset (int from, int to)
00329 {
00330
00331 crx_compute_save_regs ();
00332
00333
00334 crx_compute_frame ();
00335
00336 if ((from) == FRAME_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM)
00337 return (ACCUMULATE_OUTGOING_ARGS ?
00338 current_function_outgoing_args_size : 0);
00339 else if ((from) == ARG_POINTER_REGNUM && (to) == FRAME_POINTER_REGNUM)
00340 return (sum_regs + local_vars_size);
00341 else if ((from) == ARG_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM)
00342 return (sum_regs + local_vars_size +
00343 (ACCUMULATE_OUTGOING_ARGS ?
00344 current_function_outgoing_args_size : 0));
00345 else
00346 abort ();
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 enum reg_class
00356 crx_regno_reg_class (int regno)
00357 {
00358 if (regno >= 0 && regno < SP_REGNUM)
00359 return NOSP_REGS;
00360
00361 if (regno == SP_REGNUM)
00362 return GENERAL_REGS;
00363
00364 if (regno == LO_REGNUM)
00365 return LO_REGS;
00366 if (regno == HI_REGNUM)
00367 return HI_REGS;
00368
00369 return NO_REGS;
00370 }
00371
00372
00373
00374 enum reg_class
00375 crx_secondary_reload_class (enum reg_class class,
00376 enum machine_mode mode ATTRIBUTE_UNUSED,
00377 rtx x ATTRIBUTE_UNUSED)
00378 {
00379 if (reg_classes_intersect_p (class, HILO_REGS)
00380 && true_regnum (x) == -1)
00381 return GENERAL_REGS;
00382
00383 return NO_REGS;
00384 }
00385
00386
00387
00388 int
00389 crx_hard_regno_mode_ok (int regno, enum machine_mode mode)
00390 {
00391
00392 if (regno == CC_REGNUM)
00393 return GET_MODE_CLASS (mode) == MODE_CC;
00394 if (GET_MODE_CLASS (mode) == MODE_CC)
00395 return 0;
00396
00397 if (HILO_REGNO_P (regno))
00398 return mode == SImode || mode == DImode;
00399 return 1;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408 static int
00409 enough_regs_for_param (CUMULATIVE_ARGS * cum, tree type,
00410 enum machine_mode mode)
00411 {
00412 int type_size;
00413 int remaining_size;
00414
00415 if (mode != BLKmode)
00416 type_size = GET_MODE_BITSIZE (mode);
00417 else
00418 type_size = int_size_in_bytes (type) * BITS_PER_UNIT;
00419
00420 remaining_size =
00421 BITS_PER_WORD * (MAX_REG_FOR_PASSING_ARGS -
00422 (MIN_REG_FOR_PASSING_ARGS + cum->ints) + 1);
00423
00424
00425
00426 if ((remaining_size >= type_size) && (type_size <= 2 * BITS_PER_WORD))
00427 return (type_size + BITS_PER_WORD - 1) / BITS_PER_WORD;
00428
00429 return 0;
00430 }
00431
00432
00433
00434 rtx
00435 crx_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type,
00436 int named ATTRIBUTE_UNUSED)
00437 {
00438 last_parm_in_reg = 0;
00439
00440
00441
00442
00443
00444 if (type == void_type_node)
00445 return NULL_RTX;
00446
00447 if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
00448 return NULL_RTX;
00449
00450 if (mode == BLKmode)
00451 {
00452
00453
00454 if (enough_regs_for_param (cum, type, mode) != 0)
00455 {
00456 last_parm_in_reg = 1;
00457 return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
00458 }
00459 }
00460
00461 if (MIN_REG_FOR_PASSING_ARGS + cum->ints > MAX_REG_FOR_PASSING_ARGS)
00462 return NULL_RTX;
00463 else
00464 {
00465 if (enough_regs_for_param (cum, type, mode) != 0)
00466 {
00467 last_parm_in_reg = 1;
00468 return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
00469 }
00470 }
00471
00472 return NULL_RTX;
00473 }
00474
00475
00476
00477 void
00478 crx_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
00479 rtx libfunc ATTRIBUTE_UNUSED)
00480 {
00481 tree param, next_param;
00482
00483 cum->ints = 0;
00484
00485
00486
00487
00488 for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
00489 param != (tree) 0; param = next_param)
00490 {
00491 next_param = TREE_CHAIN (param);
00492 if (next_param == (tree) 0 && TREE_VALUE (param) != void_type_node)
00493 {
00494 cum->ints = -1;
00495 return;
00496 }
00497 }
00498 }
00499
00500
00501
00502 void
00503 crx_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode,
00504 tree type, int named ATTRIBUTE_UNUSED)
00505 {
00506
00507 int l = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
00508
00509
00510 if (!last_parm_in_reg)
00511 return;
00512
00513 if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
00514 return;
00515
00516 if (mode == SImode || mode == HImode || mode == QImode || mode == DImode)
00517 {
00518 if (l <= 1)
00519 cum->ints += 1;
00520 else
00521 cum->ints += l;
00522 }
00523 else if (mode == SFmode || mode == DFmode)
00524 cum->ints += l;
00525 else if ((mode) == BLKmode)
00526 {
00527 if ((l = enough_regs_for_param (cum, type, mode)) != 0)
00528 cum->ints += l;
00529 }
00530
00531 }
00532
00533
00534
00535
00536 int
00537 crx_function_arg_regno_p (int n)
00538 {
00539 return (n <= MAX_REG_FOR_PASSING_ARGS && n >= MIN_REG_FOR_PASSING_ARGS);
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 static int crx_addr_reg_p (rtx addr_reg)
00557 {
00558 rtx reg;
00559
00560 if (REG_P (addr_reg))
00561 {
00562 reg = addr_reg;
00563 }
00564 else if ((GET_CODE (addr_reg) == SUBREG
00565 && REG_P (SUBREG_REG (addr_reg))
00566 && GET_MODE_SIZE (GET_MODE (SUBREG_REG (addr_reg)))
00567 <= UNITS_PER_WORD))
00568 {
00569 reg = SUBREG_REG (addr_reg);
00570 }
00571 else
00572 return FALSE;
00573
00574 if (GET_MODE (addr_reg) != Pmode)
00575 {
00576 return FALSE;
00577 }
00578
00579 return TRUE;
00580 }
00581
00582 enum crx_addrtype
00583 crx_decompose_address (rtx addr, struct crx_address *out)
00584 {
00585 rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX;
00586 rtx scale_rtx = NULL_RTX, side_effect = NULL_RTX;
00587 int scale = -1;
00588
00589 enum crx_addrtype retval = CRX_INVALID;
00590
00591 switch (GET_CODE (addr))
00592 {
00593 case CONST_INT:
00594
00595 retval = CRX_ABSOLUTE;
00596 disp = addr;
00597 if (!UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), GET_MODE_BITSIZE (Pmode)))
00598 return CRX_INVALID;
00599 break;
00600
00601 case CONST:
00602 case SYMBOL_REF:
00603 case LABEL_REF:
00604
00605 retval = CRX_ABSOLUTE;
00606 disp = addr;
00607 break;
00608
00609 case REG:
00610 case SUBREG:
00611
00612 retval = CRX_REG_REL;
00613 base = addr;
00614 break;
00615
00616 case PLUS:
00617 switch (GET_CODE (XEXP (addr, 0)))
00618 {
00619 case REG:
00620 case SUBREG:
00621 if (REG_P (XEXP (addr, 1)))
00622 {
00623
00624 retval = CRX_SCALED_INDX;
00625 base = XEXP (addr, 1);
00626 index = XEXP (addr, 0);
00627 scale = 1;
00628 }
00629 else if (RTX_SIGNED_INT_FITS_N_BITS (XEXP (addr, 1), 28))
00630 {
00631
00632 retval = CRX_REG_REL;
00633 base = XEXP (addr, 0);
00634 disp = XEXP (addr, 1);
00635 }
00636 else
00637 return CRX_INVALID;
00638 break;
00639
00640 case PLUS:
00641
00642 retval = CRX_SCALED_INDX;
00643 base = XEXP (XEXP (addr, 0), 1);
00644 disp = XEXP (addr, 1);
00645 if (!RTX_SIGNED_INT_FITS_N_BITS (disp, 22))
00646 return CRX_INVALID;
00647 switch (GET_CODE (XEXP (XEXP (addr, 0), 0)))
00648 {
00649 case REG:
00650
00651 index = XEXP (XEXP (addr, 0), 0);
00652 scale = 1;
00653 break;
00654
00655 case MULT:
00656
00657 index = XEXP (XEXP (XEXP (addr, 0), 0), 0);
00658 scale_rtx = XEXP (XEXP (XEXP (addr, 0), 0), 1);
00659 if ((scale = SCALE_FOR_INDEX_P (scale_rtx)) == -1)
00660 return CRX_INVALID;
00661 break;
00662
00663 default:
00664 return CRX_INVALID;
00665 }
00666 break;
00667
00668 case MULT:
00669
00670 retval = CRX_SCALED_INDX;
00671 base = XEXP (addr, 1);
00672 index = XEXP (XEXP (addr, 0), 0);
00673 scale_rtx = XEXP (XEXP (addr, 0), 1);
00674
00675 if ((scale = SCALE_FOR_INDEX_P (scale_rtx)) == -1)
00676 return CRX_INVALID;
00677 break;
00678
00679 default:
00680 return CRX_INVALID;
00681 }
00682 break;
00683
00684 case POST_INC:
00685 case POST_DEC:
00686
00687 retval = CRX_POST_INC;
00688 base = XEXP (addr, 0);
00689 side_effect = addr;
00690 break;
00691
00692 case POST_MODIFY:
00693
00694 retval = CRX_POST_INC;
00695 base = XEXP (addr, 0);
00696 side_effect = XEXP (addr, 1);
00697 if (base != XEXP (side_effect, 0))
00698 return CRX_INVALID;
00699 switch (GET_CODE (side_effect))
00700 {
00701 case PLUS:
00702 case MINUS:
00703 disp = XEXP (side_effect, 1);
00704 if (!RTX_SIGNED_INT_FITS_N_BITS (disp, 12))
00705 return CRX_INVALID;
00706 break;
00707
00708 default:
00709
00710 return CRX_INVALID;
00711 }
00712 break;
00713
00714 default:
00715 return CRX_INVALID;
00716 }
00717
00718 if (base && !crx_addr_reg_p (base)) return CRX_INVALID;
00719 if (index && !crx_addr_reg_p (index)) return CRX_INVALID;
00720
00721 out->base = base;
00722 out->index = index;
00723 out->disp = disp;
00724 out->scale = scale;
00725 out->side_effect = side_effect;
00726
00727 return retval;
00728 }
00729
00730 int
00731 crx_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
00732 rtx addr, int strict)
00733 {
00734 enum crx_addrtype addrtype;
00735 struct crx_address address;
00736
00737 if (TARGET_DEBUG_ADDR)
00738 {
00739 fprintf (stderr,
00740 "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
00741 GET_MODE_NAME (mode), strict);
00742 debug_rtx (addr);
00743 }
00744
00745 addrtype = crx_decompose_address (addr, &address);
00746
00747 if (addrtype == CRX_POST_INC && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
00748 return FALSE;
00749
00750 if (TARGET_DEBUG_ADDR)
00751 {
00752 const char *typestr;
00753 switch (addrtype)
00754 {
00755 case CRX_INVALID:
00756 typestr = "Invalid";
00757 break;
00758 case CRX_REG_REL:
00759 typestr = "Register relative";
00760 break;
00761 case CRX_POST_INC:
00762 typestr = "Post-increment";
00763 break;
00764 case CRX_SCALED_INDX:
00765 typestr = "Scaled index";
00766 break;
00767 case CRX_ABSOLUTE:
00768 typestr = "Absolute";
00769 break;
00770 default:
00771 abort ();
00772 }
00773 fprintf (stderr, "CRX Address type: %s\n", typestr);
00774 }
00775
00776 if (addrtype == CRX_INVALID)
00777 return FALSE;
00778
00779 if (strict)
00780 {
00781 if (address.base && !REGNO_OK_FOR_BASE_P (REGNO (address.base)))
00782 {
00783 if (TARGET_DEBUG_ADDR)
00784 fprintf (stderr, "Base register not strict\n");
00785 return FALSE;
00786 }
00787 if (address.index && !REGNO_OK_FOR_INDEX_P (REGNO (address.index)))
00788 {
00789 if (TARGET_DEBUG_ADDR)
00790 fprintf (stderr, "Index register not strict\n");
00791 return FALSE;
00792 }
00793 }
00794
00795 return TRUE;
00796 }
00797
00798
00799
00800
00801
00802
00803 static int
00804 crx_address_cost (rtx addr)
00805 {
00806 enum crx_addrtype addrtype;
00807 struct crx_address address;
00808
00809 int cost = 2;
00810
00811 addrtype = crx_decompose_address (addr, &address);
00812
00813 gcc_assert (addrtype != CRX_INVALID);
00814
00815
00816 if (addrtype == CRX_ABSOLUTE)
00817 cost+=2;
00818
00819
00820 if (addrtype == CRX_POST_INC)
00821 cost-=2;
00822
00823
00824 if (address.base)
00825 cost++;
00826
00827 if (address.index && address.scale == 1)
00828 cost+=5;
00829
00830 if (address.disp && !INT_CST4 (INTVAL (address.disp)))
00831 cost+=2;
00832
00833 if (TARGET_DEBUG_ADDR)
00834 {
00835 fprintf (stderr, "\n======\nTARGET_ADDRESS_COST = %d\n", cost);
00836 debug_rtx (addr);
00837 }
00838
00839 return cost;
00840 }
00841
00842
00843
00844
00845
00846
00847 int
00848 crx_memory_move_cost (enum machine_mode mode,
00849 enum reg_class class ATTRIBUTE_UNUSED,
00850 int in ATTRIBUTE_UNUSED)
00851 {
00852
00853 if (reg_classes_intersect_p (class, GENERAL_REGS))
00854 {
00855
00856 return 4 * HARD_REGNO_NREGS (0, mode);
00857 }
00858 else if (reg_classes_intersect_p (class, HILO_REGS))
00859 {
00860
00861
00862
00863
00864
00865
00866 return (REGISTER_MOVE_COST (mode,
00867 in ? GENERAL_REGS : HILO_REGS,
00868 in ? HILO_REGS : GENERAL_REGS) + 4)
00869 * HARD_REGNO_NREGS (0, mode);
00870 }
00871 else
00872 {
00873
00874 return 100;
00875 }
00876 }
00877
00878
00879
00880
00881
00882
00883 int
00884 crx_const_double_ok (rtx op)
00885 {
00886 if (GET_MODE (op) == DFmode)
00887 {
00888 REAL_VALUE_TYPE r;
00889 long l[2];
00890 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
00891 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
00892 return (UNSIGNED_INT_FITS_N_BITS (l[0], 4) &&
00893 UNSIGNED_INT_FITS_N_BITS (l[1], 4)) ? 1 : 0;
00894 }
00895
00896 if (GET_MODE (op) == SFmode)
00897 {
00898 REAL_VALUE_TYPE r;
00899 long l;
00900 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
00901 REAL_VALUE_TO_TARGET_SINGLE (r, l);
00902 return UNSIGNED_INT_FITS_N_BITS (l, 4) ? 1 : 0;
00903 }
00904
00905 return (UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_LOW (op), 4) &&
00906 UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_HIGH (op), 4)) ? 1 : 0;
00907 }
00908
00909
00910
00911 void
00912 crx_print_operand (FILE * file, rtx x, int code)
00913 {
00914 switch (code)
00915 {
00916 case 'p' :
00917 if (GET_CODE (x) == REG) {
00918 if (GET_MODE (x) == DImode || GET_MODE (x) == DFmode)
00919 {
00920 int regno = REGNO (x);
00921 if (regno + 1 >= SP_REGNUM) abort ();
00922 fprintf (file, "{%s, %s}", reg_names[regno], reg_names[regno + 1]);
00923 return;
00924 }
00925 else
00926 {
00927 if (REGNO (x) >= SP_REGNUM) abort ();
00928 fprintf (file, "%s", reg_names[REGNO (x)]);
00929 return;
00930 }
00931 }
00932
00933 case 'd' :
00934 {
00935 const char *crx_cmp_str;
00936 switch (GET_CODE (x))
00937 {
00938
00939 case EQ : crx_cmp_str = "eq"; break;
00940 case NE : crx_cmp_str = "ne"; break;
00941 case GT : crx_cmp_str = "lt"; break;
00942 case GTU : crx_cmp_str = "lo"; break;
00943 case LT : crx_cmp_str = "gt"; break;
00944 case LTU : crx_cmp_str = "hi"; break;
00945 case GE : crx_cmp_str = "le"; break;
00946 case GEU : crx_cmp_str = "ls"; break;
00947 case LE : crx_cmp_str = "ge"; break;
00948 case LEU : crx_cmp_str = "hs"; break;
00949 default : abort ();
00950 }
00951 fprintf (file, "%s", crx_cmp_str);
00952 return;
00953 }
00954
00955 case 'H':
00956
00957 switch (GET_CODE (x))
00958 {
00959 case CONST_DOUBLE:
00960 if (GET_MODE (x) == SFmode) abort ();
00961 if (GET_MODE (x) == DFmode)
00962 {
00963
00964 REAL_VALUE_TYPE r;
00965 long l[2];
00966
00967 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
00968 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
00969
00970 fprintf (file, "$0x%lx", l[1]);
00971 return;
00972 }
00973
00974
00975
00976 case CONST_INT:
00977 {
00978 rtx high, low;
00979 split_double (x, &low, &high);
00980 putc ('$', file);
00981 output_addr_const (file, high);
00982 return;
00983 }
00984
00985 case REG:
00986 if (REGNO (x) + 1 >= FIRST_PSEUDO_REGISTER) abort ();
00987 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
00988 return;
00989
00990 case MEM:
00991
00992 {
00993 rtx adj_mem = x;
00994 adj_mem = adjust_address (adj_mem, GET_MODE (adj_mem), 4);
00995
00996 output_memory_reference_mode = GET_MODE (adj_mem);
00997 output_address (XEXP (adj_mem, 0));
00998 return;
00999 }
01000
01001 default:
01002 abort ();
01003 }
01004
01005 case 'L':
01006
01007 switch (GET_CODE (x))
01008 {
01009 case CONST_DOUBLE:
01010 if (GET_MODE (x) == SFmode) abort ();
01011 if (GET_MODE (x) == DFmode)
01012 {
01013
01014 REAL_VALUE_TYPE r;
01015 long l[2];
01016
01017 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
01018 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
01019
01020 fprintf (file, "$0x%lx", l[0]);
01021 return;
01022 }
01023
01024
01025
01026 case CONST_INT:
01027 {
01028 rtx high, low;
01029 split_double (x, &low, &high);
01030 putc ('$', file);
01031 output_addr_const (file, low);
01032 return;
01033 }
01034
01035 case REG:
01036 fprintf (file, "%s", reg_names[REGNO (x)]);
01037 return;
01038
01039 case MEM:
01040 output_memory_reference_mode = GET_MODE (x);
01041 output_address (XEXP (x, 0));
01042 return;
01043
01044 default:
01045 abort ();
01046 }
01047
01048 case 0 :
01049 switch (GET_CODE (x))
01050 {
01051 case REG:
01052 fprintf (file, "%s", reg_names[REGNO (x)]);
01053 return;
01054
01055 case MEM:
01056 output_memory_reference_mode = GET_MODE (x);
01057 output_address (XEXP (x, 0));
01058 return;
01059
01060 case CONST_DOUBLE:
01061 {
01062 REAL_VALUE_TYPE r;
01063 long l;
01064
01065
01066 gcc_assert (GET_MODE (x) == SFmode);
01067
01068 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
01069 REAL_VALUE_TO_TARGET_SINGLE (r, l);
01070
01071 fprintf (file, "$0x%lx", l);
01072 return;
01073 }
01074
01075 default:
01076 putc ('$', file);
01077 output_addr_const (file, x);
01078 return;
01079 }
01080
01081 default:
01082 output_operand_lossage ("invalid %%xn code");
01083 }
01084
01085 abort ();
01086 }
01087
01088
01089
01090 void
01091 crx_print_operand_address (FILE * file, rtx addr)
01092 {
01093 enum crx_addrtype addrtype;
01094 struct crx_address address;
01095
01096 int offset;
01097
01098 addrtype = crx_decompose_address (addr, &address);
01099
01100 if (address.disp)
01101 offset = INTVAL (address.disp);
01102 else
01103 offset = 0;
01104
01105 switch (addrtype)
01106 {
01107 case CRX_REG_REL:
01108 fprintf (file, "%d(%s)", offset, reg_names[REGNO (address.base)]);
01109 return;
01110
01111 case CRX_POST_INC:
01112 switch (GET_CODE (address.side_effect))
01113 {
01114 case PLUS:
01115 break;
01116 case MINUS:
01117 offset = -offset;
01118 break;
01119 case POST_INC:
01120 offset = GET_MODE_SIZE (output_memory_reference_mode);
01121 break;
01122 case POST_DEC:
01123 offset = -GET_MODE_SIZE (output_memory_reference_mode);
01124 break;
01125 default:
01126 abort ();
01127 }
01128 fprintf (file, "%d(%s)+", offset, reg_names[REGNO (address.base)]);
01129 return;
01130
01131 case CRX_SCALED_INDX:
01132 fprintf (file, "%d(%s, %s, %d)", offset, reg_names[REGNO (address.base)],
01133 reg_names[REGNO (address.index)], address.scale);
01134 return;
01135
01136 case CRX_ABSOLUTE:
01137 output_addr_const (file, address.disp);
01138 return;
01139
01140 default:
01141 abort ();
01142 }
01143 }
01144
01145
01146
01147
01148
01149
01150 void crx_expand_movmem_single (rtx src, rtx srcbase, rtx dst, rtx dstbase,
01151 rtx tmp_reg, unsigned HOST_WIDE_INT *offset_p)
01152 {
01153 rtx addr, mem;
01154 unsigned HOST_WIDE_INT offset = *offset_p;
01155
01156
01157 addr = plus_constant (src, offset);
01158 mem = adjust_automodify_address (srcbase, SImode, addr, offset);
01159 emit_move_insn (tmp_reg, mem);
01160
01161
01162 addr = plus_constant (dst, offset);
01163 mem = adjust_automodify_address (dstbase, SImode, addr, offset);
01164 emit_move_insn (mem, tmp_reg);
01165
01166 *offset_p = offset + 4;
01167 }
01168
01169 int
01170 crx_expand_movmem (rtx dstbase, rtx srcbase, rtx count_exp, rtx align_exp)
01171 {
01172 unsigned HOST_WIDE_INT count = 0, offset, si_moves, i;
01173 HOST_WIDE_INT align = 0;
01174
01175 rtx src, dst;
01176 rtx tmp_reg;
01177
01178 if (GET_CODE (align_exp) == CONST_INT)
01179 {
01180 align = INTVAL (align_exp);
01181 if (align & 3)
01182 return 0;
01183 }
01184
01185 if (GET_CODE (count_exp) == CONST_INT)
01186 {
01187 count = INTVAL (count_exp);
01188 if (count > 64)
01189 return 0;
01190 }
01191
01192 tmp_reg = gen_reg_rtx (SImode);
01193
01194
01195 dst = copy_to_mode_reg (Pmode, XEXP (dstbase, 0));
01196 if (dst != XEXP (dstbase, 0))
01197 dstbase = replace_equiv_address_nv (dstbase, dst);
01198 src = copy_to_mode_reg (Pmode, XEXP (srcbase, 0));
01199 if (src != XEXP (srcbase, 0))
01200 srcbase = replace_equiv_address_nv (srcbase, src);
01201
01202 offset = 0;
01203
01204
01205 si_moves = count >> 2;
01206 for (i = 0; i < si_moves; i++)
01207 crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset);
01208
01209
01210 if (count & 3)
01211 {
01212 offset = count - 4;
01213 crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset);
01214 }
01215
01216 gcc_assert (offset == count);
01217
01218 return 1;
01219 }
01220
01221 rtx
01222 crx_expand_compare (enum rtx_code code, enum machine_mode mode)
01223 {
01224 rtx op0, op1, cc_reg, ret;
01225
01226 op0 = crx_compare_op0;
01227 op1 = crx_compare_op1;
01228
01229
01230 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
01231 ret = gen_rtx_COMPARE (CCmode, op0, op1);
01232 emit_insn (gen_rtx_SET (VOIDmode, cc_reg, ret));
01233
01234
01235
01236 return gen_rtx_fmt_ee (code, mode, cc_reg, const0_rtx);
01237 }
01238
01239 void
01240 crx_expand_branch (enum rtx_code code, rtx label)
01241 {
01242 rtx tmp = crx_expand_compare (code, VOIDmode);
01243 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
01244 gen_rtx_LABEL_REF (VOIDmode, label),
01245 pc_rtx);
01246 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
01247
01248 }
01249
01250 void
01251 crx_expand_scond (enum rtx_code code, rtx dest)
01252 {
01253 rtx tmp = crx_expand_compare (code, GET_MODE (dest));
01254 emit_move_insn (dest, tmp);
01255
01256 }
01257
01258 static void
01259 mpushpop_str (char *stringbuffer, const char *mnemonic, char *mask)
01260 {
01261 if (strlen (mask) > 2 || crx_interrupt_function_p ())
01262 sprintf (stringbuffer, "\n\t%s\tsp, {%s}", mnemonic, mask);
01263 else
01264 sprintf (stringbuffer, "\n\t%s\t%s", mnemonic, mask);
01265 }
01266
01267
01268
01269
01270
01271
01272
01273
01274 char *
01275 crx_prepare_push_pop_string (int push_or_pop)
01276 {
01277
01278
01279
01280
01281 static char mask_str[50];
01282
01283
01284 int i = 0;
01285
01286 int ra_in_bitmask = 0;
01287
01288 char *return_str;
01289
01290
01291 char *temp_str;
01292
01293 return_str = (char *) xmalloc (120);
01294 temp_str = (char *) xmalloc (120);
01295
01296
01297 memset (return_str, 0, 3);
01298
01299 while (i <= last_reg_to_save)
01300 {
01301
01302 mask_str[0] = 0;
01303
01304 if (i <= SP_REGNUM)
01305 {
01306 int j = 0;
01307 while (j < MAX_COUNT && i <= SP_REGNUM)
01308 {
01309 if (save_regs[i])
01310 {
01311
01312
01313 if (i == RETURN_ADDRESS_REGNUM) ra_in_bitmask = 1;
01314 if (j > 0) strcat (mask_str, ", ");
01315 strcat (mask_str, reg_names[i]);
01316 ++j;
01317 }
01318 ++i;
01319 }
01320 }
01321 else
01322 {
01323
01324 while (i <= last_reg_to_save)
01325 {
01326 if (save_regs[i])
01327 {
01328 strcat (mask_str, "lo, hi");
01329 i = last_reg_to_save + 1;
01330 break;
01331 }
01332 ++i;
01333 }
01334 }
01335
01336 if (strlen (mask_str) == 0) continue;
01337
01338 if (push_or_pop == 1)
01339 {
01340 if (crx_interrupt_function_p ())
01341 mpushpop_str (temp_str, "popx", mask_str);
01342 else
01343 {
01344 if (ra_in_bitmask)
01345 {
01346 mpushpop_str (temp_str, "popret", mask_str);
01347 ra_in_bitmask = 0;
01348 }
01349 else mpushpop_str (temp_str, "pop", mask_str);
01350 }
01351
01352 strcat (return_str, temp_str);
01353 }
01354 else
01355 {
01356
01357
01358
01359 if (crx_interrupt_function_p ())
01360 mpushpop_str (temp_str, "pushx", mask_str);
01361 else
01362 mpushpop_str (temp_str, "push", mask_str);
01363 strcat (temp_str, return_str);
01364 strcpy (strcat (return_str, "\t"), temp_str);
01365 }
01366
01367 }
01368
01369 if (push_or_pop == 1)
01370 {
01371
01372 if (crx_interrupt_function_p ())
01373 strcat (return_str, "\n\tretx\n");
01374
01375 else if (!FUNC_IS_NORETURN_P (current_function_decl)
01376 && !save_regs[RETURN_ADDRESS_REGNUM])
01377 strcat (return_str, "\n\tjump\tra\n");
01378 }
01379
01380
01381 return_str += 2;
01382 return return_str;
01383 }
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412 void
01413 crx_expand_prologue (void)
01414 {
01415 crx_compute_frame ();
01416 crx_compute_save_regs ();
01417
01418
01419 if (size_for_adjusting_sp + sum_regs == 0)
01420 return;
01421
01422 if (last_reg_to_save != -1)
01423
01424 emit_insn (gen_push_for_prologue (GEN_INT (sum_regs)));
01425
01426 if (size_for_adjusting_sp > 0)
01427 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
01428 GEN_INT (-size_for_adjusting_sp)));
01429
01430 if (frame_pointer_needed)
01431
01432
01433 emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
01434 }
01435
01436
01437
01438
01439 void
01440 crx_expand_epilogue (void)
01441 {
01442 rtx return_reg;
01443
01444
01445
01446
01447 int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM]
01448 && (sum_regs == UNITS_PER_WORD));
01449
01450
01451 return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM);
01452
01453 if (frame_pointer_needed)
01454
01455 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
01456
01457 if (size_for_adjusting_sp > 0)
01458 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
01459 GEN_INT (size_for_adjusting_sp)));
01460
01461 if (crx_interrupt_function_p ())
01462 emit_jump_insn (gen_interrupt_return ());
01463 else if (last_reg_to_save == -1)
01464
01465
01466 emit_jump_insn (gen_indirect_jump_return ());
01467 else if (only_popret_RA)
01468 emit_jump_insn (gen_popret_RA_return ());
01469 else
01470 emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs)));
01471 }
01472