00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include "system.h"
00026 #include "coretypes.h"
00027 #include "tm.h"
00028 #include "rtl.h"
00029 #include "tree.h"
00030 #include "tm_p.h"
00031 #include "regs.h"
00032 #include "hard-reg-set.h"
00033 #include "real.h"
00034 #include "insn-config.h"
00035 #include "conditions.h"
00036 #include "output.h"
00037 #include "insn-attr.h"
00038 #include "flags.h"
00039 #include "except.h"
00040 #include "function.h"
00041 #include "recog.h"
00042 #include "expr.h"
00043 #include "reload.h"
00044 #include "toplev.h"
00045 #include "basic-block.h"
00046 #include "integrate.h"
00047 #include "ggc.h"
00048 #include "target.h"
00049 #include "target-def.h"
00050 #include "debug.h"
00051 #include "langhooks.h"
00052 #include "optabs.h"
00053 #include "tree-gimple.h"
00054
00055
00056 #define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0)
00057
00058
00059 static bool s390_assemble_integer (rtx, unsigned int, int);
00060 static void s390_encode_section_info (tree, rtx, int);
00061 static bool s390_cannot_force_const_mem (rtx);
00062 static rtx s390_delegitimize_address (rtx);
00063 static bool s390_return_in_memory (tree, tree);
00064 static void s390_init_builtins (void);
00065 static rtx s390_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
00066 static void s390_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
00067 HOST_WIDE_INT, tree);
00068 static enum attr_type s390_safe_attr_type (rtx);
00069
00070 static int s390_adjust_priority (rtx, int);
00071 static int s390_issue_rate (void);
00072 static int s390_first_cycle_multipass_dfa_lookahead (void);
00073 static bool s390_cannot_copy_insn_p (rtx);
00074 static bool s390_rtx_costs (rtx, int, int, int *);
00075 static int s390_address_cost (rtx);
00076 static void s390_reorg (void);
00077 static bool s390_valid_pointer_mode (enum machine_mode);
00078 static tree s390_build_builtin_va_list (void);
00079 static tree s390_gimplify_va_arg (tree, tree, tree *, tree *);
00080 static bool s390_function_ok_for_sibcall (tree, tree);
00081 static bool s390_call_saved_register_used (tree);
00082 static bool s390_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode mode,
00083 tree, bool);
00084 static bool s390_fixed_condition_code_regs (unsigned int *, unsigned int *);
00085 static enum machine_mode s390_cc_modes_compatible (enum machine_mode,
00086 enum machine_mode);
00087
00088
00089
00090
00091 struct processor_costs
00092 {
00093
00094 const int m;
00095 const int mghi;
00096 const int mh;
00097 const int mhi;
00098 const int ml;
00099 const int mr;
00100 const int ms;
00101 const int msg;
00102 const int msgf;
00103 const int msgfr;
00104 const int msgr;
00105 const int msr;
00106 const int mult_df;
00107
00108 const int sqdbr;
00109 const int sqebr;
00110
00111 const int madbr;
00112 const int maebr;
00113
00114 const int ddbr;
00115 const int ddr;
00116 const int debr;
00117 const int der;
00118 const int dlgr;
00119 const int dlr;
00120 const int dr;
00121 const int dsgfr;
00122 const int dsgr;
00123 };
00124
00125 const struct processor_costs *s390_cost;
00126
00127 static const
00128 struct processor_costs z900_cost =
00129 {
00130 COSTS_N_INSNS (5),
00131 COSTS_N_INSNS (10),
00132 COSTS_N_INSNS (5),
00133 COSTS_N_INSNS (4),
00134 COSTS_N_INSNS (5),
00135 COSTS_N_INSNS (5),
00136 COSTS_N_INSNS (4),
00137 COSTS_N_INSNS (15),
00138 COSTS_N_INSNS (7),
00139 COSTS_N_INSNS (7),
00140 COSTS_N_INSNS (10),
00141 COSTS_N_INSNS (4),
00142 COSTS_N_INSNS (7),
00143 COSTS_N_INSNS (44),
00144 COSTS_N_INSNS (35),
00145 COSTS_N_INSNS (18),
00146 COSTS_N_INSNS (13),
00147 COSTS_N_INSNS (30),
00148 COSTS_N_INSNS (30),
00149 COSTS_N_INSNS (27),
00150 COSTS_N_INSNS (26),
00151 COSTS_N_INSNS (220),
00152 COSTS_N_INSNS (34),
00153 COSTS_N_INSNS (34),
00154 COSTS_N_INSNS (32),
00155 COSTS_N_INSNS (32),
00156 };
00157
00158 static const
00159 struct processor_costs z990_cost =
00160 {
00161 COSTS_N_INSNS (4),
00162 COSTS_N_INSNS (2),
00163 COSTS_N_INSNS (2),
00164 COSTS_N_INSNS (2),
00165 COSTS_N_INSNS (4),
00166 COSTS_N_INSNS (4),
00167 COSTS_N_INSNS (5),
00168 COSTS_N_INSNS (6),
00169 COSTS_N_INSNS (4),
00170 COSTS_N_INSNS (4),
00171 COSTS_N_INSNS (4),
00172 COSTS_N_INSNS (4),
00173 COSTS_N_INSNS (1),
00174 COSTS_N_INSNS (66),
00175 COSTS_N_INSNS (38),
00176 COSTS_N_INSNS (1),
00177 COSTS_N_INSNS (1),
00178 COSTS_N_INSNS (40),
00179 COSTS_N_INSNS (44),
00180 COSTS_N_INSNS (26),
00181 COSTS_N_INSNS (28),
00182 COSTS_N_INSNS (176),
00183 COSTS_N_INSNS (31),
00184 COSTS_N_INSNS (31),
00185 COSTS_N_INSNS (31),
00186 COSTS_N_INSNS (31),
00187 };
00188
00189
00190 #undef TARGET_ASM_ALIGNED_HI_OP
00191 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
00192 #undef TARGET_ASM_ALIGNED_DI_OP
00193 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
00194 #undef TARGET_ASM_INTEGER
00195 #define TARGET_ASM_INTEGER s390_assemble_integer
00196
00197 #undef TARGET_ASM_OPEN_PAREN
00198 #define TARGET_ASM_OPEN_PAREN ""
00199
00200 #undef TARGET_ASM_CLOSE_PAREN
00201 #define TARGET_ASM_CLOSE_PAREN ""
00202
00203 #undef TARGET_ENCODE_SECTION_INFO
00204 #define TARGET_ENCODE_SECTION_INFO s390_encode_section_info
00205
00206 #ifdef HAVE_AS_TLS
00207 #undef TARGET_HAVE_TLS
00208 #define TARGET_HAVE_TLS true
00209 #endif
00210 #undef TARGET_CANNOT_FORCE_CONST_MEM
00211 #define TARGET_CANNOT_FORCE_CONST_MEM s390_cannot_force_const_mem
00212
00213 #undef TARGET_DELEGITIMIZE_ADDRESS
00214 #define TARGET_DELEGITIMIZE_ADDRESS s390_delegitimize_address
00215
00216 #undef TARGET_RETURN_IN_MEMORY
00217 #define TARGET_RETURN_IN_MEMORY s390_return_in_memory
00218
00219 #undef TARGET_INIT_BUILTINS
00220 #define TARGET_INIT_BUILTINS s390_init_builtins
00221 #undef TARGET_EXPAND_BUILTIN
00222 #define TARGET_EXPAND_BUILTIN s390_expand_builtin
00223
00224 #undef TARGET_ASM_OUTPUT_MI_THUNK
00225 #define TARGET_ASM_OUTPUT_MI_THUNK s390_output_mi_thunk
00226 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
00227 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
00228
00229 #undef TARGET_SCHED_ADJUST_PRIORITY
00230 #define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority
00231 #undef TARGET_SCHED_ISSUE_RATE
00232 #define TARGET_SCHED_ISSUE_RATE s390_issue_rate
00233 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
00234 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD s390_first_cycle_multipass_dfa_lookahead
00235
00236 #undef TARGET_CANNOT_COPY_INSN_P
00237 #define TARGET_CANNOT_COPY_INSN_P s390_cannot_copy_insn_p
00238 #undef TARGET_RTX_COSTS
00239 #define TARGET_RTX_COSTS s390_rtx_costs
00240 #undef TARGET_ADDRESS_COST
00241 #define TARGET_ADDRESS_COST s390_address_cost
00242
00243 #undef TARGET_MACHINE_DEPENDENT_REORG
00244 #define TARGET_MACHINE_DEPENDENT_REORG s390_reorg
00245
00246 #undef TARGET_VALID_POINTER_MODE
00247 #define TARGET_VALID_POINTER_MODE s390_valid_pointer_mode
00248
00249 #undef TARGET_BUILD_BUILTIN_VA_LIST
00250 #define TARGET_BUILD_BUILTIN_VA_LIST s390_build_builtin_va_list
00251 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
00252 #define TARGET_GIMPLIFY_VA_ARG_EXPR s390_gimplify_va_arg
00253
00254 #undef TARGET_PROMOTE_FUNCTION_ARGS
00255 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
00256 #undef TARGET_PROMOTE_FUNCTION_RETURN
00257 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
00258 #undef TARGET_PASS_BY_REFERENCE
00259 #define TARGET_PASS_BY_REFERENCE s390_pass_by_reference
00260
00261 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
00262 #define TARGET_FUNCTION_OK_FOR_SIBCALL s390_function_ok_for_sibcall
00263
00264 #undef TARGET_FIXED_CONDITION_CODE_REGS
00265 #define TARGET_FIXED_CONDITION_CODE_REGS s390_fixed_condition_code_regs
00266
00267 #undef TARGET_CC_MODES_COMPATIBLE
00268 #define TARGET_CC_MODES_COMPATIBLE s390_cc_modes_compatible
00269
00270 struct gcc_target targetm = TARGET_INITIALIZER;
00271
00272 extern int reload_completed;
00273
00274
00275 static int s390_sr_alias_set = 0;
00276
00277
00278
00279 rtx s390_compare_op0, s390_compare_op1;
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 struct s390_address
00291 {
00292 rtx base;
00293 rtx indx;
00294 rtx disp;
00295 int pointer;
00296 };
00297
00298
00299 enum processor_type s390_tune;
00300 enum processor_flags s390_tune_flags;
00301
00302 enum processor_type s390_arch;
00303 enum processor_flags s390_arch_flags;
00304
00305
00306 const char *s390_tune_string;
00307 const char *s390_arch_string;
00308
00309 const char *s390_warn_framesize_string;
00310 const char *s390_warn_dynamicstack_string;
00311 const char *s390_stack_size_string;
00312 const char *s390_stack_guard_string;
00313
00314 HOST_WIDE_INT s390_warn_framesize = 0;
00315 bool s390_warn_dynamicstack_p = 0;
00316 HOST_WIDE_INT s390_stack_size = 0;
00317 HOST_WIDE_INT s390_stack_guard = 0;
00318
00319
00320
00321
00322 struct s390_frame_layout GTY (())
00323 {
00324
00325 HOST_WIDE_INT gprs_offset;
00326 HOST_WIDE_INT f0_offset;
00327 HOST_WIDE_INT f4_offset;
00328 HOST_WIDE_INT f8_offset;
00329 HOST_WIDE_INT backchain_offset;
00330
00331
00332 int first_save_gpr;
00333 int first_restore_gpr;
00334 int last_save_gpr;
00335 int last_restore_gpr;
00336
00337
00338
00339
00340
00341
00342
00343 unsigned int fpr_bitmap;
00344
00345
00346 int high_fprs;
00347
00348
00349 bool save_return_addr_p;
00350
00351
00352 HOST_WIDE_INT frame_size;
00353 };
00354
00355
00356
00357 struct machine_function GTY(())
00358 {
00359 struct s390_frame_layout frame_layout;
00360
00361
00362 rtx base_reg;
00363
00364
00365 bool split_branches_pending_p;
00366
00367
00368 const char *some_ld_name;
00369 };
00370
00371
00372
00373 #define cfun_frame_layout (cfun->machine->frame_layout)
00374 #define cfun_save_high_fprs_p (!!cfun_frame_layout.high_fprs)
00375 #define cfun_gprs_save_area_size ((cfun_frame_layout.last_save_gpr - \
00376 cfun_frame_layout.first_save_gpr + 1) * UNITS_PER_WORD)
00377 #define cfun_set_fpr_bit(BITNUM) (cfun->machine->frame_layout.fpr_bitmap |= \
00378 (1 << (BITNUM)))
00379 #define cfun_fpr_bit_p(BITNUM) (!!(cfun->machine->frame_layout.fpr_bitmap & \
00380 (1 << (BITNUM))))
00381
00382 static int s390_match_ccmode_set (rtx, enum machine_mode);
00383 static int s390_branch_condition_mask (rtx);
00384 static const char *s390_branch_condition_mnemonic (rtx, int);
00385 static int check_mode (rtx, enum machine_mode *);
00386 static int s390_short_displacement (rtx);
00387 static int s390_decompose_address (rtx, struct s390_address *);
00388 static rtx get_thread_pointer (void);
00389 static rtx legitimize_tls_address (rtx, rtx);
00390 static void print_shift_count_operand (FILE *, rtx);
00391 static const char *get_some_local_dynamic_name (void);
00392 static int get_some_local_dynamic_name_1 (rtx *, void *);
00393 static int reg_used_in_mem_p (int, rtx);
00394 static int addr_generation_dependency_p (rtx, rtx);
00395 static int s390_split_branches (void);
00396 static void annotate_constant_pool_refs (rtx *x);
00397 static void find_constant_pool_ref (rtx, rtx *);
00398 static void replace_constant_pool_ref (rtx *, rtx, rtx);
00399 static rtx find_ltrel_base (rtx);
00400 static void replace_ltrel_base (rtx *);
00401 static void s390_optimize_prologue (void);
00402 static int find_unused_clobbered_reg (void);
00403 static void s390_frame_area (int *, int *);
00404 static void s390_register_info (int []);
00405 static void s390_frame_info (void);
00406 static void s390_init_frame_layout (void);
00407 static void s390_update_frame_layout (void);
00408 static rtx save_fpr (rtx, int, int);
00409 static rtx restore_fpr (rtx, int, int);
00410 static rtx save_gprs (rtx, int, int, int);
00411 static rtx restore_gprs (rtx, int, int, int);
00412 static int s390_function_arg_size (enum machine_mode, tree);
00413 static bool s390_function_arg_float (enum machine_mode, tree);
00414 static struct machine_function * s390_init_machine_status (void);
00415
00416
00417 #define DISP_IN_RANGE(d) \
00418 (TARGET_LONG_DISPLACEMENT? ((d) >= -524288 && (d) <= 524287) \
00419 : ((d) >= 0 && (d) <= 4095))
00420
00421
00422
00423
00424
00425 static int
00426 s390_match_ccmode_set (rtx set, enum machine_mode req_mode)
00427 {
00428 enum machine_mode set_mode;
00429
00430 if (GET_CODE (set) != SET)
00431 abort ();
00432
00433 if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set))))
00434 return 1;
00435
00436 set_mode = GET_MODE (SET_DEST (set));
00437 switch (set_mode)
00438 {
00439 case CCSmode:
00440 case CCSRmode:
00441 case CCUmode:
00442 case CCURmode:
00443 case CCLmode:
00444 case CCL1mode:
00445 case CCL2mode:
00446 case CCL3mode:
00447 case CCT1mode:
00448 case CCT2mode:
00449 case CCT3mode:
00450 if (req_mode != set_mode)
00451 return 0;
00452 break;
00453
00454 case CCZmode:
00455 if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode
00456 && req_mode != CCSRmode && req_mode != CCURmode)
00457 return 0;
00458 break;
00459
00460 case CCAPmode:
00461 case CCANmode:
00462 if (req_mode != CCAmode)
00463 return 0;
00464 break;
00465
00466 default:
00467 abort ();
00468 }
00469
00470 return (GET_MODE (SET_SRC (set)) == set_mode);
00471 }
00472
00473
00474
00475
00476
00477
00478 int
00479 s390_match_ccmode (rtx insn, enum machine_mode req_mode)
00480 {
00481 int i;
00482
00483
00484 if (req_mode == VOIDmode)
00485 return 0;
00486
00487 if (GET_CODE (PATTERN (insn)) == SET)
00488 return s390_match_ccmode_set (PATTERN (insn), req_mode);
00489
00490 if (GET_CODE (PATTERN (insn)) == PARALLEL)
00491 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
00492 {
00493 rtx set = XVECEXP (PATTERN (insn), 0, i);
00494 if (GET_CODE (set) == SET)
00495 if (!s390_match_ccmode_set (set, req_mode))
00496 return 0;
00497 }
00498
00499 return 1;
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509 enum machine_mode
00510 s390_tm_ccmode (rtx op1, rtx op2, int mixed)
00511 {
00512 int bit0, bit1;
00513
00514
00515 if (GET_CODE (op1) != CONST_INT || GET_CODE (op2) != CONST_INT)
00516 return VOIDmode;
00517
00518
00519
00520 if (INTVAL (op2) == 0)
00521 return CCTmode;
00522
00523
00524
00525 if (INTVAL (op2) == INTVAL (op1))
00526 return CCT3mode;
00527
00528
00529
00530
00531
00532 if (mixed)
00533 {
00534 bit1 = exact_log2 (INTVAL (op2));
00535 bit0 = exact_log2 (INTVAL (op1) ^ INTVAL (op2));
00536 if (bit0 != -1 && bit1 != -1)
00537 return bit0 > bit1 ? CCT1mode : CCT2mode;
00538 }
00539
00540 return VOIDmode;
00541 }
00542
00543
00544
00545
00546
00547 enum machine_mode
00548 s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
00549 {
00550 switch (code)
00551 {
00552 case EQ:
00553 case NE:
00554 if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS)
00555 && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
00556 return CCAPmode;
00557 if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
00558 && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))
00559 return CCAPmode;
00560 if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
00561 || GET_CODE (op1) == NEG)
00562 && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
00563 return CCLmode;
00564
00565 if (GET_CODE (op0) == AND)
00566 {
00567
00568 enum machine_mode ccmode;
00569 ccmode = s390_tm_ccmode (XEXP (op0, 1), op1, 1);
00570 if (ccmode != VOIDmode)
00571 {
00572
00573
00574 return ccmode == CCTmode ? CCZmode : ccmode;
00575 }
00576 }
00577
00578 if (register_operand (op0, HImode)
00579 && GET_CODE (op1) == CONST_INT
00580 && (INTVAL (op1) == -1 || INTVAL (op1) == 65535))
00581 return CCT3mode;
00582 if (register_operand (op0, QImode)
00583 && GET_CODE (op1) == CONST_INT
00584 && (INTVAL (op1) == -1 || INTVAL (op1) == 255))
00585 return CCT3mode;
00586
00587 return CCZmode;
00588
00589 case LE:
00590 case LT:
00591 case GE:
00592 case GT:
00593
00594
00595
00596
00597 if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS)
00598 && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
00599 return CCAPmode;
00600
00601
00602
00603
00604
00605
00606 if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
00607 && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))
00608 {
00609 if (INTVAL (XEXP((op0), 1)) < 0)
00610 return CCANmode;
00611 else
00612 return CCAPmode;
00613 }
00614
00615 case UNORDERED:
00616 case ORDERED:
00617 case UNEQ:
00618 case UNLE:
00619 case UNLT:
00620 case UNGE:
00621 case UNGT:
00622 case LTGT:
00623 if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
00624 && GET_CODE (op1) != CONST_INT)
00625 return CCSRmode;
00626 return CCSmode;
00627
00628 case LTU:
00629 case GEU:
00630 if (GET_CODE (op0) == PLUS
00631 && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
00632 return CCL1mode;
00633
00634 if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
00635 && GET_CODE (op1) != CONST_INT)
00636 return CCURmode;
00637 return CCUmode;
00638
00639 case LEU:
00640 case GTU:
00641 if (GET_CODE (op0) == MINUS
00642 && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
00643 return CCL2mode;
00644
00645 if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
00646 && GET_CODE (op1) != CONST_INT)
00647 return CCURmode;
00648 return CCUmode;
00649
00650 default:
00651 abort ();
00652 }
00653 }
00654
00655
00656
00657
00658 void
00659 s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
00660 {
00661
00662 if ((*code == EQ || *code == NE)
00663 && *op1 == const0_rtx
00664 && GET_CODE (*op0) == ZERO_EXTRACT
00665 && GET_CODE (XEXP (*op0, 1)) == CONST_INT
00666 && GET_CODE (XEXP (*op0, 2)) == CONST_INT
00667 && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))
00668 {
00669 rtx inner = XEXP (*op0, 0);
00670 HOST_WIDE_INT modesize = GET_MODE_BITSIZE (GET_MODE (inner));
00671 HOST_WIDE_INT len = INTVAL (XEXP (*op0, 1));
00672 HOST_WIDE_INT pos = INTVAL (XEXP (*op0, 2));
00673
00674 if (len > 0 && len < modesize
00675 && pos >= 0 && pos + len <= modesize
00676 && modesize <= HOST_BITS_PER_WIDE_INT)
00677 {
00678 unsigned HOST_WIDE_INT block;
00679 block = ((unsigned HOST_WIDE_INT) 1 << len) - 1;
00680 block <<= modesize - pos - len;
00681
00682 *op0 = gen_rtx_AND (GET_MODE (inner), inner,
00683 gen_int_mode (block, GET_MODE (inner)));
00684 }
00685 }
00686
00687
00688 if ((*code == EQ || *code == NE)
00689 && *op1 == const0_rtx
00690 && GET_CODE (*op0) == AND
00691 && GET_CODE (XEXP (*op0, 1)) == CONST_INT
00692 && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))
00693 {
00694 rtx inner = XEXP (*op0, 0);
00695 rtx mask = XEXP (*op0, 1);
00696
00697
00698 if (GET_CODE (inner) == SUBREG
00699 && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (inner)))
00700 && (GET_MODE_SIZE (GET_MODE (inner))
00701 >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))
00702 && ((INTVAL (mask)
00703 & GET_MODE_MASK (GET_MODE (inner))
00704 & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (inner))))
00705 == 0))
00706 inner = SUBREG_REG (inner);
00707
00708
00709 if (MEM_P (inner) && !MEM_VOLATILE_P (inner))
00710 {
00711 int part = s390_single_part (XEXP (*op0, 1),
00712 GET_MODE (inner), QImode, 0);
00713 if (part >= 0)
00714 {
00715 mask = gen_int_mode (s390_extract_part (mask, QImode, 0), QImode);
00716 inner = adjust_address_nv (inner, QImode, part);
00717 *op0 = gen_rtx_AND (QImode, inner, mask);
00718 }
00719 }
00720 }
00721
00722
00723 if ((*code == EQ || *code == NE)
00724 && GET_CODE (*op1) == CONST_INT
00725 && INTVAL (*op1) == 0xffff
00726 && SCALAR_INT_MODE_P (GET_MODE (*op0))
00727 && (nonzero_bits (*op0, GET_MODE (*op0))
00728 & ~(unsigned HOST_WIDE_INT) 0xffff) == 0)
00729 {
00730 *op0 = gen_lowpart (HImode, *op0);
00731 *op1 = constm1_rtx;
00732 }
00733
00734
00735
00736 if (GET_CODE (*op0) == UNSPEC
00737 && XINT (*op0, 1) == UNSPEC_CMPINT
00738 && XVECLEN (*op0, 0) == 1
00739 && GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode
00740 && GET_CODE (XVECEXP (*op0, 0, 0)) == REG
00741 && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM
00742 && *op1 == const0_rtx)
00743 {
00744 enum rtx_code new_code = UNKNOWN;
00745 switch (*code)
00746 {
00747 case EQ: new_code = EQ; break;
00748 case NE: new_code = NE; break;
00749 case LT: new_code = GTU; break;
00750 case GT: new_code = LTU; break;
00751 case LE: new_code = GEU; break;
00752 case GE: new_code = LEU; break;
00753 default: break;
00754 }
00755
00756 if (new_code != UNKNOWN)
00757 {
00758 *op0 = XVECEXP (*op0, 0, 0);
00759 *code = new_code;
00760 }
00761 }
00762 }
00763
00764
00765
00766
00767
00768 rtx
00769 s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
00770 {
00771 enum machine_mode mode = s390_select_ccmode (code, op0, op1);
00772 rtx cc = gen_rtx_REG (mode, CC_REGNUM);
00773
00774 emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1)));
00775 return gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);
00776 }
00777
00778
00779
00780
00781 void
00782 s390_emit_jump (rtx target, rtx cond)
00783 {
00784 rtx insn;
00785
00786 target = gen_rtx_LABEL_REF (VOIDmode, target);
00787 if (cond)
00788 target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx);
00789
00790 insn = gen_rtx_SET (VOIDmode, pc_rtx, target);
00791 emit_jump_insn (insn);
00792 }
00793
00794
00795
00796
00797 int
00798 s390_comparison (rtx op, enum machine_mode mode)
00799 {
00800 if (mode != VOIDmode && mode != GET_MODE (op))
00801 return 0;
00802
00803 if (!COMPARISON_P (op))
00804 return 0;
00805
00806 if (GET_CODE (XEXP (op, 0)) != REG
00807 || REGNO (XEXP (op, 0)) != CC_REGNUM
00808 || XEXP (op, 1) != const0_rtx)
00809 return 0;
00810
00811 return s390_branch_condition_mask (op) >= 0;
00812 }
00813
00814
00815
00816
00817 int
00818 s390_alc_comparison (rtx op, enum machine_mode mode)
00819 {
00820 if (mode != VOIDmode && mode != GET_MODE (op))
00821 return 0;
00822
00823 while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
00824 op = XEXP (op, 0);
00825
00826 if (!COMPARISON_P (op))
00827 return 0;
00828
00829 if (GET_CODE (XEXP (op, 0)) != REG
00830 || REGNO (XEXP (op, 0)) != CC_REGNUM
00831 || XEXP (op, 1) != const0_rtx)
00832 return 0;
00833
00834 switch (GET_MODE (XEXP (op, 0)))
00835 {
00836 case CCL1mode:
00837 return GET_CODE (op) == LTU;
00838
00839 case CCL2mode:
00840 return GET_CODE (op) == LEU;
00841
00842 case CCL3mode:
00843 return GET_CODE (op) == GEU;
00844
00845 case CCUmode:
00846 return GET_CODE (op) == GTU;
00847
00848 case CCURmode:
00849 return GET_CODE (op) == LTU;
00850
00851 case CCSmode:
00852 return GET_CODE (op) == UNGT;
00853
00854 case CCSRmode:
00855 return GET_CODE (op) == UNLT;
00856
00857 default:
00858 return 0;
00859 }
00860 }
00861
00862
00863
00864
00865 int
00866 s390_slb_comparison (rtx op, enum machine_mode mode)
00867 {
00868 if (mode != VOIDmode && mode != GET_MODE (op))
00869 return 0;
00870
00871 while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
00872 op = XEXP (op, 0);
00873
00874 if (!COMPARISON_P (op))
00875 return 0;
00876
00877 if (GET_CODE (XEXP (op, 0)) != REG
00878 || REGNO (XEXP (op, 0)) != CC_REGNUM
00879 || XEXP (op, 1) != const0_rtx)
00880 return 0;
00881
00882 switch (GET_MODE (XEXP (op, 0)))
00883 {
00884 case CCL1mode:
00885 return GET_CODE (op) == GEU;
00886
00887 case CCL2mode:
00888 return GET_CODE (op) == GTU;
00889
00890 case CCL3mode:
00891 return GET_CODE (op) == LTU;
00892
00893 case CCUmode:
00894 return GET_CODE (op) == LEU;
00895
00896 case CCURmode:
00897 return GET_CODE (op) == GEU;
00898
00899 case CCSmode:
00900 return GET_CODE (op) == LE;
00901
00902 case CCSRmode:
00903 return GET_CODE (op) == GE;
00904
00905 default:
00906 return 0;
00907 }
00908 }
00909
00910
00911
00912
00913 static int
00914 s390_branch_condition_mask (rtx code)
00915 {
00916 const int CC0 = 1 << 3;
00917 const int CC1 = 1 << 2;
00918 const int CC2 = 1 << 1;
00919 const int CC3 = 1 << 0;
00920
00921 if (GET_CODE (XEXP (code, 0)) != REG
00922 || REGNO (XEXP (code, 0)) != CC_REGNUM
00923 || XEXP (code, 1) != const0_rtx)
00924 abort ();
00925
00926 switch (GET_MODE (XEXP (code, 0)))
00927 {
00928 case CCZmode:
00929 switch (GET_CODE (code))
00930 {
00931 case EQ: return CC0;
00932 case NE: return CC1 | CC2 | CC3;
00933 default: return -1;
00934 }
00935 break;
00936
00937 case CCT1mode:
00938 switch (GET_CODE (code))
00939 {
00940 case EQ: return CC1;
00941 case NE: return CC0 | CC2 | CC3;
00942 default: return -1;
00943 }
00944 break;
00945
00946 case CCT2mode:
00947 switch (GET_CODE (code))
00948 {
00949 case EQ: return CC2;
00950 case NE: return CC0 | CC1 | CC3;
00951 default: return -1;
00952 }
00953 break;
00954
00955 case CCT3mode:
00956 switch (GET_CODE (code))
00957 {
00958 case EQ: return CC3;
00959 case NE: return CC0 | CC1 | CC2;
00960 default: return -1;
00961 }
00962 break;
00963
00964 case CCLmode:
00965 switch (GET_CODE (code))
00966 {
00967 case EQ: return CC0 | CC2;
00968 case NE: return CC1 | CC3;
00969 default: return -1;
00970 }
00971 break;
00972
00973 case CCL1mode:
00974 switch (GET_CODE (code))
00975 {
00976 case LTU: return CC2 | CC3;
00977 case GEU: return CC0 | CC1;
00978 default: return -1;
00979 }
00980 break;
00981
00982 case CCL2mode:
00983 switch (GET_CODE (code))
00984 {
00985 case GTU: return CC0 | CC1;
00986 case LEU: return CC2 | CC3;
00987 default: return -1;
00988 }
00989 break;
00990
00991 case CCL3mode:
00992 switch (GET_CODE (code))
00993 {
00994 case EQ: return CC0 | CC2;
00995 case NE: return CC1 | CC3;
00996 case LTU: return CC1;
00997 case GTU: return CC3;
00998 case LEU: return CC1 | CC2;
00999 case GEU: return CC2 | CC3;
01000 default: return -1;
01001 }
01002
01003 case CCUmode:
01004 switch (GET_CODE (code))
01005 {
01006 case EQ: return CC0;
01007 case NE: return CC1 | CC2 | CC3;
01008 case LTU: return CC1;
01009 case GTU: return CC2;
01010 case LEU: return CC0 | CC1;
01011 case GEU: return CC0 | CC2;
01012 default: return -1;
01013 }
01014 break;
01015
01016 case CCURmode:
01017 switch (GET_CODE (code))
01018 {
01019 case EQ: return CC0;
01020 case NE: return CC2 | CC1 | CC3;
01021 case LTU: return CC2;
01022 case GTU: return CC1;
01023 case LEU: return CC0 | CC2;
01024 case GEU: return CC0 | CC1;
01025 default: return -1;
01026 }
01027 break;
01028
01029 case CCAPmode:
01030 switch (GET_CODE (code))
01031 {
01032 case EQ: return CC0;
01033 case NE: return CC1 | CC2 | CC3;
01034 case LT: return CC1 | CC3;
01035 case GT: return CC2;
01036 case LE: return CC0 | CC1 | CC3;
01037 case GE: return CC0 | CC2;
01038 default: return -1;
01039 }
01040 break;
01041
01042 case CCANmode:
01043 switch (GET_CODE (code))
01044 {
01045 case EQ: return CC0;
01046 case NE: return CC1 | CC2 | CC3;
01047 case LT: return CC1;
01048 case GT: return CC2 | CC3;
01049 case LE: return CC0 | CC1;
01050 case GE: return CC0 | CC2 | CC3;
01051 default: return -1;
01052 }
01053 break;
01054
01055 case CCSmode:
01056 switch (GET_CODE (code))
01057 {
01058 case EQ: return CC0;
01059 case NE: return CC1 | CC2 | CC3;
01060 case LT: return CC1;
01061 case GT: return CC2;
01062 case LE: return CC0 | CC1;
01063 case GE: return CC0 | CC2;
01064 case UNORDERED: return CC3;
01065 case ORDERED: return CC0 | CC1 | CC2;
01066 case UNEQ: return CC0 | CC3;
01067 case UNLT: return CC1 | CC3;
01068 case UNGT: return CC2 | CC3;
01069 case UNLE: return CC0 | CC1 | CC3;
01070 case UNGE: return CC0 | CC2 | CC3;
01071 case LTGT: return CC1 | CC2;
01072 default: return -1;
01073 }
01074 break;
01075
01076 case CCSRmode:
01077 switch (GET_CODE (code))
01078 {
01079 case EQ: return CC0;
01080 case NE: return CC2 | CC1 | CC3;
01081 case LT: return CC2;
01082 case GT: return CC1;
01083 case LE: return CC0 | CC2;
01084 case GE: return CC0 | CC1;
01085 case UNORDERED: return CC3;
01086 case ORDERED: return CC0 | CC2 | CC1;
01087 case UNEQ: return CC0 | CC3;
01088 case UNLT: return CC2 | CC3;
01089 case UNGT: return CC1 | CC3;
01090 case UNLE: return CC0 | CC2 | CC3;
01091 case UNGE: return CC0 | CC1 | CC3;
01092 case LTGT: return CC2 | CC1;
01093 default: return -1;
01094 }
01095 break;
01096
01097 default:
01098 return -1;
01099 }
01100 }
01101
01102
01103
01104
01105
01106 static const char *
01107 s390_branch_condition_mnemonic (rtx code, int inv)
01108 {
01109 static const char *const mnemonic[16] =
01110 {
01111 NULL, "o", "h", "nle",
01112 "l", "nhe", "lh", "ne",
01113 "e", "nlh", "he", "nl",
01114 "le", "nh", "no", NULL
01115 };
01116
01117 int mask = s390_branch_condition_mask (code);
01118 gcc_assert (mask >= 0);
01119
01120 if (inv)
01121 mask ^= 15;
01122
01123 if (mask < 1 || mask > 14)
01124 abort ();
01125
01126 return mnemonic[mask];
01127 }
01128
01129
01130
01131
01132
01133
01134 unsigned HOST_WIDE_INT
01135 s390_extract_part (rtx op, enum machine_mode mode, int def)
01136 {
01137 unsigned HOST_WIDE_INT value = 0;
01138 int max_parts = HOST_BITS_PER_WIDE_INT / GET_MODE_BITSIZE (mode);
01139 int part_bits = GET_MODE_BITSIZE (mode);
01140 unsigned HOST_WIDE_INT part_mask
01141 = ((unsigned HOST_WIDE_INT)1 << part_bits) - 1;
01142 int i;
01143
01144 for (i = 0; i < max_parts; i++)
01145 {
01146 if (i == 0)
01147 value = (unsigned HOST_WIDE_INT) INTVAL (op);
01148 else
01149 value >>= part_bits;
01150
01151 if ((value & part_mask) != (def & part_mask))
01152 return value & part_mask;
01153 }
01154
01155 abort ();
01156 }
01157
01158
01159
01160
01161
01162 int
01163 s390_single_part (rtx op,
01164 enum machine_mode mode,
01165 enum machine_mode part_mode,
01166 int def)
01167 {
01168 unsigned HOST_WIDE_INT value = 0;
01169 int n_parts = GET_MODE_SIZE (mode) / GET_MODE_SIZE (part_mode);
01170 unsigned HOST_WIDE_INT part_mask
01171 = ((unsigned HOST_WIDE_INT)1 << GET_MODE_BITSIZE (part_mode)) - 1;
01172 int i, part = -1;
01173
01174 if (GET_CODE (op) != CONST_INT)
01175 return -1;
01176
01177 for (i = 0; i < n_parts; i++)
01178 {
01179 if (i == 0)
01180 value = (unsigned HOST_WIDE_INT) INTVAL (op);
01181 else
01182 value >>= GET_MODE_BITSIZE (part_mode);
01183
01184 if ((value & part_mask) != (def & part_mask))
01185 {
01186 if (part != -1)
01187 return -1;
01188 else
01189 part = i;
01190 }
01191 }
01192 return part == -1 ? -1 : n_parts - 1 - part;
01193 }
01194
01195
01196
01197
01198
01199 bool
01200 s390_split_ok_p (rtx dst, rtx src, enum machine_mode mode, int first_subword)
01201 {
01202
01203 if (FP_REG_P (src) || FP_REG_P (dst))
01204 return false;
01205
01206
01207 if (s_operand (src, mode) || s_operand (dst, mode))
01208 return false;
01209
01210
01211 if ((GET_CODE (src) == MEM && !offsettable_memref_p (src))
01212 || (GET_CODE (dst) == MEM && !offsettable_memref_p (dst)))
01213 return false;
01214
01215
01216
01217 if (register_operand (dst, mode))
01218 {
01219 rtx subreg = operand_subword (dst, first_subword, 0, mode);
01220 if (reg_overlap_mentioned_p (subreg, src))
01221 return false;
01222 }
01223
01224 return true;
01225 }
01226
01227
01228
01229
01230
01231 bool
01232 s390_offset_p (rtx mem1, rtx mem2, rtx delta)
01233 {
01234 rtx addr1, addr2, addr_delta;
01235
01236 if (GET_CODE (mem1) != MEM || GET_CODE (mem2) != MEM)
01237 return false;
01238
01239 addr1 = XEXP (mem1, 0);
01240 addr2 = XEXP (mem2, 0);
01241
01242 addr_delta = simplify_binary_operation (MINUS, Pmode, addr2, addr1);
01243 if (!addr_delta || !rtx_equal_p (addr_delta, delta))
01244 return false;
01245
01246 return true;
01247 }
01248
01249
01250
01251 void
01252 s390_expand_logical_operator (enum rtx_code code, enum machine_mode mode,
01253 rtx *operands)
01254 {
01255 enum machine_mode wmode = mode;
01256 rtx dst = operands[0];
01257 rtx src1 = operands[1];
01258 rtx src2 = operands[2];
01259 rtx op, clob, tem;
01260
01261
01262 if (!s390_logical_operator_ok_p (operands))
01263 dst = gen_reg_rtx (mode);
01264
01265
01266
01267 if ((mode == QImode || mode == HImode) && GET_CODE (dst) != MEM)
01268 wmode = SImode;
01269
01270
01271 if (mode != wmode)
01272 {
01273 if (GET_CODE (dst) == SUBREG
01274 && (tem = simplify_subreg (wmode, dst, mode, 0)) != 0)
01275 dst = tem;
01276 else if (REG_P (dst))
01277 dst = gen_rtx_SUBREG (wmode, dst, 0);
01278 else
01279 dst = gen_reg_rtx (wmode);
01280
01281 if (GET_CODE (src1) == SUBREG
01282 && (tem = simplify_subreg (wmode, src1, mode, 0)) != 0)
01283 src1 = tem;
01284 else if (GET_MODE (src1) != VOIDmode)
01285 src1 = gen_rtx_SUBREG (wmode, force_reg (mode, src1), 0);
01286
01287 if (GET_CODE (src2) == SUBREG
01288 && (tem = simplify_subreg (wmode, src2, mode, 0)) != 0)
01289 src2 = tem;
01290 else if (GET_MODE (src2) != VOIDmode)
01291 src2 = gen_rtx_SUBREG (wmode, force_reg (mode, src2), 0);
01292 }
01293
01294
01295 op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, wmode, src1, src2));
01296 clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
01297 emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
01298
01299
01300 if (dst != operands[0])
01301 emit_move_insn (operands[0], gen_lowpart (mode, dst));
01302 }
01303
01304
01305
01306 bool
01307 s390_logical_operator_ok_p (rtx *operands)
01308 {
01309
01310
01311
01312 if (GET_CODE (operands[0]) == MEM)
01313 return rtx_equal_p (operands[0], operands[1])
01314 || (!reload_completed && rtx_equal_p (operands[0], operands[2]));
01315
01316 return true;
01317 }
01318
01319
01320
01321
01322 void
01323 s390_narrow_logical_operator (enum rtx_code code, rtx *memop, rtx *immop)
01324 {
01325 int def = code == AND ? -1 : 0;
01326 HOST_WIDE_INT mask;
01327 int part;
01328
01329 gcc_assert (GET_CODE (*memop) == MEM);
01330 gcc_assert (!MEM_VOLATILE_P (*memop));
01331
01332 mask = s390_extract_part (*immop, QImode, def);
01333 part = s390_single_part (*immop, GET_MODE (*memop), QImode, def);
01334 gcc_assert (part >= 0);
01335
01336 *memop = adjust_address (*memop, QImode, part);
01337 *immop = gen_int_mode (mask, QImode);
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349 void
01350 optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
01351 {
01352
01353 flag_caller_saves = 0;
01354
01355
01356
01357 flag_asynchronous_unwind_tables = 1;
01358 }
01359
01360 void
01361 override_options (void)
01362 {
01363 int i;
01364 static struct pta
01365 {
01366 const char *const name;
01367 const enum processor_type processor;
01368 const enum processor_flags flags;
01369 }
01370 const processor_alias_table[] =
01371 {
01372 {"g5", PROCESSOR_9672_G5, PF_IEEE_FLOAT},
01373 {"g6", PROCESSOR_9672_G6, PF_IEEE_FLOAT},
01374 {"z900", PROCESSOR_2064_Z900, PF_IEEE_FLOAT | PF_ZARCH},
01375 {"z990", PROCESSOR_2084_Z990, PF_IEEE_FLOAT | PF_ZARCH
01376 | PF_LONG_DISPLACEMENT},
01377 };
01378
01379 int const pta_size = ARRAY_SIZE (processor_alias_table);
01380
01381
01382 s390_sr_alias_set = new_alias_set ();
01383
01384
01385 init_machine_status = s390_init_machine_status;
01386
01387
01388 if (!(target_flags_explicit & MASK_ZARCH))
01389 {
01390 if (TARGET_64BIT)
01391 target_flags |= MASK_ZARCH;
01392 else
01393 target_flags &= ~MASK_ZARCH;
01394 }
01395
01396
01397 if (!s390_arch_string)
01398 s390_arch_string = TARGET_ZARCH? "z900" : "g5";
01399
01400 for (i = 0; i < pta_size; i++)
01401 if (! strcmp (s390_arch_string, processor_alias_table[i].name))
01402 {
01403 s390_arch = processor_alias_table[i].processor;
01404 s390_arch_flags = processor_alias_table[i].flags;
01405 break;
01406 }
01407 if (i == pta_size)
01408 error ("Unknown cpu used in -march=%s.", s390_arch_string);
01409
01410
01411 if (!s390_tune_string)
01412 {
01413 s390_tune = s390_arch;
01414 s390_tune_flags = s390_arch_flags;
01415 s390_tune_string = s390_arch_string;
01416 }
01417 else
01418 {
01419 for (i = 0; i < pta_size; i++)
01420 if (! strcmp (s390_tune_string, processor_alias_table[i].name))
01421 {
01422 s390_tune = processor_alias_table[i].processor;
01423 s390_tune_flags = processor_alias_table[i].flags;
01424 break;
01425 }
01426 if (i == pta_size)
01427 error ("Unknown cpu used in -mtune=%s.", s390_tune_string);
01428 }
01429
01430
01431 if (TARGET_ZARCH && !(s390_arch_flags & PF_ZARCH))
01432 error ("z/Architecture mode not supported on %s.", s390_arch_string);
01433 if (TARGET_64BIT && !TARGET_ZARCH)
01434 error ("64-bit ABI not supported in ESA/390 mode.");
01435
01436
01437
01438 if (s390_tune == PROCESSOR_2084_Z990)
01439 s390_cost = &z990_cost;
01440 else
01441 s390_cost = &z900_cost;
01442
01443
01444 if (TARGET_BACKCHAIN && TARGET_PACKED_STACK && TARGET_HARD_FLOAT)
01445 error ("-mbackchain -mpacked-stack -mhard-float are not supported "
01446 "in combination.");
01447
01448 if (s390_warn_framesize_string)
01449 {
01450 if (sscanf (s390_warn_framesize_string, HOST_WIDE_INT_PRINT_DEC,
01451 &s390_warn_framesize) != 1)
01452 error ("invalid value for -mwarn-framesize");
01453 }
01454
01455 if (s390_warn_dynamicstack_string)
01456 s390_warn_dynamicstack_p = 1;
01457
01458 if (s390_stack_size_string)
01459 {
01460 if (sscanf (s390_stack_size_string, HOST_WIDE_INT_PRINT_DEC,
01461 &s390_stack_size) != 1)
01462 error ("invalid value for -mstack-size");
01463
01464 if (exact_log2 (s390_stack_size) == -1)
01465 error ("stack size must be an exact power of 2");
01466
01467 if (s390_stack_guard_string)
01468 {
01469 if (sscanf (s390_stack_guard_string, HOST_WIDE_INT_PRINT_DEC,
01470 &s390_stack_guard) != 1)
01471 error ("invalid value for -mstack-guard");
01472
01473 if (s390_stack_guard >= s390_stack_size)
01474 error ("stack size must be greater than the stack guard value");
01475
01476 if (exact_log2 (s390_stack_guard) == -1)
01477 error ("stack guard value must be an exact power of 2");
01478 }
01479 else
01480 error ("-mstack-size implies use of -mstack-guard");
01481 }
01482
01483 if (s390_stack_guard_string && !s390_stack_size_string)
01484 error ("-mstack-guard implies use of -mstack-size");
01485 }
01486
01487
01488
01489 const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
01490 { GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
01491 ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
01492 ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
01493 ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
01494 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
01495 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
01496 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
01497 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
01498 ADDR_REGS, CC_REGS, ADDR_REGS, ADDR_REGS,
01499 ACCESS_REGS, ACCESS_REGS
01500 };
01501
01502
01503
01504 static enum attr_type
01505 s390_safe_attr_type (rtx insn)
01506 {
01507 if (recog_memoized (insn) >= 0)
01508 return get_attr_type (insn);
01509 else
01510 return TYPE_NONE;
01511 }
01512
01513
01514
01515
01516
01517 int
01518 const0_operand (register rtx op, enum machine_mode mode)
01519 {
01520 return op == CONST0_RTX (mode);
01521 }
01522
01523
01524
01525
01526
01527 int
01528 consttable_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
01529 {
01530 return CONSTANT_P (op);
01531 }
01532
01533
01534
01535
01536 static int
01537 check_mode (register rtx op, enum machine_mode *mode)
01538 {
01539 if (*mode == VOIDmode)
01540 *mode = GET_MODE (op);
01541 else
01542 {
01543 if (GET_MODE (op) != VOIDmode && GET_MODE (op) != *mode)
01544 return 0;
01545 }
01546 return 1;
01547 }
01548
01549
01550
01551
01552
01553 int
01554 larl_operand (register rtx op, enum machine_mode mode)
01555 {
01556 if (! check_mode (op, &mode))
01557 return 0;
01558
01559
01560 if (GET_CODE (op) == LABEL_REF)
01561 return 1;
01562 if (GET_CODE (op) == SYMBOL_REF)
01563 return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
01564 && SYMBOL_REF_TLS_MODEL (op) == 0
01565 && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
01566
01567
01568 if (GET_CODE (op) != CONST)
01569 return 0;
01570 op = XEXP (op, 0);
01571
01572
01573 if (GET_CODE (op) == PLUS)
01574 {
01575 if (GET_CODE (XEXP (op, 1)) != CONST_INT
01576 || (INTVAL (XEXP (op, 1)) & 1) != 0)
01577 return 0;
01578 #if HOST_BITS_PER_WIDE_INT > 32
01579 if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 32
01580 || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 32))
01581 return 0;
01582 #endif
01583 op = XEXP (op, 0);
01584 }
01585
01586
01587 if (GET_CODE (op) == LABEL_REF)
01588 return 1;
01589 if (GET_CODE (op) == SYMBOL_REF)
01590 return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
01591 && SYMBOL_REF_TLS_MODEL (op) == 0
01592 && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
01593
01594
01595
01596 if (GET_CODE (op) == UNSPEC
01597 && XINT (op, 1) == UNSPEC_GOTENT)
01598 return 1;
01599 if (GET_CODE (op) == UNSPEC
01600 && XINT (op, 1) == UNSPEC_PLT)
01601 return 1;
01602 if (GET_CODE (op) == UNSPEC
01603 && XINT (op, 1) == UNSPEC_INDNTPOFF)
01604 return 1;
01605
01606 return 0;
01607 }
01608
01609
01610
01611
01612
01613 int
01614 s_operand (rtx op, enum machine_mode mode)
01615 {
01616 struct s390_address addr;
01617
01618
01619
01620 if (!general_operand (op, mode))
01621 return 0;
01622
01623
01624
01625 if (reload_completed
01626 && GET_CODE (op) == SUBREG
01627 && GET_CODE (SUBREG_REG (op)) == MEM)
01628 op = SUBREG_REG (op);
01629
01630 if (GET_CODE (op) != MEM)
01631 return 0;
01632 if (!s390_decompose_address (XEXP (op, 0), &addr))
01633 return 0;
01634 if (addr.indx)
01635 return 0;
01636
01637 return 1;
01638 }
01639
01640
01641
01642
01643
01644 int
01645 shift_count_operand (rtx op, enum machine_mode mode)
01646 {
01647 HOST_WIDE_INT offset = 0;
01648
01649 if (! check_mode (op, &mode))
01650 return 0;
01651
01652
01653
01654
01655
01656 if (GET_CODE (op) == CONST_INT)
01657 {
01658 offset = INTVAL (op);
01659 op = NULL_RTX;
01660 }
01661 if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
01662 {
01663 offset = INTVAL (XEXP (op, 1));
01664 op = XEXP (op, 0);
01665 }
01666 while (op && GET_CODE (op) == SUBREG)
01667 op = SUBREG_REG (op);
01668 if (op && GET_CODE (op) != REG)
01669 return 0;
01670
01671
01672
01673 if (!DISP_IN_RANGE (offset))
01674 return 0;
01675
01676 return 1;
01677 }
01678
01679
01680
01681 static int
01682 s390_short_displacement (rtx disp)
01683 {
01684
01685 if (!disp)
01686 return 1;
01687
01688
01689 if (GET_CODE (disp) == CONST_INT)
01690 return INTVAL (disp) >= 0 && INTVAL (disp) < 4096;
01691
01692
01693 if (GET_CODE (disp) == CONST
01694 && GET_CODE (XEXP (disp, 0)) == UNSPEC
01695 && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT
01696 || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF))
01697 return 0;
01698
01699
01700
01701 if (GET_CODE (disp) == CONST)
01702 return 1;
01703
01704 return 0;
01705 }
01706
01707
01708
01709 int
01710 s390_extra_constraint_str (rtx op, int c, const char * str)
01711 {
01712 struct s390_address addr;
01713
01714 if (c != str[0])
01715 abort ();
01716
01717
01718 if (c == 'A')
01719 {
01720
01721 if (!MEM_P (op) || MEM_VOLATILE_P (op))
01722 return 0;
01723
01724 if ((reload_completed || reload_in_progress)
01725 ? !offsettable_memref_p (op)
01726 : !offsettable_nonstrict_memref_p (op))
01727 return 0;
01728
01729 c = str[1];
01730 }
01731
01732
01733 else if (c == 'B')
01734 {
01735 if (GET_CODE (op) != MEM)
01736 return 0;
01737 if (!s390_decompose_address (XEXP (op, 0), &addr))
01738 return 0;
01739 if (addr.base && REG_P (addr.base) && REGNO (addr.base) == BASE_REGNUM)
01740 return 0;
01741 if (addr.indx && REG_P (addr.indx) && REGNO (addr.indx) == BASE_REGNUM)
01742 return 0;
01743
01744 c = str[1];
01745 }
01746
01747 switch (c)
01748 {
01749 case 'Q':
01750 if (GET_CODE (op) != MEM)
01751 return 0;
01752 if (!s390_decompose_address (XEXP (op, 0), &addr))
01753 return 0;
01754 if (addr.indx)
01755 return 0;
01756
01757 if (TARGET_LONG_DISPLACEMENT)
01758 {
01759 if (!s390_short_displacement (addr.disp))
01760 return 0;
01761 }
01762 break;
01763
01764 case 'R':
01765 if (GET_CODE (op) != MEM)
01766 return 0;
01767
01768 if (TARGET_LONG_DISPLACEMENT)
01769 {
01770 if (!s390_decompose_address (XEXP (op, 0), &addr))
01771 return 0;
01772 if (!s390_short_displacement (addr.disp))
01773 return 0;
01774 }
01775 break;
01776
01777 case 'S':
01778 if (!TARGET_LONG_DISPLACEMENT)
01779 return 0;
01780 if (GET_CODE (op) != MEM)
01781 return 0;
01782 if (!s390_decompose_address (XEXP (op, 0), &addr))
01783 return 0;
01784 if (addr.indx)
01785 return 0;
01786 if (s390_short_displacement (addr.disp))
01787 return 0;
01788 break;
01789
01790 case 'T':
01791 if (!TARGET_LONG_DISPLACEMENT)
01792 return 0;
01793 if (GET_CODE (op) != MEM)
01794 return 0;
01795
01796
01797 if (s390_decompose_address (XEXP (op, 0), &addr)
01798 && s390_short_displacement (addr.disp))
01799 return 0;
01800 break;
01801
01802 case 'U':
01803 if (TARGET_LONG_DISPLACEMENT)
01804 {
01805 if (!s390_decompose_address (op, &addr))
01806 return 0;
01807 if (!s390_short_displacement (addr.disp))
01808 return 0;
01809 }
01810 break;
01811
01812 case 'W':
01813 if (!TARGET_LONG_DISPLACEMENT)
01814 return 0;
01815
01816
01817 if (s390_decompose_address (op, &addr)
01818 && s390_short_displacement (addr.disp))
01819 return 0;
01820 break;
01821
01822 case 'Y':
01823 return shift_count_operand (op, VOIDmode);
01824
01825 default:
01826 return 0;
01827 }
01828
01829 return 1;
01830 }
01831
01832
01833
01834 int
01835 s390_const_ok_for_constraint_p (HOST_WIDE_INT value,
01836 int c,
01837 const char * str)
01838 {
01839 enum machine_mode mode, part_mode;
01840 int def;
01841 int part, part_goal;
01842
01843 if (c != str[0])
01844 abort ();
01845
01846 switch (str[0])
01847 {
01848 case 'I':
01849 return (unsigned int)value < 256;
01850
01851 case 'J':
01852 return (unsigned int)value < 4096;
01853
01854 case 'K':
01855 return value >= -32768 && value < 32768;
01856
01857 case 'L':
01858 return (TARGET_LONG_DISPLACEMENT ?
01859 (value >= -524288 && value <= 524287)
01860 : (value >= 0 && value <= 4095));
01861 case 'M':
01862 return value == 2147483647;
01863
01864 case 'N':
01865 if (str[1] == 'x')
01866 part_goal = -1;
01867 else
01868 part_goal = str[1] - '0';
01869
01870 switch (str[2])
01871 {
01872 case 'Q': part_mode = QImode; break;
01873 case 'H': part_mode = HImode; break;
01874 case 'S': part_mode = SImode; break;
01875 default: return 0;
01876 }
01877
01878 switch (str[3])
01879 {
01880 case 'H': mode = HImode; break;
01881 case 'S': mode = SImode; break;
01882 case 'D': mode = DImode; break;
01883 default: return 0;
01884 }
01885
01886 switch (str[4])
01887 {
01888 case '0': def = 0; break;
01889 case 'F': def = -1; break;
01890 default: return 0;
01891 }
01892
01893 if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (part_mode))
01894 return 0;
01895
01896 part = s390_single_part (GEN_INT (value), mode, part_mode, def);
01897 if (part < 0)
01898 return 0;
01899 if (part_goal != -1 && part_goal != part)
01900 return 0;
01901
01902 break;
01903
01904 default:
01905 return 0;
01906 }
01907
01908 return 1;
01909 }
01910
01911
01912
01913
01914
01915
01916
01917 static bool
01918 s390_rtx_costs (rtx x, int code, int outer_code, int *total)
01919 {
01920 switch (code)
01921 {
01922 case CONST:
01923 case CONST_INT:
01924 case LABEL_REF:
01925 case SYMBOL_REF:
01926 case CONST_DOUBLE:
01927 case MEM:
01928 *total = 0;
01929 return true;
01930
01931 case ASHIFT:
01932 case ASHIFTRT:
01933 case LSHIFTRT:
01934 case ROTATE:
01935 case ROTATERT:
01936 case AND:
01937 case IOR:
01938 case XOR:
01939 case NEG:
01940 case NOT:
01941 *total = COSTS_N_INSNS (1);
01942 return false;
01943
01944 case PLUS:
01945 case MINUS:
01946
01947 if ((GET_MODE (x) == DFmode || GET_MODE (x) == SFmode)
01948 && GET_CODE (XEXP (x, 0)) == MULT
01949 && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD)
01950 {
01951
01952 if (GET_MODE (x) == DFmode)
01953 *total = s390_cost->madbr;
01954 else
01955 *total = s390_cost->maebr;
01956 *total += rtx_cost (XEXP (XEXP (x, 0), 0), MULT)
01957 + rtx_cost (XEXP (XEXP (x, 0), 1), MULT)
01958 + rtx_cost (XEXP (x, 1), code);
01959 return true;
01960 }
01961 *total = COSTS_N_INSNS (1);
01962 return false;
01963
01964 case MULT:
01965 switch (GET_MODE (x))
01966 {
01967 case SImode:
01968 {
01969 rtx left = XEXP (x, 0);
01970 rtx right = XEXP (x, 1);
01971 if (GET_CODE (right) == CONST_INT
01972 && CONST_OK_FOR_CONSTRAINT_P (INTVAL (right), 'K', "K"))
01973 *total = s390_cost->mhi;
01974 else if (GET_CODE (left) == SIGN_EXTEND)
01975 *total = s390_cost->mh;
01976 else
01977 *total = s390_cost->ms;
01978 break;
01979 }
01980 case DImode:
01981 {
01982 rtx left = XEXP (x, 0);
01983 rtx right = XEXP (x, 1);
01984 if (TARGET_64BIT)
01985 {
01986 if (GET_CODE (right) == CONST_INT
01987 && CONST_OK_FOR_CONSTRAINT_P (INTVAL (right), 'K', "K"))
01988 *total = s390_cost->mghi;
01989 else if (GET_CODE (left) == SIGN_EXTEND)
01990 *total = s390_cost->msgf;
01991 else
01992 *total = s390_cost->msg;
01993 }
01994 else
01995 {
01996 if (GET_CODE (left) == SIGN_EXTEND
01997 && GET_CODE (right) == SIGN_EXTEND)
01998
01999 *total = s390_cost->m;
02000 else if (GET_CODE (left) == ZERO_EXTEND
02001 && GET_CODE (right) == ZERO_EXTEND
02002 && TARGET_CPU_ZARCH)
02003
02004 *total = s390_cost->ml;
02005 else
02006
02007 *total = COSTS_N_INSNS (40);
02008 }
02009 break;
02010 }
02011 case SFmode:
02012 case DFmode:
02013 *total = s390_cost->mult_df;
02014 break;
02015 default:
02016 return false;
02017 }
02018 return false;
02019
02020 case UDIV:
02021 case UMOD:
02022 if (GET_MODE (x) == TImode)
02023 *total = s390_cost->dlgr;
02024 else if (GET_MODE (x) == DImode)
02025 {
02026 rtx right = XEXP (x, 1);
02027 if (GET_CODE (right) == ZERO_EXTEND)
02028 *total = s390_cost->dlr;
02029 else
02030 *total = s390_cost->dlgr;
02031 }
02032 else if (GET_MODE (x) == SImode)
02033 *total = s390_cost->dlr;
02034 return false;
02035
02036 case DIV:
02037 case MOD:
02038 if (GET_MODE (x) == DImode)
02039 {
02040 rtx right = XEXP (x, 1);
02041 if (GET_CODE (right) == ZERO_EXTEND)
02042 if (TARGET_64BIT)
02043 *total = s390_cost->dsgfr;
02044 else
02045 *total = s390_cost->dr;
02046 else
02047 *total = s390_cost->dsgr;
02048 }
02049 else if (GET_MODE (x) == SImode)
02050 *total = s390_cost->dlr;
02051 else if (GET_MODE (x) == SFmode)
02052 {
02053 if (TARGET_IEEE_FLOAT)
02054 *total = s390_cost->debr;
02055 else
02056 *total = s390_cost->der;
02057 }
02058 else if (GET_MODE (x) == DFmode)
02059 {
02060 if (TARGET_IEEE_FLOAT)
02061 *total = s390_cost->ddbr;
02062 else
02063 *total = s390_cost->ddr;
02064 }
02065 return false;
02066
02067 case SQRT:
02068 if (GET_MODE (x) == SFmode)
02069 *total = s390_cost->sqebr;
02070 else
02071 *total = s390_cost->sqdbr;
02072 return false;
02073
02074 case SIGN_EXTEND:
02075 case ZERO_EXTEND:
02076 if (outer_code == MULT || outer_code == DIV || outer_code == MOD
02077 || outer_code == PLUS || outer_code == MINUS
02078 || outer_code == COMPARE)
02079 *total = 0;
02080 return false;
02081
02082 case COMPARE:
02083 *total = COSTS_N_INSNS (1);
02084 if (GET_CODE (XEXP (x, 0)) == AND
02085 && GET_CODE (XEXP (x, 1)) == CONST_INT
02086 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
02087 {
02088 rtx op0 = XEXP (XEXP (x, 0), 0);
02089 rtx op1 = XEXP (XEXP (x, 0), 1);
02090 rtx op2 = XEXP (x, 1);
02091
02092 if (memory_operand (op0, GET_MODE (op0))
02093 && s390_tm_ccmode (op1, op2, 0) != VOIDmode)
02094 return true;
02095 if (register_operand (op0, GET_MODE (op0))
02096 && s390_tm_ccmode (op1, op2, 1) != VOIDmode)
02097 return true;
02098 }
02099 return false;
02100
02101 default:
02102 return false;
02103 }
02104 }
02105
02106
02107
02108 static int
02109 s390_address_cost (rtx addr)
02110 {
02111 struct s390_address ad;
02112 if (!s390_decompose_address (addr, &ad))
02113 return 1000;
02114
02115 return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1);
02116 }
02117
02118
02119
02120
02121
02122 int
02123 bras_sym_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
02124 {
02125 register enum rtx_code code = GET_CODE (op);
02126
02127
02128 if (code == SYMBOL_REF)
02129 return 1;
02130
02131
02132 if (code == CONST
02133 && GET_CODE (XEXP (op, 0)) == UNSPEC
02134 && XINT (XEXP (op, 0), 1) == UNSPEC_PLT)
02135 return 1;
02136 return 0;
02137 }
02138
02139
02140
02141
02142 int
02143 tls_symbolic_operand (register rtx op)
02144 {
02145 if (GET_CODE (op) != SYMBOL_REF)
02146 return 0;
02147 return SYMBOL_REF_TLS_MODEL (op);
02148 }
02149
02150
02151
02152
02153
02154
02155 int
02156 load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
02157 {
02158 enum machine_mode elt_mode;
02159 int count = XVECLEN (op, 0);
02160 unsigned int dest_regno;
02161 rtx src_addr;
02162 int i, off;
02163
02164
02165
02166 if (count <= 1
02167 || GET_CODE (XVECEXP (op, 0, 0)) != SET
02168 || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
02169 || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
02170 return 0;
02171
02172 dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
02173 src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
02174 elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0)));
02175
02176
02177
02178 if (GET_CODE (src_addr) == REG)
02179 off = 0;
02180 else if (GET_CODE (src_addr) == PLUS
02181 && GET_CODE (XEXP (src_addr, 0)) == REG
02182 && GET_CODE (XEXP (src_addr, 1)) == CONST_INT)
02183 {
02184 off = INTVAL (XEXP (src_addr, 1));
02185 src_addr = XEXP (src_addr, 0);
02186 }
02187 else
02188 return 0;
02189
02190 for (i = 1; i < count; i++)
02191 {
02192 rtx elt = XVECEXP (op, 0, i);
02193
02194 if (GET_CODE (elt) != SET
02195 || GET_CODE (SET_DEST (elt)) != REG
02196 || GET_MODE (SET_DEST (elt)) != elt_mode
02197 || REGNO (SET_DEST (elt)) != dest_regno + i
02198 || GET_CODE (SET_SRC (elt)) != MEM
02199 || GET_MODE (SET_SRC (elt)) != elt_mode
02200 || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
02201 || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
02202 || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
02203 || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1))
02204 != off + i * GET_MODE_SIZE (elt_mode))
02205 return 0;
02206 }
02207
02208 return 1;
02209 }
02210
02211
02212
02213
02214
02215
02216 int
02217 store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
02218 {
02219 enum machine_mode elt_mode;
02220 int count = XVECLEN (op, 0);
02221 unsigned int src_regno;
02222 rtx dest_addr;
02223 int i, off;
02224
02225
02226 if (count <= 1
02227 || GET_CODE (XVECEXP (op, 0, 0)) != SET
02228 || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
02229 || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
02230 return 0;
02231
02232 src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
02233 dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
02234 elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0)));
02235
02236
02237
02238 if (GET_CODE (dest_addr) == REG)
02239 off = 0;
02240 else if (GET_CODE (dest_addr) == PLUS
02241 && GET_CODE (XEXP (dest_addr, 0)) == REG
02242 && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT)
02243 {
02244 off = INTVAL (XEXP (dest_addr, 1));
02245 dest_addr = XEXP (dest_addr, 0);
02246 }
02247 else
02248 return 0;
02249
02250 for (i = 1; i < count; i++)
02251 {
02252 rtx elt = XVECEXP (op, 0, i);
02253
02254 if (GET_CODE (elt) != SET
02255 || GET_CODE (SET_SRC (elt)) != REG
02256 || GET_MODE (SET_SRC (elt)) != elt_mode
02257 || REGNO (SET_SRC (elt)) != src_regno + i
02258 || GET_CODE (SET_DEST (elt)) != MEM
02259 || GET_MODE (SET_DEST (elt)) != elt_mode
02260 || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
02261 || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
02262 || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
02263 || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1))
02264 != off + i * GET_MODE_SIZE (elt_mode))
02265 return 0;
02266 }
02267 return 1;
02268 }
02269
02270
02271
02272
02273
02274
02275 void
02276 s390_split_access_reg (rtx reg, rtx *lo, rtx *hi)
02277 {
02278 gcc_assert (TARGET_64BIT);
02279 gcc_assert (ACCESS_REG_P (reg));
02280 gcc_assert (GET_MODE (reg) == DImode);
02281 gcc_assert (!(REGNO (reg) & 1));
02282
02283 *lo = gen_rtx_REG (SImode, REGNO (reg) + 1);
02284 *hi = gen_rtx_REG (SImode, REGNO (reg));
02285 }
02286
02287
02288
02289 int
02290 symbolic_reference_mentioned_p (rtx op)
02291 {
02292 register const char *fmt;
02293 register int i;
02294
02295 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
02296 return 1;
02297
02298 fmt = GET_RTX_FORMAT (GET_CODE (op));
02299 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
02300 {
02301 if (fmt[i] == 'E')
02302 {
02303 register int j;
02304
02305 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
02306 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
02307 return 1;
02308 }
02309
02310 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
02311 return 1;
02312 }
02313
02314 return 0;
02315 }
02316
02317
02318
02319 int
02320 tls_symbolic_reference_mentioned_p (rtx op)
02321 {
02322 register const char *fmt;
02323 register int i;
02324
02325 if (GET_CODE (op) == SYMBOL_REF)
02326 return tls_symbolic_operand (op);
02327
02328 fmt = GET_RTX_FORMAT (GET_CODE (op));
02329 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
02330 {
02331 if (fmt[i] == 'E')
02332 {
02333 register int j;
02334
02335 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
02336 if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
02337 return 1;
02338 }
02339
02340 else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i)))
02341 return 1;
02342 }
02343
02344 return 0;
02345 }
02346
02347
02348
02349
02350
02351
02352 int
02353 legitimate_pic_operand_p (register rtx op)
02354 {
02355
02356 if (!SYMBOLIC_CONST (op))
02357 return 1;
02358
02359
02360
02361 return 0;
02362 }
02363
02364
02365
02366
02367 int
02368 legitimate_constant_p (register rtx op)
02369 {
02370
02371 if (!SYMBOLIC_CONST (op))
02372 return 1;
02373
02374
02375 if (TARGET_CPU_ZARCH && larl_operand (op, VOIDmode))
02376 return 1;
02377
02378
02379
02380
02381 if (TLS_SYMBOLIC_CONST (op))
02382 return 0;
02383
02384
02385
02386
02387 if (flag_pic)
02388 return 1;
02389
02390
02391
02392 return 0;
02393 }
02394
02395
02396
02397
02398
02399 static bool
02400 s390_cannot_force_const_mem (rtx x)
02401 {
02402 switch (GET_CODE (x))
02403 {
02404 case CONST_INT:
02405 case CONST_DOUBLE:
02406
02407 return false;
02408
02409 case LABEL_REF:
02410
02411 return flag_pic != 0;
02412
02413 case SYMBOL_REF:
02414
02415
02416 if (tls_symbolic_operand (x))
02417 return true;
02418 else
02419 return flag_pic != 0;
02420
02421 case CONST:
02422 return s390_cannot_force_const_mem (XEXP (x, 0));
02423 case PLUS:
02424 case MINUS:
02425 return s390_cannot_force_const_mem (XEXP (x, 0))
02426 || s390_cannot_force_const_mem (XEXP (x, 1));
02427
02428 case UNSPEC:
02429 switch (XINT (x, 1))
02430 {
02431
02432 case UNSPEC_LTREL_OFFSET:
02433 case UNSPEC_GOT:
02434 case UNSPEC_GOTOFF:
02435 case UNSPEC_PLTOFF:
02436 case UNSPEC_TLSGD:
02437 case UNSPEC_TLSLDM:
02438 case UNSPEC_NTPOFF:
02439 case UNSPEC_DTPOFF:
02440 case UNSPEC_GOTNTPOFF:
02441 case UNSPEC_INDNTPOFF:
02442 return false;
02443
02444
02445
02446 case UNSPEC_INSN:
02447 return TARGET_CPU_ZARCH;
02448
02449 default:
02450 return true;
02451 }
02452 break;
02453
02454 default:
02455 abort ();
02456 }
02457 }
02458
02459
02460
02461
02462
02463
02464
02465 int
02466 legitimate_reload_constant_p (register rtx op)
02467 {
02468
02469 if (GET_CODE (op) == CONST_INT
02470 && DISP_IN_RANGE (INTVAL (op)))
02471 return 1;
02472
02473
02474 if (GET_CODE (op) == CONST_INT
02475 && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', "K"))
02476 return 1;
02477
02478
02479 if (TARGET_ZARCH
02480 && s390_single_part (op, DImode, HImode, 0) >= 0)
02481 return 1;
02482
02483
02484 if (TARGET_CPU_ZARCH
02485 && larl_operand (op, VOIDmode))
02486 return 1;
02487
02488
02489 return 0;
02490 }
02491
02492
02493
02494
02495 enum reg_class
02496 s390_preferred_reload_class (rtx op, enum reg_class class)
02497 {
02498 switch (GET_CODE (op))
02499 {
02500
02501
02502
02503 case CONST_DOUBLE:
02504 case CONST_INT:
02505 if (legitimate_reload_constant_p (op))
02506 return class;
02507 else
02508 return NO_REGS;
02509
02510
02511
02512
02513
02514 case PLUS:
02515 case LABEL_REF:
02516 case SYMBOL_REF:
02517 case CONST:
02518 if (reg_class_subset_p (ADDR_REGS, class))
02519 return ADDR_REGS;
02520 else
02521 return NO_REGS;
02522
02523 default:
02524 break;
02525 }
02526
02527 return class;
02528 }
02529
02530
02531
02532
02533
02534
02535
02536 enum reg_class
02537 s390_secondary_input_reload_class (enum reg_class class,
02538 enum machine_mode mode, rtx in)
02539 {
02540 if (s390_plus_operand (in, mode))
02541 return ADDR_REGS;
02542
02543 if (reg_classes_intersect_p (CC_REGS, class))
02544 return GENERAL_REGS;
02545
02546 return NO_REGS;
02547 }
02548
02549
02550
02551
02552
02553
02554
02555 enum reg_class
02556 s390_secondary_output_reload_class (enum reg_class class,
02557 enum machine_mode mode, rtx out)
02558 {
02559 if ((TARGET_64BIT ? mode == TImode
02560 : (mode == DImode || mode == DFmode))
02561 && reg_classes_intersect_p (GENERAL_REGS, class)
02562 && GET_CODE (out) == MEM
02563 && GET_CODE (XEXP (out, 0)) == PLUS
02564 && GET_CODE (XEXP (XEXP (out, 0), 0)) == PLUS
02565 && GET_CODE (XEXP (XEXP (out, 0), 1)) == CONST_INT
02566 && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (out, 0), 1))
02567 + GET_MODE_SIZE (mode) - 1))
02568 return ADDR_REGS;
02569
02570 if (reg_classes_intersect_p (CC_REGS, class))
02571 return GENERAL_REGS;
02572
02573 return NO_REGS;
02574 }
02575
02576
02577
02578
02579
02580
02581 int
02582 s390_plus_operand (register rtx op, enum machine_mode mode)
02583 {
02584 if (!check_mode (op, &mode) || mode != Pmode)
02585 return FALSE;
02586
02587 if (GET_CODE (op) != PLUS)
02588 return FALSE;
02589
02590 if (legitimate_la_operand_p (op))
02591 return FALSE;
02592
02593 return TRUE;
02594 }
02595
02596
02597
02598
02599
02600 void
02601 s390_expand_plus_operand (register rtx target, register rtx src,
02602 register rtx scratch)
02603 {
02604 rtx sum1, sum2;
02605 struct s390_address ad;
02606
02607
02608 if (GET_CODE (src) != PLUS || GET_MODE (src) != Pmode)
02609 abort ();
02610
02611
02612
02613
02614 sum1 = find_replacement (&XEXP (src, 0));
02615 sum2 = find_replacement (&XEXP (src, 1));
02616 src = gen_rtx_PLUS (Pmode, sum1, sum2);
02617
02618
02619 if (!s390_decompose_address (src, &ad)
02620 || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
02621 || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx)))
02622 {
02623
02624
02625 if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15)
02626 {
02627 emit_move_insn (scratch, sum1);
02628 sum1 = scratch;
02629 }
02630 if (true_regnum (sum2) < 1 || true_regnum (sum2) > 15)
02631 {
02632 emit_move_insn (scratch, sum2);
02633 sum2 = scratch;
02634 }
02635
02636
02637
02638
02639
02640 if (sum1 == scratch && sum2 == scratch)
02641 {
02642 debug_rtx (src);
02643 abort ();
02644 }
02645
02646 src = gen_rtx_PLUS (Pmode, sum1, sum2);
02647 }
02648
02649
02650
02651
02652 s390_load_address (target, src);
02653 }
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667 static int
02668 s390_decompose_address (register rtx addr, struct s390_address *out)
02669 {
02670 HOST_WIDE_INT offset = 0;
02671 rtx base = NULL_RTX;
02672 rtx indx = NULL_RTX;
02673 rtx disp = NULL_RTX;
02674 rtx orig_disp;
02675 int pointer = FALSE;
02676 int base_ptr = FALSE;
02677 int indx_ptr = FALSE;
02678
02679
02680
02681 if (GET_CODE (addr) == REG || GET_CODE (addr) == UNSPEC)
02682 base = addr;
02683
02684 else if (GET_CODE (addr) == PLUS)
02685 {
02686 rtx op0 = XEXP (addr, 0);
02687 rtx op1 = XEXP (addr, 1);
02688 enum rtx_code code0 = GET_CODE (op0);
02689 enum rtx_code code1 = GET_CODE (op1);
02690
02691 if (code0 == REG || code0 == UNSPEC)
02692 {
02693 if (code1 == REG || code1 == UNSPEC)
02694 {
02695 indx = op0;
02696 base = op1;
02697 }
02698
02699 else
02700 {
02701 base = op0;
02702 disp = op1;
02703 }
02704 }
02705
02706 else if (code0 == PLUS)
02707 {
02708 indx = XEXP (op0, 0);
02709 base = XEXP (op0, 1);
02710 disp = op1;
02711 }
02712
02713 else
02714 {
02715 return FALSE;
02716 }
02717 }
02718
02719 else
02720 disp = addr;
02721
02722
02723 orig_disp = disp;
02724 if (disp)
02725 {
02726 if (GET_CODE (disp) == CONST_INT)
02727 {
02728 offset = INTVAL (disp);
02729 disp = NULL_RTX;
02730 }
02731 else if (GET_CODE (disp) == CONST
02732 && GET_CODE (XEXP (disp, 0)) == PLUS
02733 && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
02734 {
02735 offset = INTVAL (XEXP (XEXP (disp, 0), 1));
02736 disp = XEXP (XEXP (disp, 0), 0);
02737 }
02738 }
02739
02740
02741 if (disp && GET_CODE (disp) == CONST)
02742 disp = XEXP (disp, 0);
02743
02744
02745
02746 if (disp && GET_CODE (disp) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (disp))
02747 {
02748
02749 if (!base)
02750 base = gen_rtx_REG (Pmode, BASE_REGNUM);
02751 else if (!indx)
02752 indx = gen_rtx_REG (Pmode, BASE_REGNUM);
02753 else
02754 return FALSE;
02755
02756
02757 disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
02758 UNSPEC_LTREL_OFFSET);
02759 }
02760
02761
02762 if (base)
02763 {
02764 if (GET_CODE (base) == UNSPEC)
02765 switch (XINT (base, 1))
02766 {
02767 case UNSPEC_LTREF:
02768 if (!disp)
02769 disp = gen_rtx_UNSPEC (Pmode,
02770 gen_rtvec (1, XVECEXP (base, 0, 0)),
02771 UNSPEC_LTREL_OFFSET);
02772 else
02773 return FALSE;
02774
02775 base = gen_rtx_REG (Pmode, BASE_REGNUM);
02776 break;
02777
02778 case UNSPEC_LTREL_BASE:
02779 base = gen_rtx_REG (Pmode, BASE_REGNUM);
02780 break;
02781
02782 default:
02783 return FALSE;
02784 }
02785
02786 if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
02787 return FALSE;
02788
02789 if (REGNO (base) == BASE_REGNUM
02790 || REGNO (base) == STACK_POINTER_REGNUM
02791 || REGNO (base) == FRAME_POINTER_REGNUM
02792 || ((reload_completed || reload_in_progress)
02793 && frame_pointer_needed
02794 && REGNO (base) == HARD_FRAME_POINTER_REGNUM)
02795 || REGNO (base) == ARG_POINTER_REGNUM
02796 || (flag_pic
02797 && REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
02798 pointer = base_ptr = TRUE;
02799 }
02800
02801
02802 if (indx)
02803 {
02804 if (GET_CODE (indx) == UNSPEC)
02805 switch (XINT (indx, 1))
02806 {
02807 case UNSPEC_LTREF:
02808 if (!disp)
02809 disp = gen_rtx_UNSPEC (Pmode,
02810 gen_rtvec (1, XVECEXP (indx, 0, 0)),
02811 UNSPEC_LTREL_OFFSET);
02812 else
02813 return FALSE;
02814
02815 indx = gen_rtx_REG (Pmode, BASE_REGNUM);
02816 break;
02817
02818 case UNSPEC_LTREL_BASE:
02819 indx = gen_rtx_REG (Pmode, BASE_REGNUM);
02820 break;
02821
02822 default:
02823 return FALSE;
02824 }
02825
02826 if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
02827 return FALSE;
02828
02829 if (REGNO (indx) == BASE_REGNUM
02830 || REGNO (indx) == STACK_POINTER_REGNUM
02831 || REGNO (indx) == FRAME_POINTER_REGNUM
02832 || ((reload_completed || reload_in_progress)
02833 && frame_pointer_needed
02834 && REGNO (indx) == HARD_FRAME_POINTER_REGNUM)
02835 || REGNO (indx) == ARG_POINTER_REGNUM
02836 || (flag_pic
02837 && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
02838 pointer = indx_ptr = TRUE;
02839 }
02840
02841
02842 if (base && indx && !base_ptr
02843 && (indx_ptr || (!REG_POINTER (base) && REG_POINTER (indx))))
02844 {
02845 rtx tmp = base;
02846 base = indx;
02847 indx = tmp;
02848 }
02849
02850
02851 if (!disp)
02852 {
02853
02854
02855
02856
02857
02858
02859
02860
02861
02862 if (base != arg_pointer_rtx
02863 && indx != arg_pointer_rtx
02864 && base != return_address_pointer_rtx
02865 && indx != return_address_pointer_rtx)
02866 if (!DISP_IN_RANGE (offset))
02867 return FALSE;
02868 }
02869 else
02870 {
02871
02872 pointer = TRUE;
02873
02874
02875
02876 if (GET_CODE (disp) == UNSPEC
02877 && (XINT (disp, 1) == UNSPEC_GOT
02878 || XINT (disp, 1) == UNSPEC_GOTNTPOFF)
02879 && offset == 0
02880 && flag_pic == 1)
02881 {
02882 ;
02883 }
02884
02885
02886 else if (GET_CODE (disp) == MINUS
02887 && GET_CODE (XEXP (disp, 0)) == LABEL_REF
02888 && GET_CODE (XEXP (disp, 1)) == LABEL_REF)
02889 {
02890 ;
02891 }
02892
02893
02894 else if (GET_CODE (disp) == UNSPEC
02895 && XINT (disp, 1) == UNSPEC_LTREL_OFFSET)
02896 {
02897 orig_disp = gen_rtx_CONST (Pmode, disp);
02898 if (offset)
02899 {
02900
02901
02902 rtx sym = XVECEXP (disp, 0, 0);
02903 if (offset >= GET_MODE_SIZE (get_pool_mode (sym)))
02904 return FALSE;
02905
02906 orig_disp = plus_constant (orig_disp, offset);
02907 }
02908 }
02909
02910 else
02911 return FALSE;
02912 }
02913
02914 if (!base && !indx)
02915 pointer = TRUE;
02916
02917 if (out)
02918 {
02919 out->base = base;
02920 out->indx = indx;
02921 out->disp = orig_disp;
02922 out->pointer = pointer;
02923 }
02924
02925 return TRUE;
02926 }
02927
02928
02929
02930
02931 int
02932 legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
02933 register rtx addr, int strict)
02934 {
02935 struct s390_address ad;
02936 if (!s390_decompose_address (addr, &ad))
02937 return FALSE;
02938
02939 if (strict)
02940 {
02941 if (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
02942 return FALSE;
02943 if (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx))
02944 return FALSE;
02945 }
02946 else
02947 {
02948 if (ad.base && !REG_OK_FOR_BASE_NONSTRICT_P (ad.base))
02949 return FALSE;
02950 if (ad.indx && !REG_OK_FOR_INDEX_NONSTRICT_P (ad.indx))
02951 return FALSE;
02952 }
02953
02954 return TRUE;
02955 }
02956
02957
02958
02959
02960
02961 int
02962 legitimate_la_operand_p (register rtx op)
02963 {
02964 struct s390_address addr;
02965 if (!s390_decompose_address (op, &addr))
02966 return FALSE;
02967
02968 if (TARGET_64BIT || addr.pointer)
02969 return TRUE;
02970
02971 return FALSE;
02972 }
02973
02974
02975
02976
02977 int
02978 preferred_la_operand_p (rtx op1, rtx op2)
02979 {
02980 struct s390_address addr;
02981
02982 if (op2 != const0_rtx)
02983 op1 = gen_rtx_PLUS (Pmode, op1, op2);
02984
02985 if (!s390_decompose_address (op1, &addr))
02986 return FALSE;
02987 if (addr.base && !REG_OK_FOR_BASE_STRICT_P (addr.base))
02988 return FALSE;
02989 if (addr.indx && !REG_OK_FOR_INDEX_STRICT_P (addr.indx))
02990 return FALSE;
02991
02992 if (!TARGET_64BIT && !addr.pointer)
02993 return FALSE;
02994
02995 if (addr.pointer)
02996 return TRUE;
02997
02998 if ((addr.base && REG_P (addr.base) && REG_POINTER (addr.base))
02999 || (addr.indx && REG_P (addr.indx) && REG_POINTER (addr.indx)))
03000 return TRUE;
03001
03002 return FALSE;
03003 }
03004
03005
03006
03007
03008
03009 void
03010 s390_load_address (rtx dst, rtx src)
03011 {
03012 if (TARGET_64BIT)
03013 emit_move_insn (dst, src);
03014 else
03015 emit_insn (gen_force_la_31 (dst, src));
03016 }
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036 rtx
03037 legitimize_pic_address (rtx orig, rtx reg)
03038 {
03039 rtx addr = orig;
03040 rtx new = orig;
03041 rtx base;
03042
03043 if (GET_CODE (addr) == LABEL_REF
03044 || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr)))
03045 {
03046
03047 if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode))
03048 {
03049
03050
03051
03052 }
03053 else
03054 {
03055
03056
03057 rtx temp = reg? reg : gen_reg_rtx (Pmode);
03058
03059 if (reload_in_progress || reload_completed)
03060 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03061
03062 addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
03063 addr = gen_rtx_CONST (Pmode, addr);
03064 addr = force_const_mem (Pmode, addr);
03065 emit_move_insn (temp, addr);
03066
03067 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
03068 if (reg != 0)
03069 {
03070 s390_load_address (reg, new);
03071 new = reg;
03072 }
03073 }
03074 }
03075 else if (GET_CODE (addr) == SYMBOL_REF)
03076 {
03077 if (reg == 0)
03078 reg = gen_reg_rtx (Pmode);
03079
03080 if (flag_pic == 1)
03081 {
03082
03083
03084
03085 if (reload_in_progress || reload_completed)
03086 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03087
03088 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
03089 new = gen_rtx_CONST (Pmode, new);
03090 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
03091 new = gen_const_mem (Pmode, new);
03092 emit_move_insn (reg, new);
03093 new = reg;
03094 }
03095 else if (TARGET_CPU_ZARCH)
03096 {
03097
03098
03099
03100 rtx temp = gen_reg_rtx (Pmode);
03101
03102 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
03103 new = gen_rtx_CONST (Pmode, new);
03104 emit_move_insn (temp, new);
03105
03106 new = gen_const_mem (Pmode, temp);
03107 emit_move_insn (reg, new);
03108 new = reg;
03109 }
03110 else
03111 {
03112
03113
03114
03115 rtx temp = gen_reg_rtx (Pmode);
03116
03117 if (reload_in_progress || reload_completed)
03118 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03119
03120 addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
03121 addr = gen_rtx_CONST (Pmode, addr);
03122 addr = force_const_mem (Pmode, addr);
03123 emit_move_insn (temp, addr);
03124
03125 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
03126 new = gen_const_mem (Pmode, new);
03127 emit_move_insn (reg, new);
03128 new = reg;
03129 }
03130 }
03131 else
03132 {
03133 if (GET_CODE (addr) == CONST)
03134 {
03135 addr = XEXP (addr, 0);
03136 if (GET_CODE (addr) == UNSPEC)
03137 {
03138 if (XVECLEN (addr, 0) != 1)
03139 abort ();
03140 switch (XINT (addr, 1))
03141 {
03142
03143
03144 case UNSPEC_GOTOFF:
03145 case UNSPEC_PLTOFF:
03146 new = force_const_mem (Pmode, orig);
03147 break;
03148
03149
03150 case UNSPEC_GOT:
03151 if (flag_pic == 2)
03152 new = force_const_mem (Pmode, orig);
03153 break;
03154
03155
03156 case UNSPEC_GOTENT:
03157 break;
03158
03159
03160
03161 case UNSPEC_PLT:
03162 if (!TARGET_CPU_ZARCH)
03163 {
03164 rtx temp = reg? reg : gen_reg_rtx (Pmode);
03165
03166 if (reload_in_progress || reload_completed)
03167 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03168
03169 addr = XVECEXP (addr, 0, 0);
03170 addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
03171 UNSPEC_PLTOFF);
03172 addr = gen_rtx_CONST (Pmode, addr);
03173 addr = force_const_mem (Pmode, addr);
03174 emit_move_insn (temp, addr);
03175
03176 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
03177 if (reg != 0)
03178 {
03179 s390_load_address (reg, new);
03180 new = reg;
03181 }
03182 }
03183 break;
03184
03185
03186 default:
03187 abort ();
03188 }
03189 }
03190 else if (GET_CODE (addr) != PLUS)
03191 abort ();
03192 }
03193 if (GET_CODE (addr) == PLUS)
03194 {
03195 rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
03196
03197
03198 if ((GET_CODE (op0) == LABEL_REF
03199 || (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0)))
03200 && GET_CODE (op1) == CONST_INT)
03201 {
03202 if (TARGET_CPU_ZARCH && larl_operand (op0, VOIDmode))
03203 {
03204 if (INTVAL (op1) & 1)
03205 {
03206
03207
03208 rtx temp = reg? reg : gen_reg_rtx (Pmode);
03209
03210 if (!DISP_IN_RANGE (INTVAL (op1)))
03211 {
03212 int even = INTVAL (op1) - 1;
03213 op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even));
03214 op0 = gen_rtx_CONST (Pmode, op0);
03215 op1 = const1_rtx;
03216 }
03217
03218 emit_move_insn (temp, op0);
03219 new = gen_rtx_PLUS (Pmode, temp, op1);
03220
03221 if (reg != 0)
03222 {
03223 s390_load_address (reg, new);
03224 new = reg;
03225 }
03226 }
03227 else
03228 {
03229
03230
03231 }
03232 }
03233 else
03234 {
03235
03236
03237 rtx temp = reg? reg : gen_reg_rtx (Pmode);
03238
03239 if (reload_in_progress || reload_completed)
03240 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03241
03242 addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
03243 UNSPEC_GOTOFF);
03244 addr = gen_rtx_PLUS (Pmode, addr, op1);
03245 addr = gen_rtx_CONST (Pmode, addr);
03246 addr = force_const_mem (Pmode, addr);
03247 emit_move_insn (temp, addr);
03248
03249 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
03250 if (reg != 0)
03251 {
03252 s390_load_address (reg, new);
03253 new = reg;
03254 }
03255 }
03256 }
03257
03258
03259
03260
03261 else if (GET_CODE (op0) == UNSPEC
03262 && GET_CODE (op1) == CONST_INT
03263 && XINT (op0, 1) == UNSPEC_GOTOFF)
03264 {
03265 if (XVECLEN (op0, 0) != 1)
03266 abort ();
03267
03268 new = force_const_mem (Pmode, orig);
03269 }
03270
03271
03272 else
03273 {
03274 base = legitimize_pic_address (XEXP (addr, 0), reg);
03275 new = legitimize_pic_address (XEXP (addr, 1),
03276 base == reg ? NULL_RTX : reg);
03277 if (GET_CODE (new) == CONST_INT)
03278 new = plus_constant (base, INTVAL (new));
03279 else
03280 {
03281 if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1)))
03282 {
03283 base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0));
03284 new = XEXP (new, 1);
03285 }
03286 new = gen_rtx_PLUS (Pmode, base, new);
03287 }
03288
03289 if (GET_CODE (new) == CONST)
03290 new = XEXP (new, 0);
03291 new = force_operand (new, 0);
03292 }
03293 }
03294 }
03295 return new;
03296 }
03297
03298
03299
03300 static rtx
03301 get_thread_pointer (void)
03302 {
03303 rtx tp = gen_reg_rtx (Pmode);
03304
03305 emit_move_insn (tp, gen_rtx_REG (Pmode, TP_REGNUM));
03306 mark_reg_pointer (tp, BITS_PER_WORD);
03307
03308 return tp;
03309 }
03310
03311
03312
03313
03314
03315
03316 static GTY(()) rtx s390_tls_symbol;
03317
03318 static void
03319 s390_emit_tls_call_insn (rtx result_reg, rtx tls_call)
03320 {
03321 rtx insn;
03322
03323 if (!flag_pic)
03324 abort ();
03325
03326 if (!s390_tls_symbol)
03327 s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
03328
03329 insn = s390_emit_call (s390_tls_symbol, tls_call, result_reg,
03330 gen_rtx_REG (Pmode, RETURN_REGNUM));
03331
03332 use_reg (&CALL_INSN_FUNCTION_USAGE (insn), result_reg);
03333 CONST_OR_PURE_CALL_P (insn) = 1;
03334 }
03335
03336
03337
03338
03339 static rtx
03340 legitimize_tls_address (rtx addr, rtx reg)
03341 {
03342 rtx new, tls_call, temp, base, r2, insn;
03343
03344 if (GET_CODE (addr) == SYMBOL_REF)
03345 switch (tls_symbolic_operand (addr))
03346 {
03347 case TLS_MODEL_GLOBAL_DYNAMIC:
03348 start_sequence ();
03349 r2 = gen_rtx_REG (Pmode, 2);
03350 tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_TLSGD);
03351 new = gen_rtx_CONST (Pmode, tls_call);
03352 new = force_const_mem (Pmode, new);
03353 emit_move_insn (r2, new);
03354 s390_emit_tls_call_insn (r2, tls_call);
03355 insn = get_insns ();
03356 end_sequence ();
03357
03358 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF);
03359 temp = gen_reg_rtx (Pmode);
03360 emit_libcall_block (insn, temp, r2, new);
03361
03362 new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
03363 if (reg != 0)
03364 {
03365 s390_load_address (reg, new);
03366 new = reg;
03367 }
03368 break;
03369
03370 case TLS_MODEL_LOCAL_DYNAMIC:
03371 start_sequence ();
03372 r2 = gen_rtx_REG (Pmode, 2);
03373 tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM);
03374 new = gen_rtx_CONST (Pmode, tls_call);
03375 new = force_const_mem (Pmode, new);
03376 emit_move_insn (r2, new);
03377 s390_emit_tls_call_insn (r2, tls_call);
03378 insn = get_insns ();
03379 end_sequence ();
03380
03381 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM_NTPOFF);
03382 temp = gen_reg_rtx (Pmode);
03383 emit_libcall_block (insn, temp, r2, new);
03384
03385 new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
03386 base = gen_reg_rtx (Pmode);
03387 s390_load_address (base, new);
03388
03389 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_DTPOFF);
03390 new = gen_rtx_CONST (Pmode, new);
03391 new = force_const_mem (Pmode, new);
03392 temp = gen_reg_rtx (Pmode);
03393 emit_move_insn (temp, new);
03394
03395 new = gen_rtx_PLUS (Pmode, base, temp);
03396 if (reg != 0)
03397 {
03398 s390_load_address (reg, new);
03399 new = reg;
03400 }
03401 break;
03402
03403 case TLS_MODEL_INITIAL_EXEC:
03404 if (flag_pic == 1)
03405 {
03406
03407
03408
03409 if (reload_in_progress || reload_completed)
03410 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03411
03412 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF);
03413 new = gen_rtx_CONST (Pmode, new);
03414 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
03415 new = gen_const_mem (Pmode, new);
03416 temp = gen_reg_rtx (Pmode);
03417 emit_move_insn (temp, new);
03418 }
03419 else if (TARGET_CPU_ZARCH)
03420 {
03421
03422
03423
03424 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF);
03425 new = gen_rtx_CONST (Pmode, new);
03426 temp = gen_reg_rtx (Pmode);
03427 emit_move_insn (temp, new);
03428
03429 new = gen_const_mem (Pmode, temp);
03430 temp = gen_reg_rtx (Pmode);
03431 emit_move_insn (temp, new);
03432 }
03433 else if (flag_pic)
03434 {
03435
03436
03437
03438 if (reload_in_progress || reload_completed)
03439 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03440
03441 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF);
03442 new = gen_rtx_CONST (Pmode, new);
03443 new = force_const_mem (Pmode, new);
03444 temp = gen_reg_rtx (Pmode);
03445 emit_move_insn (temp, new);
03446
03447 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
03448 new = gen_const_mem (Pmode, new);
03449
03450 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD);
03451 temp = gen_reg_rtx (Pmode);
03452 emit_insn (gen_rtx_SET (Pmode, temp, new));
03453 }
03454 else
03455 {
03456
03457
03458
03459 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF);
03460 new = gen_rtx_CONST (Pmode, new);
03461 new = force_const_mem (Pmode, new);
03462 temp = gen_reg_rtx (Pmode);
03463 emit_move_insn (temp, new);
03464
03465 new = temp;
03466 new = gen_const_mem (Pmode, new);
03467 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD);
03468 temp = gen_reg_rtx (Pmode);
03469 emit_insn (gen_rtx_SET (Pmode, temp, new));
03470 }
03471
03472 new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
03473 if (reg != 0)
03474 {
03475 s390_load_address (reg, new);
03476 new = reg;
03477 }
03478 break;
03479
03480 case TLS_MODEL_LOCAL_EXEC:
03481 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF);
03482 new = gen_rtx_CONST (Pmode, new);
03483 new = force_const_mem (Pmode, new);
03484 temp = gen_reg_rtx (Pmode);
03485 emit_move_insn (temp, new);
03486
03487 new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
03488 if (reg != 0)
03489 {
03490 s390_load_address (reg, new);
03491 new = reg;
03492 }
03493 break;
03494
03495 default:
03496 abort ();
03497 }
03498
03499 else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == UNSPEC)
03500 {
03501 switch (XINT (XEXP (addr, 0), 1))
03502 {
03503 case UNSPEC_INDNTPOFF:
03504 if (TARGET_CPU_ZARCH)
03505 new = addr;
03506 else
03507 abort ();
03508 break;
03509
03510 default:
03511 abort ();
03512 }
03513 }
03514
03515 else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
03516 && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
03517 {
03518 new = XEXP (XEXP (addr, 0), 0);
03519 if (GET_CODE (new) != SYMBOL_REF)
03520 new = gen_rtx_CONST (Pmode, new);
03521
03522 new = legitimize_tls_address (new, reg);
03523 new = plus_constant (new, INTVAL (XEXP (XEXP (addr, 0), 1)));
03524 new = force_operand (new, 0);
03525 }
03526
03527 else
03528 abort ();
03529
03530 return new;
03531 }
03532
03533
03534
03535 void
03536 emit_symbolic_move (rtx *operands)
03537 {
03538 rtx temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
03539
03540 if (GET_CODE (operands[0]) == MEM)
03541 operands[1] = force_reg (Pmode, operands[1]);
03542 else if (TLS_SYMBOLIC_CONST (operands[1]))
03543 operands[1] = legitimize_tls_address (operands[1], temp);
03544 else if (flag_pic)
03545 operands[1] = legitimize_pic_address (operands[1], temp);
03546 }
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556
03557
03558
03559 rtx
03560 legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED,
03561 enum machine_mode mode ATTRIBUTE_UNUSED)
03562 {
03563 rtx constant_term = const0_rtx;
03564
03565 if (TLS_SYMBOLIC_CONST (x))
03566 {
03567 x = legitimize_tls_address (x, 0);
03568
03569 if (legitimate_address_p (mode, x, FALSE))
03570 return x;
03571 }
03572 else if (flag_pic)
03573 {
03574 if (SYMBOLIC_CONST (x)
03575 || (GET_CODE (x) == PLUS
03576 && (SYMBOLIC_CONST (XEXP (x, 0))
03577 || SYMBOLIC_CONST (XEXP (x, 1)))))
03578 x = legitimize_pic_address (x, 0);
03579
03580 if (legitimate_address_p (mode, x, FALSE))
03581 return x;
03582 }
03583
03584 x = eliminate_constant_term (x, &constant_term);
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594 if (GET_CODE (constant_term) == CONST_INT
03595 && !TARGET_LONG_DISPLACEMENT
03596 && !DISP_IN_RANGE (INTVAL (constant_term))
03597 && !(REG_P (x) && REGNO_PTR_FRAME_P (REGNO (x))))
03598 {
03599 HOST_WIDE_INT lower = INTVAL (constant_term) & 0xfff;
03600 HOST_WIDE_INT upper = INTVAL (constant_term) ^ lower;
03601
03602 rtx temp = gen_reg_rtx (Pmode);
03603 rtx val = force_operand (GEN_INT (upper), temp);
03604 if (val != temp)
03605 emit_move_insn (temp, val);
03606
03607 x = gen_rtx_PLUS (Pmode, x, temp);
03608 constant_term = GEN_INT (lower);
03609 }
03610
03611 if (GET_CODE (x) == PLUS)
03612 {
03613 if (GET_CODE (XEXP (x, 0)) == REG)
03614 {
03615 register rtx temp = gen_reg_rtx (Pmode);
03616 register rtx val = force_operand (XEXP (x, 1), temp);
03617 if (val != temp)
03618 emit_move_insn (temp, val);
03619
03620 x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp);
03621 }
03622
03623 else if (GET_CODE (XEXP (x, 1)) == REG)
03624 {
03625 register rtx temp = gen_reg_rtx (Pmode);
03626 register rtx val = force_operand (XEXP (x, 0), temp);
03627 if (val != temp)
03628 emit_move_insn (temp, val);
03629
03630 x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1));
03631 }
03632 }
03633
03634 if (constant_term != const0_rtx)
03635 x = gen_rtx_PLUS (Pmode, x, constant_term);
03636
03637 return x;
03638 }
03639
03640
03641
03642
03643
03644
03645
03646 rtx
03647 legitimize_reload_address (rtx ad, enum machine_mode mode ATTRIBUTE_UNUSED,
03648 int opnum, int type)
03649 {
03650 if (!optimize || TARGET_LONG_DISPLACEMENT)
03651 return NULL_RTX;
03652
03653 if (GET_CODE (ad) == PLUS)
03654 {
03655 rtx tem = simplify_binary_operation (PLUS, Pmode,
03656 XEXP (ad, 0), XEXP (ad, 1));
03657 if (tem)
03658 ad = tem;
03659 }
03660
03661 if (GET_CODE (ad) == PLUS
03662 && GET_CODE (XEXP (ad, 0)) == REG
03663 && GET_CODE (XEXP (ad, 1)) == CONST_INT
03664 && !DISP_IN_RANGE (INTVAL (XEXP (ad, 1))))
03665 {
03666 HOST_WIDE_INT lower = INTVAL (XEXP (ad, 1)) & 0xfff;
03667 HOST_WIDE_INT upper = INTVAL (XEXP (ad, 1)) ^ lower;
03668 rtx cst, tem, new;
03669
03670 cst = GEN_INT (upper);
03671 if (!legitimate_reload_constant_p (cst))
03672 cst = force_const_mem (Pmode, cst);
03673
03674 tem = gen_rtx_PLUS (Pmode, XEXP (ad, 0), cst);
03675 new = gen_rtx_PLUS (Pmode, tem, GEN_INT (lower));
03676
03677 push_reload (XEXP (tem, 1), 0, &XEXP (tem, 1), 0,
03678 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
03679 opnum, (enum reload_type) type);
03680 return new;
03681 }
03682
03683 return NULL_RTX;
03684 }
03685
03686
03687
03688 void
03689 s390_expand_movmem (rtx dst, rtx src, rtx len)
03690 {
03691 if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
03692 {
03693 if (INTVAL (len) > 0)
03694 emit_insn (gen_movmem_short (dst, src, GEN_INT (INTVAL (len) - 1)));
03695 }
03696
03697 else if (TARGET_MVCLE)
03698 {
03699 emit_insn (gen_movmem_long (dst, src, convert_to_mode (Pmode, len, 1)));
03700 }
03701
03702 else
03703 {
03704 rtx dst_addr, src_addr, count, blocks, temp;
03705 rtx loop_start_label = gen_label_rtx ();
03706 rtx loop_end_label = gen_label_rtx ();
03707 rtx end_label = gen_label_rtx ();
03708 enum machine_mode mode;
03709
03710 mode = GET_MODE (len);
03711 if (mode == VOIDmode)
03712 mode = Pmode;
03713
03714 dst_addr = gen_reg_rtx (Pmode);
03715 src_addr = gen_reg_rtx (Pmode);
03716 count = gen_reg_rtx (mode);
03717 blocks = gen_reg_rtx (mode);
03718
03719 convert_move (count, len, 1);
03720 emit_cmp_and_jump_insns (count, const0_rtx,
03721 EQ, NULL_RTX, mode, 1, end_label);
03722
03723 emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
03724 emit_move_insn (src_addr, force_operand (XEXP (src, 0), NULL_RTX));
03725 dst = change_address (dst, VOIDmode, dst_addr);
03726 src = change_address (src, VOIDmode, src_addr);
03727
03728 temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
03729 if (temp != count)
03730 emit_move_insn (count, temp);
03731
03732 temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
03733 if (temp != blocks)
03734 emit_move_insn (blocks, temp);
03735
03736 emit_cmp_and_jump_insns (blocks, const0_rtx,
03737 EQ, NULL_RTX, mode, 1, loop_end_label);
03738
03739 emit_label (loop_start_label);
03740
03741 emit_insn (gen_movmem_short (dst, src, GEN_INT (255)));
03742 s390_load_address (dst_addr,
03743 gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
03744 s390_load_address (src_addr,
03745 gen_rtx_PLUS (Pmode, src_addr, GEN_INT (256)));
03746
03747 temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
03748 if (temp != blocks)
03749 emit_move_insn (blocks, temp);
03750
03751 emit_cmp_and_jump_insns (blocks, const0_rtx,
03752 EQ, NULL_RTX, mode, 1, loop_end_label);
03753
03754 emit_jump (loop_start_label);
03755 emit_label (loop_end_label);
03756
03757 emit_insn (gen_movmem_short (dst, src,
03758 convert_to_mode (Pmode, count, 1)));
03759 emit_label (end_label);
03760 }
03761 }
03762
03763
03764
03765 void
03766 s390_expand_clrmem (rtx dst, rtx len)
03767 {
03768 if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
03769 {
03770 if (INTVAL (len) > 0)
03771 emit_insn (gen_clrmem_short (dst, GEN_INT (INTVAL (len) - 1)));
03772 }
03773
03774 else if (TARGET_MVCLE)
03775 {
03776 emit_insn (gen_clrmem_long (dst, convert_to_mode (Pmode, len, 1)));
03777 }
03778
03779 else
03780 {
03781 rtx dst_addr, src_addr, count, blocks, temp;
03782 rtx loop_start_label = gen_label_rtx ();
03783 rtx loop_end_label = gen_label_rtx ();
03784 rtx end_label = gen_label_rtx ();
03785 enum machine_mode mode;
03786
03787 mode = GET_MODE (len);
03788 if (mode == VOIDmode)
03789 mode = Pmode;
03790
03791 dst_addr = gen_reg_rtx (Pmode);
03792 src_addr = gen_reg_rtx (Pmode);
03793 count = gen_reg_rtx (mode);
03794 blocks = gen_reg_rtx (mode);
03795
03796 convert_move (count, len, 1);
03797 emit_cmp_and_jump_insns (count, const0_rtx,
03798 EQ, NULL_RTX, mode, 1, end_label);
03799
03800 emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
03801 dst = change_address (dst, VOIDmode, dst_addr);
03802
03803 temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
03804 if (temp != count)
03805 emit_move_insn (count, temp);
03806
03807 temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
03808 if (temp != blocks)
03809 emit_move_insn (blocks, temp);
03810
03811 emit_cmp_and_jump_insns (blocks, const0_rtx,
03812 EQ, NULL_RTX, mode, 1, loop_end_label);
03813
03814 emit_label (loop_start_label);
03815
03816 emit_insn (gen_clrmem_short (dst, GEN_INT (255)));
03817 s390_load_address (dst_addr,
03818 gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
03819
03820 temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
03821 if (temp != blocks)
03822 emit_move_insn (blocks, temp);
03823
03824 emit_cmp_and_jump_insns (blocks, const0_rtx,
03825 EQ, NULL_RTX, mode, 1, loop_end_label);
03826
03827 emit_jump (loop_start_label);
03828 emit_label (loop_end_label);
03829
03830 emit_insn (gen_clrmem_short (dst, convert_to_mode (Pmode, count, 1)));
03831 emit_label (end_label);
03832 }
03833 }
03834
03835
03836
03837
03838 void
03839 s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
03840 {
03841 rtx ccreg = gen_rtx_REG (CCUmode, CC_REGNUM);
03842 rtx tmp;
03843
03844
03845
03846 tmp = op0; op0 = op1; op1 = tmp;
03847
03848 if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
03849 {
03850 if (INTVAL (len) > 0)
03851 {
03852 emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (INTVAL (len) - 1)));
03853 emit_insn (gen_cmpint (target, ccreg));
03854 }
03855 else
03856 emit_move_insn (target, const0_rtx);
03857 }
03858 else if (TARGET_MVCLE)
03859 {
03860 emit_insn (gen_cmpmem_long (op0, op1, convert_to_mode (Pmode, len, 1)));
03861 emit_insn (gen_cmpint (target, ccreg));
03862 }
03863 else
03864 {
03865 rtx addr0, addr1, count, blocks, temp;
03866 rtx loop_start_label = gen_label_rtx ();
03867 rtx loop_end_label = gen_label_rtx ();
03868 rtx end_label = gen_label_rtx ();
03869 enum machine_mode mode;
03870
03871 mode = GET_MODE (len);
03872 if (mode == VOIDmode)
03873 mode = Pmode;
03874
03875 addr0 = gen_reg_rtx (Pmode);
03876 addr1 = gen_reg_rtx (Pmode);
03877 count = gen_reg_rtx (mode);
03878 blocks = gen_reg_rtx (mode);
03879
03880 convert_move (count, len, 1);
03881 emit_cmp_and_jump_insns (count, const0_rtx,
03882 EQ, NULL_RTX, mode, 1, end_label);
03883
03884 emit_move_insn (addr0, force_operand (XEXP (op0, 0), NULL_RTX));
03885 emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX));
03886 op0 = change_address (op0, VOIDmode, addr0);
03887 op1 = change_address (op1, VOIDmode, addr1);
03888
03889 temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
03890 if (temp != count)
03891 emit_move_insn (count, temp);
03892
03893 temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
03894 if (temp != blocks)
03895 emit_move_insn (blocks, temp);
03896
03897 emit_cmp_and_jump_insns (blocks, const0_rtx,
03898 EQ, NULL_RTX, mode, 1, loop_end_label);
03899
03900 emit_label (loop_start_label);
03901
03902 emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255)));
03903 temp = gen_rtx_NE (VOIDmode, ccreg, const0_rtx);
03904 temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp,
03905 gen_rtx_LABEL_REF (VOIDmode, end_label), pc_rtx);
03906 temp = gen_rtx_SET (VOIDmode, pc_rtx, temp);
03907 emit_jump_insn (temp);
03908
03909 s390_load_address (addr0,
03910 gen_rtx_PLUS (Pmode, addr0, GEN_INT (256)));
03911 s390_load_address (addr1,
03912 gen_rtx_PLUS (Pmode, addr1, GEN_INT (256)));
03913
03914 temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
03915 if (temp != blocks)
03916 emit_move_insn (blocks, temp);
03917
03918 emit_cmp_and_jump_insns (blocks, const0_rtx,
03919 EQ, NULL_RTX, mode, 1, loop_end_label);
03920
03921 emit_jump (loop_start_label);
03922 emit_label (loop_end_label);
03923
03924 emit_insn (gen_cmpmem_short (op0, op1,
03925 convert_to_mode (Pmode, count, 1)));
03926 emit_label (end_label);
03927
03928 emit_insn (gen_cmpint (target, ccreg));
03929 }
03930 }
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951
03952 bool
03953 s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1,
03954 rtx dst, rtx src, rtx increment)
03955 {
03956 enum machine_mode cmp_mode;
03957 enum machine_mode cc_mode;
03958 rtx op_res;
03959 rtx insn;
03960 rtvec p;
03961
03962 if ((GET_MODE (cmp_op0) == SImode || GET_MODE (cmp_op0) == VOIDmode)
03963 && (GET_MODE (cmp_op1) == SImode || GET_MODE (cmp_op1) == VOIDmode))
03964 cmp_mode = SImode;
03965 else if ((GET_MODE (cmp_op0) == DImode || GET_MODE (cmp_op0) == VOIDmode)
03966 && (GET_MODE (cmp_op1) == DImode || GET_MODE (cmp_op1) == VOIDmode))
03967 cmp_mode = DImode;
03968 else
03969 return false;
03970
03971
03972 if (increment == const1_rtx)
03973 {
03974
03975 if (cmp_code == EQ || cmp_code == NE)
03976 {
03977 if (cmp_op1 != const0_rtx)
03978 {
03979 cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1,
03980 NULL_RTX, 0, OPTAB_WIDEN);
03981 cmp_op1 = const0_rtx;
03982 }
03983
03984 cmp_code = cmp_code == EQ ? LEU : GTU;
03985 }
03986
03987 if (cmp_code == LTU || cmp_code == LEU)
03988 {
03989 rtx tem = cmp_op0;
03990 cmp_op0 = cmp_op1;
03991 cmp_op1 = tem;
03992 cmp_code = swap_condition (cmp_code);
03993 }
03994
03995 switch (cmp_code)
03996 {
03997 case GTU:
03998 cc_mode = CCUmode;
03999 break;
04000
04001 case GEU:
04002 cc_mode = CCL3mode;
04003 break;
04004
04005 default:
04006 return false;
04007 }
04008
04009
04010 if (!register_operand (cmp_op0, cmp_mode))
04011 cmp_op0 = force_reg (cmp_mode, cmp_op0);
04012
04013 insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM),
04014 gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1));
04015
04016 if (insn_invalid_p (emit_insn (insn)))
04017 abort ();
04018
04019
04020 op_res = gen_rtx_fmt_ee (cmp_code, GET_MODE (dst),
04021 gen_rtx_REG (cc_mode, CC_REGNUM),
04022 const0_rtx);
04023
04024 if (src != const0_rtx)
04025 {
04026 if (!register_operand (src, GET_MODE (dst)))
04027 src = force_reg (GET_MODE (dst), src);
04028
04029 src = gen_rtx_PLUS (GET_MODE (dst), src, const0_rtx);
04030 op_res = gen_rtx_PLUS (GET_MODE (dst), src, op_res);
04031 }
04032
04033 p = rtvec_alloc (2);
04034 RTVEC_ELT (p, 0) =
04035 gen_rtx_SET (VOIDmode, dst, op_res);
04036 RTVEC_ELT (p, 1) =
04037 gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
04038 emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
04039
04040 return true;
04041 }
04042
04043
04044 if (increment == constm1_rtx)
04045 {
04046
04047 if (cmp_code == EQ || cmp_code == NE)
04048 {
04049 if (cmp_op1 != const0_rtx)
04050 {
04051 cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1,
04052 NULL_RTX, 0, OPTAB_WIDEN);
04053 cmp_op1 = const0_rtx;
04054 }
04055
04056 cmp_code = cmp_code == EQ ? LEU : GTU;
04057 }
04058
04059 if (cmp_code == GTU || cmp_code == GEU)
04060 {
04061 rtx tem = cmp_op0;
04062 cmp_op0 = cmp_op1;
04063 cmp_op1 = tem;
04064 cmp_code = swap_condition (cmp_code);
04065 }
04066
04067 switch (cmp_code)
04068 {
04069 case LEU:
04070 cc_mode = CCUmode;
04071 break;
04072
04073 case LTU:
04074 cc_mode = CCL3mode;
04075 break;
04076
04077 default:
04078 return false;
04079 }
04080
04081
04082 if (!register_operand (cmp_op0, cmp_mode))
04083 cmp_op0 = force_reg (cmp_mode, cmp_op0);
04084
04085 insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM),
04086 gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1));
04087
04088 if (insn_invalid_p (emit_insn (insn)))
04089 abort ();
04090
04091
04092 if (!register_operand (src, GET_MODE (dst)))
04093 src = force_reg (GET_MODE (dst), src);
04094
04095 op_res = gen_rtx_MINUS (GET_MODE (dst),
04096 gen_rtx_MINUS (GET_MODE (dst), src, const0_rtx),
04097 gen_rtx_fmt_ee (cmp_code, GET_MODE (dst),
04098 gen_rtx_REG (cc_mode, CC_REGNUM),
04099 const0_rtx));
04100 p = rtvec_alloc (2);
04101 RTVEC_ELT (p, 0) =
04102 gen_rtx_SET (VOIDmode, dst, op_res);
04103 RTVEC_ELT (p, 1) =
04104 gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
04105 emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
04106
04107 return true;
04108 }
04109
04110 return false;
04111 }
04112
04113
04114
04115
04116
04117 void
04118 s390_output_dwarf_dtprel (FILE *file, int size, rtx x)
04119 {
04120 switch (size)
04121 {
04122 case 4:
04123 fputs ("\t.long\t", file);
04124 break;
04125 case 8:
04126 fputs ("\t.quad\t", file);
04127 break;
04128 default:
04129 abort ();
04130 }
04131 output_addr_const (file, x);
04132 fputs ("@DTPOFF", file);
04133 }
04134
04135
04136
04137
04138
04139 static rtx
04140 s390_delegitimize_address (rtx orig_x)
04141 {
04142 rtx x = orig_x, y;
04143
04144 if (GET_CODE (x) != MEM)
04145 return orig_x;
04146
04147 x = XEXP (x, 0);
04148 if (GET_CODE (x) == PLUS
04149 && GET_CODE (XEXP (x, 1)) == CONST
04150 && GET_CODE (XEXP (x, 0)) == REG
04151 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
04152 {
04153 y = XEXP (XEXP (x, 1), 0);
04154 if (GET_CODE (y) == UNSPEC
04155 && XINT (y, 1) == UNSPEC_GOT)
04156 return XVECEXP (y, 0, 0);
04157 return orig_x;
04158 }
04159
04160 if (GET_CODE (x) == CONST)
04161 {
04162 y = XEXP (x, 0);
04163 if (GET_CODE (y) == UNSPEC
04164 && XINT (y, 1) == UNSPEC_GOTENT)
04165 return XVECEXP (y, 0, 0);
04166 return orig_x;
04167 }
04168
04169 return orig_x;
04170 }
04171
04172
04173
04174 static void
04175 print_shift_count_operand (FILE *file, rtx op)
04176 {
04177 HOST_WIDE_INT offset = 0;
04178
04179
04180
04181 if (GET_CODE (op) == CONST_INT)
04182 {
04183 offset = INTVAL (op);
04184 op = NULL_RTX;
04185 }
04186 if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
04187 {
04188 offset = INTVAL (XEXP (op, 1));
04189 op = XEXP (op, 0);
04190 }
04191 while (op && GET_CODE (op) == SUBREG)
04192 op = SUBREG_REG (op);
04193
04194
04195 if (op && (GET_CODE (op) != REG
04196 || REGNO (op) >= FIRST_PSEUDO_REGISTER
04197 || REGNO_REG_CLASS (REGNO (op)) != ADDR_REGS))
04198 abort ();
04199
04200
04201 fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & 63);
04202 if (op)
04203 fprintf (file, "(%s)", reg_names[REGNO (op)]);
04204 }
04205
04206
04207
04208
04209 static const char *
04210 get_some_local_dynamic_name (void)
04211 {
04212 rtx insn;
04213
04214 if (cfun->machine->some_ld_name)
04215 return cfun->machine->some_ld_name;
04216
04217 for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
04218 if (INSN_P (insn)
04219 && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
04220 return cfun->machine->some_ld_name;
04221
04222 abort ();
04223 }
04224
04225 static int
04226 get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
04227 {
04228 rtx x = *px;
04229
04230 if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
04231 {
04232 x = get_pool_constant (x);
04233 return for_each_rtx (&x, get_some_local_dynamic_name_1, 0);
04234 }
04235
04236 if (GET_CODE (x) == SYMBOL_REF
04237 && tls_symbolic_operand (x) == TLS_MODEL_LOCAL_DYNAMIC)
04238 {
04239 cfun->machine->some_ld_name = XSTR (x, 0);
04240 return 1;
04241 }
04242
04243 return 0;
04244 }
04245
04246
04247
04248
04249
04250 bool
04251 s390_output_addr_const_extra (FILE *file, rtx x)
04252 {
04253 if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 1)
04254 switch (XINT (x, 1))
04255 {
04256 case UNSPEC_GOTENT:
04257 output_addr_const (file, XVECEXP (x, 0, 0));
04258 fprintf (file, "@GOTENT");
04259 return true;
04260 case UNSPEC_GOT:
04261 output_addr_const (file, XVECEXP (x, 0, 0));
04262 fprintf (file, "@GOT");
04263 return true;
04264 case UNSPEC_GOTOFF:
04265 output_addr_const (file, XVECEXP (x, 0, 0));
04266 fprintf (file, "@GOTOFF");
04267 return true;
04268 case UNSPEC_PLT:
04269 output_addr_const (file, XVECEXP (x, 0, 0));
04270 fprintf (file, "@PLT");
04271 return true;
04272 case UNSPEC_PLTOFF:
04273 output_addr_const (file, XVECEXP (x, 0, 0));
04274 fprintf (file, "@PLTOFF");
04275 return true;
04276 case UNSPEC_TLSGD:
04277 output_addr_const (file, XVECEXP (x, 0, 0));
04278 fprintf (file, "@TLSGD");
04279 return true;
04280 case UNSPEC_TLSLDM:
04281 assemble_name (file, get_some_local_dynamic_name ());
04282 fprintf (file, "@TLSLDM");
04283 return true;
04284 case UNSPEC_DTPOFF:
04285 output_addr_const (file, XVECEXP (x, 0, 0));
04286 fprintf (file, "@DTPOFF");
04287 return true;
04288 case UNSPEC_NTPOFF:
04289 output_addr_const (file, XVECEXP (x, 0, 0));
04290 fprintf (file, "@NTPOFF");
04291 return true;
04292 case UNSPEC_GOTNTPOFF:
04293 output_addr_const (file, XVECEXP (x, 0, 0));
04294 fprintf (file, "@GOTNTPOFF");
04295 return true;
04296 case UNSPEC_INDNTPOFF:
04297 output_addr_const (file, XVECEXP (x, 0, 0));
04298 fprintf (file, "@INDNTPOFF");
04299 return true;
04300 }
04301
04302 return false;
04303 }
04304
04305
04306
04307
04308 void
04309 print_operand_address (FILE *file, rtx addr)
04310 {
04311 struct s390_address ad;
04312
04313 if (!s390_decompose_address (addr, &ad)
04314 || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
04315 || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx)))
04316 output_operand_lossage ("Cannot decompose address.");
04317
04318 if (ad.disp)
04319 output_addr_const (file, ad.disp);
04320 else
04321 fprintf (file, "0");
04322
04323 if (ad.base && ad.indx)
04324 fprintf (file, "(%s,%s)", reg_names[REGNO (ad.indx)],
04325 reg_names[REGNO (ad.base)]);
04326 else if (ad.base)
04327 fprintf (file, "(%s)", reg_names[REGNO (ad.base)]);
04328 }
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345
04346
04347
04348
04349
04350 void
04351 print_operand (FILE *file, rtx x, int code)
04352 {
04353 switch (code)
04354 {
04355 case 'C':
04356 fprintf (file, s390_branch_condition_mnemonic (x, FALSE));
04357 return;
04358
04359 case 'D':
04360 fprintf (file, s390_branch_condition_mnemonic (x, TRUE));
04361 return;
04362
04363 case 'J':
04364 if (GET_CODE (x) == SYMBOL_REF)
04365 {
04366 fprintf (file, "%s", ":tls_load:");
04367 output_addr_const (file, x);
04368 }
04369 else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
04370 {
04371 fprintf (file, "%s", ":tls_gdcall:");
04372 output_addr_const (file, XVECEXP (x, 0, 0));
04373 }
04374 else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM)
04375 {
04376 fprintf (file, "%s", ":tls_ldcall:");
04377 assemble_name (file, get_some_local_dynamic_name ());
04378 }
04379 else
04380 abort ();
04381 return;
04382
04383 case 'O':
04384 {
04385 struct s390_address ad;
04386
04387 if (GET_CODE (x) != MEM
04388 || !s390_decompose_address (XEXP (x, 0), &ad)
04389 || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
04390 || ad.indx)
04391 abort ();
04392
04393 if (ad.disp)
04394 output_addr_const (file, ad.disp);
04395 else
04396 fprintf (file, "0");
04397 }
04398 return;
04399
04400 case 'R':
04401 {
04402 struct s390_address ad;
04403
04404 if (GET_CODE (x) != MEM
04405 || !s390_decompose_address (XEXP (x, 0), &ad)
04406 || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
04407 || ad.indx)
04408 abort ();
04409
04410 if (ad.base)
04411 fprintf (file, "%s", reg_names[REGNO (ad.base)]);
04412 else
04413 fprintf (file, "0");
04414 }
04415 return;
04416
04417 case 'S':
04418 {
04419 struct s390_address ad;
04420
04421 if (GET_CODE (x) != MEM
04422 || !s390_decompose_address (XEXP (x, 0), &ad)
04423 || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
04424 || ad.indx)
04425 abort ();
04426
04427 if (ad.disp)
04428 output_addr_const (file, ad.disp);
04429 else
04430 fprintf (file, "0");
04431
04432 if (ad.base)
04433 fprintf (file, "(%s)", reg_names[REGNO (ad.base)]);
04434 }
04435 return;
04436
04437 case 'N':
04438 if (GET_CODE (x) == REG)
04439 x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1);
04440 else if (GET_CODE (x) == MEM)
04441 x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 4));
04442 else
04443 abort ();
04444 break;
04445
04446 case 'M':
04447 if (GET_CODE (x) == REG)
04448 x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1);
04449 else if (GET_CODE (x) == MEM)
04450 x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 8));
04451 else
04452 abort ();
04453 break;
04454
04455 case 'Y':
04456 print_shift_count_operand (file, x);
04457 return;
04458 }
04459
04460 switch (GET_CODE (x))
04461 {
04462 case REG:
04463 fprintf (file, "%s", reg_names[REGNO (x)]);
04464 break;
04465
04466 case MEM:
04467 output_address (XEXP (x, 0));
04468 break;
04469
04470 case CONST:
04471 case CODE_LABEL:
04472 case LABEL_REF:
04473 case SYMBOL_REF:
04474 output_addr_const (file, x);
04475 break;
04476
04477 case CONST_INT:
04478 if (code == 'b')
04479 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff);
04480 else if (code == 'x')
04481 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff);
04482 else if (code == 'h')
04483 fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000);
04484 else if (code == 'i')
04485 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
04486 s390_extract_part (x, HImode, 0));
04487 else if (code == 'j')
04488 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
04489 s390_extract_part (x, HImode, -1));
04490 else
04491 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
04492 break;
04493
04494 case CONST_DOUBLE:
04495 if (GET_MODE (x) != VOIDmode)
04496 abort ();
04497 if (code == 'b')
04498 fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xff);
04499 else if (code == 'x')
04500 fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xffff);
04501 else if (code == 'h')
04502 fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000);
04503 else
04504 abort ();
04505 break;
04506
04507 default:
04508 fatal_insn ("UNKNOWN in print_operand !?", x);
04509 break;
04510 }
04511 }
04512
04513
04514
04515
04516
04517 static bool
04518 s390_assemble_integer (rtx x, unsigned int size, int aligned_p)
04519 {
04520 if (size == 8 && aligned_p
04521 && GET_CODE (x) == CONST_INT && INTVAL (x) < INT_MIN)
04522 {
04523 fprintf (asm_out_file, "\t.quad\t" HOST_WIDE_INT_PRINT_HEX "\n",
04524 INTVAL (x));
04525 return true;
04526 }
04527 return default_assemble_integer (x, size, aligned_p);
04528 }
04529
04530
04531
04532
04533 static int
04534 reg_used_in_mem_p (int regno, rtx x)
04535 {
04536 enum rtx_code code = GET_CODE (x);
04537 int i, j;
04538 const char *fmt;
04539
04540 if (code == MEM)
04541 {
04542 if (refers_to_regno_p (regno, regno+1,
04543 XEXP (x, 0), 0))
04544 return 1;
04545 }
04546 else if (code == SET
04547 && GET_CODE (SET_DEST (x)) == PC)
04548 {
04549 if (refers_to_regno_p (regno, regno+1,
04550 SET_SRC (x), 0))
04551 return 1;
04552 }
04553
04554 fmt = GET_RTX_FORMAT (code);
04555 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
04556 {
04557 if (fmt[i] == 'e'
04558 && reg_used_in_mem_p (regno, XEXP (x, i)))
04559 return 1;
04560
04561 else if (fmt[i] == 'E')
04562 for (j = 0; j < XVECLEN (x, i); j++)
04563 if (reg_used_in_mem_p (regno, XVECEXP (x, i, j)))
04564 return 1;
04565 }
04566 return 0;
04567 }
04568
04569
04570
04571
04572 static int
04573 addr_generation_dependency_p (rtx dep_rtx, rtx insn)
04574 {
04575 rtx target, pat;
04576
04577 if (GET_CODE (dep_rtx) == INSN)
04578 dep_rtx = PATTERN (dep_rtx);
04579
04580 if (GET_CODE (dep_rtx) == SET)
04581 {
04582 target = SET_DEST (dep_rtx);
04583 if (GET_CODE (target) == STRICT_LOW_PART)
04584 target = XEXP (target, 0);
04585 while (GET_CODE (target) == SUBREG)
04586 target = SUBREG_REG (target);
04587
04588 if (GET_CODE (target) == REG)
04589 {
04590 int regno = REGNO (target);
04591
04592 if (s390_safe_attr_type (insn) == TYPE_LA)
04593 {
04594 pat = PATTERN (insn);
04595 if (GET_CODE (pat) == PARALLEL)
04596 {
04597 if (XVECLEN (pat, 0) != 2)
04598 abort();
04599 pat = XVECEXP (pat, 0, 0);
04600 }
04601 if (GET_CODE (pat) == SET)
04602 return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0);
04603 else
04604 abort();
04605 }
04606 else if (get_attr_atype (insn) == ATYPE_AGEN)
04607 return reg_used_in_mem_p (regno, PATTERN (insn));
04608 }
04609 }
04610 return 0;
04611 }
04612
04613
04614
04615 int
04616 s390_agen_dep_p (rtx dep_insn, rtx insn)
04617 {
04618 rtx dep_rtx = PATTERN (dep_insn);
04619 int i;
04620
04621 if (GET_CODE (dep_rtx) == SET
04622 && addr_generation_dependency_p (dep_rtx, insn))
04623 return 1;
04624 else if (GET_CODE (dep_rtx) == PARALLEL)
04625 {
04626 for (i = 0; i < XVECLEN (dep_rtx, 0); i++)
04627 {
04628 if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), insn))
04629 return 1;
04630 }
04631 }
04632 return 0;
04633 }
04634
04635
04636
04637
04638
04639
04640
04641
04642
04643 static int
04644 s390_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
04645 {
04646 if (! INSN_P (insn))
04647 return priority;
04648
04649 if (s390_tune != PROCESSOR_2084_Z990)
04650 return priority;
04651
04652 switch (s390_safe_attr_type (insn))
04653 {
04654 case TYPE_FSTORED:
04655 case TYPE_FSTORES:
04656 priority = priority << 3;
04657 break;
04658 case TYPE_STORE:
04659 case TYPE_STM:
04660 priority = priority << 1;
04661 break;
04662 default:
04663 break;
04664 }
04665 return priority;
04666 }
04667
04668
04669
04670 static int
04671 s390_issue_rate (void)
04672 {
04673 if (s390_tune == PROCESSOR_2084_Z990)
04674 return 3;
04675 return 1;
04676 }
04677
04678 static int
04679 s390_first_cycle_multipass_dfa_lookahead (void)
04680 {
04681 return 4;
04682 }
04683
04684
04685
04686
04687
04688 static int
04689 s390_split_branches (void)
04690 {
04691 rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
04692 int new_literal = 0;
04693 rtx insn, pat, tmp, target;
04694 rtx *label;
04695
04696
04697
04698 shorten_branches (get_insns ());
04699
04700
04701
04702 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
04703 {
04704 if (GET_CODE (insn) != JUMP_INSN)
04705 continue;
04706
04707 pat = PATTERN (insn);
04708 if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2)
04709 pat = XVECEXP (pat, 0, 0);
04710 if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx)
04711 continue;
04712
04713 if (GET_CODE (SET_SRC (pat)) == LABEL_REF)
04714 {
04715 label = &SET_SRC (pat);
04716 }
04717 else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
04718 {
04719 if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
04720 label = &XEXP (SET_SRC (pat), 1);
04721 else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF)
04722 label = &XEXP (SET_SRC (pat), 2);
04723 else
04724 continue;
04725 }
04726 else
04727 continue;
04728
04729 if (get_attr_length (insn) <= 4)
04730 continue;
04731
04732
04733
04734 cfun_frame_layout.save_return_addr_p = 1;
04735
04736 if (!flag_pic)
04737 {
04738 new_literal = 1;
04739 tmp = force_const_mem (Pmode, *label);
04740 tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
04741 INSN_ADDRESSES_NEW (tmp, -1);
04742 annotate_constant_pool_refs (&PATTERN (tmp));
04743
04744 target = temp_reg;
04745 }
04746 else
04747 {
04748 new_literal = 1;
04749 target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, *label),
04750 UNSPEC_LTREL_OFFSET);
04751 target = gen_rtx_CONST (Pmode, target);
04752 target = force_const_mem (Pmode, target);
04753 tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn);
04754 INSN_ADDRESSES_NEW (tmp, -1);
04755 annotate_constant_pool_refs (&PATTERN (tmp));
04756
04757 target = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XEXP (target, 0),
04758 cfun->machine->base_reg),
04759 UNSPEC_LTREL_BASE);
04760 target = gen_rtx_PLUS (Pmode, temp_reg, target);
04761 }
04762
04763 if (!validate_change (insn, label, target, 0))
04764 abort ();
04765 }
04766
04767 return new_literal;
04768 }
04769
04770
04771
04772
04773 static void
04774 annotate_constant_pool_refs (rtx *x)
04775 {
04776 int i, j;
04777 const char *fmt;
04778
04779 if (GET_CODE (*x) == SYMBOL_REF
04780 && CONSTANT_POOL_ADDRESS_P (*x))
04781 abort ();
04782
04783
04784 if (GET_CODE (*x) == MEM)
04785 {
04786 rtx memref = XEXP (*x, 0);
04787
04788 if (GET_CODE (memref) == SYMBOL_REF
04789 && CONSTANT_POOL_ADDRESS_P (memref))
04790 {
04791 rtx base = cfun->machine->base_reg;
04792 rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, memref, base),
04793 UNSPEC_LTREF);
04794
04795 *x = replace_equiv_address (*x, addr);
04796 return;
04797 }
04798
04799 if (GET_CODE (memref) == CONST
04800 && GET_CODE (XEXP (memref, 0)) == PLUS
04801 && GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT
04802 && GET_CODE (XEXP (XEXP (memref, 0), 0)) == SYMBOL_REF
04803 && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (memref, 0), 0)))
04804 {
04805 HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
04806 rtx sym = XEXP (XEXP (memref, 0), 0);
04807 rtx base = cfun->machine->base_reg;
04808 rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
04809 UNSPEC_LTREF);
04810
04811 *x = replace_equiv_address (*x, plus_constant (addr, off));
04812 return;
04813 }
04814 }
04815
04816
04817 if (GET_CODE (*x) == SET)
04818 {
04819 rtx addrref = SET_SRC (*x);
04820
04821 if (GET_CODE (addrref) == SYMBOL_REF
04822 && CONSTANT_POOL_ADDRESS_P (addrref))
04823 {
04824 rtx base = cfun->machine->base_reg;
04825 rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addrref, base),
04826 UNSPEC_LTREF);
04827
04828 SET_SRC (*x) = addr;
04829 return;
04830 }
04831
04832 if (GET_CODE (addrref) == CONST
04833 && GET_CODE (XEXP (addrref, 0)) == PLUS
04834 && GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT
04835 && GET_CODE (XEXP (XEXP (addrref, 0), 0)) == SYMBOL_REF
04836 && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (addrref, 0), 0)))
04837 {
04838 HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
04839 rtx sym = XEXP (XEXP (addrref, 0), 0);
04840 rtx base = cfun->machine->base_reg;
04841 rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
04842 UNSPEC_LTREF);
04843
04844 SET_SRC (*x) = plus_constant (addr, off);
04845 return;
04846 }
04847 }
04848
04849
04850 if (GET_CODE (*x) == UNSPEC
04851 && XINT (*x, 1) == UNSPEC_LTREL_BASE)
04852 {
04853 rtx base = cfun->machine->base_reg;
04854 *x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XVECEXP (*x, 0, 0), base),
04855 UNSPEC_LTREL_BASE);
04856 return;
04857 }
04858
04859 fmt = GET_RTX_FORMAT (GET_CODE (*x));
04860 for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
04861 {
04862 if (fmt[i] == 'e')
04863 {
04864 annotate_constant_pool_refs (&XEXP (*x, i));
04865 }
04866 else if (fmt[i] == 'E')
04867 {
04868 for (j = 0; j < XVECLEN (*x, i); j++)
04869 annotate_constant_pool_refs (&XVECEXP (*x, i, j));
04870 }
04871 }
04872 }
04873
04874
04875
04876
04877
04878
04879
04880
04881
04882
04883 static void
04884 find_constant_pool_ref (rtx x, rtx *ref)
04885 {
04886 int i, j;
04887 const char *fmt;
04888
04889
04890 if (GET_CODE (x) == UNSPEC
04891 && XINT (x, 1) == UNSPEC_LTREL_BASE)
04892 return;
04893
04894 if (GET_CODE (x) == UNSPEC_VOLATILE
04895 && XINT (x, 1) == UNSPECV_POOL_ENTRY)
04896 return;
04897
04898 if (GET_CODE (x) == SYMBOL_REF
04899 && CONSTANT_POOL_ADDRESS_P (x))
04900 abort ();
04901
04902 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_LTREF)
04903 {
04904 rtx sym = XVECEXP (x, 0, 0);
04905 if (GET_CODE (sym) != SYMBOL_REF
04906 || !CONSTANT_POOL_ADDRESS_P (sym))
04907 abort ();
04908
04909 if (*ref == NULL_RTX)
04910 *ref = sym;
04911 else if (*ref != sym)
04912 abort ();
04913
04914 return;
04915 }
04916
04917 fmt = GET_RTX_FORMAT (GET_CODE (x));
04918 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
04919 {
04920 if (fmt[i] == 'e')
04921 {
04922 find_constant_pool_ref (XEXP (x, i), ref);
04923 }
04924 else if (fmt[i] == 'E')
04925 {
04926 for (j = 0; j < XVECLEN (x, i); j++)
04927 find_constant_pool_ref (XVECEXP (x, i, j), ref);
04928 }
04929 }
04930 }
04931
04932
04933
04934
04935 static void
04936 replace_constant_pool_ref (rtx *x, rtx ref, rtx offset)
04937 {
04938 int i, j;
04939 const char *fmt;
04940
04941 if (*x == ref)
04942 abort ();
04943
04944 if (GET_CODE (*x) == UNSPEC
04945 && XINT (*x, 1) == UNSPEC_LTREF
04946 && XVECEXP (*x, 0, 0) == ref)
04947 {
04948 *x = gen_rtx_PLUS (Pmode, XVECEXP (*x, 0, 1), offset);
04949 return;
04950 }
04951
04952 if (GET_CODE (*x) == PLUS
04953 && GET_CODE (XEXP (*x, 1)) == CONST_INT
04954 && GET_CODE (XEXP (*x, 0)) == UNSPEC
04955 && XINT (XEXP (*x, 0), 1) == UNSPEC_LTREF
04956 && XVECEXP (XEXP (*x, 0), 0, 0) == ref)
04957 {
04958 rtx addr = gen_rtx_PLUS (Pmode, XVECEXP (XEXP (*x, 0), 0, 1), offset);
04959 *x = plus_constant (addr, INTVAL (XEXP (*x, 1)));
04960 return;
04961 }
04962
04963 fmt = GET_RTX_FORMAT (GET_CODE (*x));
04964 for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
04965 {
04966 if (fmt[i] == 'e')
04967 {
04968 replace_constant_pool_ref (&XEXP (*x, i), ref, offset);
04969 }
04970 else if (fmt[i] == 'E')
04971 {
04972 for (j = 0; j < XVECLEN (*x, i); j++)
04973 replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset);
04974 }
04975 }
04976 }
04977
04978
04979
04980
04981 static rtx
04982 find_ltrel_base (rtx x)
04983 {
04984 int i, j;
04985 const char *fmt;
04986
04987 if (GET_CODE (x) == UNSPEC
04988 && XINT (x, 1) == UNSPEC_LTREL_BASE)
04989 return XVECEXP (x, 0, 0);
04990
04991 fmt = GET_RTX_FORMAT (GET_CODE (x));
04992 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
04993 {
04994 if (fmt[i] == 'e')
04995 {
04996 rtx fnd = find_ltrel_base (XEXP (x, i));
04997 if (fnd)
04998 return fnd;
04999 }
05000 else if (fmt[i] == 'E')
05001 {
05002 for (j = 0; j < XVECLEN (x, i); j++)
05003 {
05004 rtx fnd = find_ltrel_base (XVECEXP (x, i, j));
05005 if (fnd)
05006 return fnd;
05007 }
05008 }
05009 }
05010
05011 return NULL_RTX;
05012 }
05013
05014
05015
05016 static void
05017 replace_ltrel_base (rtx *x)
05018 {
05019 int i, j;
05020 const char *fmt;
05021
05022 if (GET_CODE (*x) == UNSPEC
05023 && XINT (*x, 1) == UNSPEC_LTREL_BASE)
05024 {
05025 *x = XVECEXP (*x, 0, 1);
05026 return;
05027 }
05028
05029 fmt = GET_RTX_FORMAT (GET_CODE (*x));
05030 for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
05031 {
05032 if (fmt[i] == 'e')
05033 {
05034 replace_ltrel_base (&XEXP (*x, i));
05035 }
05036 else if (fmt[i] == 'E')
05037 {
05038 for (j = 0; j < XVECLEN (*x, i); j++)
05039 replace_ltrel_base (&XVECEXP (*x, i, j));
05040 }
05041 }
05042 }
05043
05044
05045
05046
05047
05048 #define NR_C_MODES 7
05049 enum machine_mode constant_modes[NR_C_MODES] =
05050 {
05051 TImode,
05052 DFmode, DImode,
05053 SFmode, SImode,
05054 HImode,
05055 QImode
05056 };
05057
05058 struct constant
05059 {
05060 struct constant *next;
05061 rtx value;
05062 rtx label;
05063 };
05064
05065 struct constant_pool
05066 {
05067 struct constant_pool *next;
05068 rtx first_insn;
05069 rtx pool_insn;
05070 bitmap insns;
05071
05072 struct constant *constants[NR_C_MODES];
05073 struct constant *execute;
05074 rtx label;
05075 int size;
05076 };
05077
05078 static struct constant_pool * s390_mainpool_start (void);
05079 static void s390_mainpool_finish (struct constant_pool *);
05080 static void s390_mainpool_cancel (struct constant_pool *);
05081
05082 static struct constant_pool * s390_chunkify_start (void);
05083 static void s390_chunkify_finish (struct constant_pool *);
05084 static void s390_chunkify_cancel (struct constant_pool *);
05085
05086 static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
05087 static void s390_end_pool (struct constant_pool *, rtx);
05088 static void s390_add_pool_insn (struct constant_pool *, rtx);
05089 static struct constant_pool *s390_find_pool (struct constant_pool *, rtx);
05090 static void s390_add_constant (struct constant_pool *, rtx, enum machine_mode);
05091 static rtx s390_find_constant (struct constant_pool *, rtx, enum machine_mode);
05092 static void s390_add_execute (struct constant_pool *, rtx);
05093 static rtx s390_find_execute (struct constant_pool *, rtx);
05094 static rtx s390_execute_label (rtx);
05095 static rtx s390_execute_target (rtx);
05096 static void s390_dump_pool (struct constant_pool *, bool);
05097 static void s390_dump_execute (struct constant_pool *);
05098 static struct constant_pool *s390_alloc_pool (void);
05099 static void s390_free_pool (struct constant_pool *);
05100
05101
05102
05103
05104 static struct constant_pool *
05105 s390_start_pool (struct constant_pool **pool_list, rtx insn)
05106 {
05107 struct constant_pool *pool, **prev;
05108
05109 pool = s390_alloc_pool ();
05110 pool->first_insn = insn;
05111
05112 for (prev = pool_list; *prev; prev = &(*prev)->next)
05113 ;
05114 *prev = pool;
05115
05116 return pool;
05117 }
05118
05119
05120
05121
05122 static void
05123 s390_end_pool (struct constant_pool *pool, rtx insn)
05124 {
05125 rtx pool_size = GEN_INT (pool->size + 8 );
05126
05127 if (!insn)
05128 insn = get_last_insn ();
05129
05130 pool->pool_insn = emit_insn_after (gen_pool (pool_size), insn);
05131 INSN_ADDRESSES_NEW (pool->pool_insn, -1);
05132 }
05133
05134
05135
05136 static void
05137 s390_add_pool_insn (struct constant_pool *pool, rtx insn)
05138 {
05139 bitmap_set_bit (pool->insns, INSN_UID (insn));
05140 }
05141
05142
05143
05144 static struct constant_pool *
05145 s390_find_pool (struct constant_pool *pool_list, rtx insn)
05146 {
05147 struct constant_pool *pool;
05148
05149 for (pool = pool_list; pool; pool = pool->next)
05150 if (bitmap_bit_p (pool->insns, INSN_UID (insn)))
05151 break;
05152
05153 return pool;
05154 }
05155
05156
05157
05158 static void
05159 s390_add_constant (struct constant_pool *pool, rtx val, enum machine_mode mode)
05160 {
05161 struct constant *c;
05162 int i;
05163
05164 for (i = 0; i < NR_C_MODES; i++)
05165 if (constant_modes[i] == mode)
05166 break;
05167 if (i == NR_C_MODES)
05168 abort ();
05169
05170 for (c = pool->constants[i]; c != NULL; c = c->next)
05171 if (rtx_equal_p (val, c->value))
05172 break;
05173
05174 if (c == NULL)
05175 {
05176 c = (struct constant *) xmalloc (sizeof *c);
05177 c->value = val;
05178 c->label = gen_label_rtx ();
05179 c->next = pool->constants[i];
05180 pool->constants[i] = c;
05181 pool->size += GET_MODE_SIZE (mode);
05182 }
05183 }
05184
05185
05186
05187
05188
05189 static rtx
05190 s390_find_constant (struct constant_pool *pool, rtx val,
05191 enum machine_mode mode)
05192 {
05193 struct constant *c;
05194 rtx offset;
05195 int i;
05196
05197 for (i = 0; i < NR_C_MODES; i++)
05198 if (constant_modes[i] == mode)
05199 break;
05200 if (i == NR_C_MODES)
05201 abort ();
05202
05203 for (c = pool->constants[i]; c != NULL; c = c->next)
05204 if (rtx_equal_p (val, c->value))
05205 break;
05206
05207 if (c == NULL)
05208 abort ();
05209
05210 offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
05211 gen_rtx_LABEL_REF (Pmode, pool->label));
05212 offset = gen_rtx_CONST (Pmode, offset);
05213 return offset;
05214 }
05215
05216
05217
05218 static void
05219 s390_add_execute (struct constant_pool *pool, rtx insn)
05220 {
05221 struct constant *c;
05222
05223 for (c = pool->execute; c != NULL; c = c->next)
05224 if (INSN_UID (insn) == INSN_UID (c->value))
05225 break;
05226
05227 if (c == NULL)
05228 {
05229 rtx label = s390_execute_label (insn);
05230 gcc_assert (label);
05231
05232 c = (struct constant *) xmalloc (sizeof *c);
05233 c->value = insn;
05234 c->label = label == const0_rtx ? gen_label_rtx () : XEXP (label, 0);
05235 c->next = pool->execute;
05236 pool->execute = c;
05237 pool->size += label == const0_rtx ? 6 : 0;
05238 }
05239 }
05240
05241
05242
05243
05244
05245 static rtx
05246 s390_find_execute (struct constant_pool *pool, rtx insn)
05247 {
05248 struct constant *c;
05249 rtx offset;
05250
05251 for (c = pool->execute; c != NULL; c = c->next)
05252 if (INSN_UID (insn) == INSN_UID (c->value))
05253 break;
05254
05255 if (c == NULL)
05256 abort ();
05257
05258 offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
05259 gen_rtx_LABEL_REF (Pmode, pool->label));
05260 offset = gen_rtx_CONST (Pmode, offset);
05261 return offset;
05262 }
05263
05264
05265
05266
05267 static rtx
05268 s390_execute_label (rtx insn)
05269 {
05270 if (GET_CODE (insn) == INSN
05271 && GET_CODE (PATTERN (insn)) == PARALLEL
05272 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == UNSPEC
05273 && XINT (XVECEXP (PATTERN (insn), 0, 0), 1) == UNSPEC_EXECUTE)
05274 return XVECEXP (XVECEXP (PATTERN (insn), 0, 0), 0, 2);
05275
05276 return NULL_RTX;
05277 }
05278
05279
05280
05281 static rtx
05282 s390_execute_target (rtx insn)
05283 {
05284 rtx pattern = PATTERN (insn);
05285 gcc_assert (s390_execute_label (insn));
05286
05287 if (XVECLEN (pattern, 0) == 2)
05288 {
05289 pattern = copy_rtx (XVECEXP (pattern, 0, 1));
05290 }
05291 else
05292 {
05293 rtvec vec = rtvec_alloc (XVECLEN (pattern, 0) - 1);
05294 int i;
05295
05296 for (i = 0; i < XVECLEN (pattern, 0) - 1; i++)
05297 RTVEC_ELT (vec, i) = copy_rtx (XVECEXP (pattern, 0, i + 1));
05298
05299 pattern = gen_rtx_PARALLEL (VOIDmode, vec);
05300 }
05301
05302 return pattern;
05303 }
05304
05305
05306
05307
05308 static bool
05309 s390_cannot_copy_insn_p (rtx insn)
05310 {
05311 rtx label = s390_execute_label (insn);
05312 return label && label != const0_rtx;
05313 }
05314
05315
05316
05317
05318 static void
05319 s390_dump_pool (struct constant_pool *pool, bool remote_label)
05320 {
05321 struct constant *c;
05322 rtx insn = pool->pool_insn;
05323 int i;
05324
05325
05326 if (TARGET_CPU_ZARCH)
05327 {
05328 insn = emit_insn_after (gen_pool_section_start (), insn);
05329 INSN_ADDRESSES_NEW (insn, -1);
05330 }
05331
05332
05333 if (TARGET_CPU_ZARCH)
05334 insn = emit_insn_after (gen_pool_align (GEN_INT (8)), insn);
05335 else
05336 insn = emit_insn_after (gen_pool_align (GEN_INT (4)), insn);
05337 INSN_ADDRESSES_NEW (insn, -1);
05338
05339
05340 if (!remote_label)
05341 {
05342 insn = emit_label_after (pool->label, insn);
05343 INSN_ADDRESSES_NEW (insn, -1);
05344 }
05345
05346
05347
05348 for (i = 0; i < NR_C_MODES; i++)
05349 for (c = pool->constants[i]; c; c = c->next)
05350 {
05351
05352 rtx value = c->value;
05353 if (GET_CODE (value) == CONST
05354 && GET_CODE (XEXP (value, 0)) == UNSPEC
05355 && XINT (XEXP (value, 0), 1) == UNSPEC_LTREL_OFFSET
05356 && XVECLEN (XEXP (value, 0), 0) == 1)
05357 {
05358 value = gen_rtx_MINUS (Pmode, XVECEXP (XEXP (value, 0), 0, 0),
05359 gen_rtx_LABEL_REF (VOIDmode, pool->label));
05360 value = gen_rtx_CONST (VOIDmode, value);
05361 }
05362
05363 insn = emit_label_after (c->label, insn);
05364 INSN_ADDRESSES_NEW (insn, -1);
05365
05366 value = gen_rtx_UNSPEC_VOLATILE (constant_modes[i],
05367 gen_rtvec (1, value),
05368 UNSPECV_POOL_ENTRY);
05369 insn = emit_insn_after (value, insn);
05370 INSN_ADDRESSES_NEW (insn, -1);
05371 }
05372
05373
05374 insn = emit_insn_after (gen_pool_align (GEN_INT (2)), insn);
05375 INSN_ADDRESSES_NEW (insn, -1);
05376
05377
05378 for (c = pool->execute; c; c = c->next)
05379 {
05380 if (s390_execute_label (c->value) != const0_rtx)
05381 continue;
05382
05383 insn = emit_label_after (c->label, insn);
05384 INSN_ADDRESSES_NEW (insn, -1);
05385
05386 insn = emit_insn_after (s390_execute_target (c->value), insn);
05387 INSN_ADDRESSES_NEW (insn, -1);
05388 }
05389
05390
05391 if (TARGET_CPU_ZARCH)
05392 {
05393 insn = emit_insn_after (gen_pool_section_end (), insn);
05394 INSN_ADDRESSES_NEW (insn, -1);
05395 }
05396
05397 insn = emit_barrier_after (insn);
05398 INSN_ADDRESSES_NEW (insn, -1);
05399
05400
05401 remove_insn (pool->pool_insn);
05402
05403
05404 s390_dump_execute (pool);
05405 }
05406
05407
05408
05409
05410 static void
05411 s390_dump_execute (struct constant_pool *pool)
05412 {
05413 struct constant *c;
05414 rtx insn;
05415
05416 for (c = pool->execute; c; c = c->next)
05417 {
05418 if (s390_execute_label (c->value) == const0_rtx)
05419 continue;
05420
05421 insn = emit_label (c->label);
05422 INSN_ADDRESSES_NEW (insn, -1);
05423
05424 insn = emit_insn (s390_execute_target (c->value));
05425 INSN_ADDRESSES_NEW (insn, -1);
05426 }
05427 }
05428
05429
05430
05431 static struct constant_pool *
05432 s390_alloc_pool (void)
05433 {
05434 struct constant_pool *pool;
05435 int i;
05436
05437 pool = (struct constant_pool *) xmalloc (sizeof *pool);
05438 pool->next = NULL;
05439 for (i = 0; i < NR_C_MODES; i++)
05440 pool->constants[i] = NULL;
05441
05442 pool->execute = NULL;
05443 pool->label = gen_label_rtx ();
05444 pool->first_insn = NULL_RTX;
05445 pool->pool_insn = NULL_RTX;
05446 pool->insns = BITMAP_ALLOC (NULL);
05447 pool->size = 0;
05448
05449 return pool;
05450 }
05451
05452
05453
05454 static void
05455 s390_free_pool (struct constant_pool *pool)
05456 {
05457 struct constant *c, *next;
05458 int i;
05459
05460 for (i = 0; i < NR_C_MODES; i++)
05461 for (c = pool->constants[i]; c; c = next)
05462 {
05463 next = c->next;
05464 free (c);
05465 }
05466
05467 for (c = pool->execute; c; c = next)
05468 {
05469 next = c->next;
05470 free (c);
05471 }
05472
05473 BITMAP_FREE (pool->insns);
05474 free (pool);
05475 }
05476
05477
05478
05479
05480 static struct constant_pool *
05481 s390_mainpool_start (void)
05482 {
05483 struct constant_pool *pool;
05484 rtx insn;
05485
05486 pool = s390_alloc_pool ();
05487
05488 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
05489 {
05490 if (GET_CODE (insn) == INSN
05491 && GET_CODE (PATTERN (insn)) == SET
05492 && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE
05493 && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL)
05494 {
05495 if (pool->pool_insn)
05496 abort ();
05497 pool->pool_insn = insn;
05498 }
05499
05500 if (s390_execute_label (insn))
05501 {
05502 s390_add_execute (pool, insn);
05503 }
05504 else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
05505 {
05506 rtx pool_ref = NULL_RTX;
05507 find_constant_pool_ref (PATTERN (insn), &pool_ref);
05508 if (pool_ref)
05509 {
05510 rtx constant = get_pool_constant (pool_ref);
05511 enum machine_mode mode = get_pool_mode (pool_ref);
05512 s390_add_constant (pool, constant, mode);
05513 }
05514 }
05515 }
05516
05517 if (!pool->pool_insn && pool->size > 0)
05518 abort ();
05519
05520 if (pool->size >= 4096)
05521 {
05522
05523
05524 remove_insn (pool->pool_insn);
05525
05526 s390_free_pool (pool);
05527 pool = NULL;
05528 }
05529
05530 return pool;
05531 }
05532
05533
05534
05535
05536
05537 static void
05538 s390_mainpool_finish (struct constant_pool *pool)
05539 {
05540 rtx base_reg = cfun->machine->base_reg;
05541 rtx insn;
05542
05543
05544 if (pool->size == 0)
05545 {
05546
05547 s390_dump_execute (pool);
05548
05549
05550 cfun->machine->base_reg = NULL_RTX;
05551
05552 if (pool->pool_insn)
05553 remove_insn (pool->pool_insn);
05554 s390_free_pool (pool);
05555 return;
05556 }
05557
05558
05559 shorten_branches (get_insns ());
05560
05561
05562
05563 if (TARGET_CPU_ZARCH)
05564 {
05565 insn = gen_main_base_64 (base_reg, pool->label);
05566 insn = emit_insn_after (insn, pool->pool_insn);
05567 INSN_ADDRESSES_NEW (insn, -1);
05568 remove_insn (pool->pool_insn);
05569
05570 insn = get_last_insn ();
05571 pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
05572 INSN_ADDRESSES_NEW (pool->pool_insn, -1);
05573
05574 s390_dump_pool (pool, 0);
05575 }
05576
05577
05578
05579
05580 else if (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
05581 + pool->size + 8 < 4096)
05582 {
05583 insn = gen_main_base_31_small (base_reg, pool->label);
05584 insn = emit_insn_after (insn, pool->pool_insn);
05585 INSN_ADDRESSES_NEW (insn, -1);
05586 remove_insn (pool->pool_insn);
05587
05588 insn = emit_label_after (pool->label, insn);
05589 INSN_ADDRESSES_NEW (insn, -1);
05590
05591 insn = get_last_insn ();
05592 pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
05593 INSN_ADDRESSES_NEW (pool->pool_insn, -1);
05594
05595 s390_dump_pool (pool, 1);
05596 }
05597
05598
05599
05600 else
05601 {
05602 rtx pool_end = gen_label_rtx ();
05603
05604 insn = gen_main_base_31_large (base_reg, pool->label, pool_end);
05605 insn = emit_insn_after (insn, pool->pool_insn);
05606 INSN_ADDRESSES_NEW (insn, -1);
05607 remove_insn (pool->pool_insn);
05608
05609 insn = emit_label_after (pool->label, insn);
05610 INSN_ADDRESSES_NEW (insn, -1);
05611
05612 pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
05613 INSN_ADDRESSES_NEW (pool->pool_insn, -1);
05614
05615 insn = emit_label_after (pool_end, pool->pool_insn);
05616 INSN_ADDRESSES_NEW (insn, -1);
05617
05618 s390_dump_pool (pool, 1);
05619 }
05620
05621
05622
05623
05624 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
05625 {
05626 if (INSN_P (insn))
05627 replace_ltrel_base (&PATTERN (insn));
05628
05629 if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
05630 {
05631 rtx addr, pool_ref = NULL_RTX;
05632 find_constant_pool_ref (PATTERN (insn), &pool_ref);
05633 if (pool_ref)
05634 {
05635 if (s390_execute_label (insn))
05636 addr = s390_find_execute (pool, insn);
05637 else
05638 addr = s390_find_constant (pool, get_pool_constant (pool_ref),
05639 get_pool_mode (pool_ref));
05640
05641 replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
05642 INSN_CODE (insn) = -1;
05643 }
05644 }
05645 }
05646
05647
05648
05649 s390_free_pool (pool);
05650 }
05651
05652
05653
05654
05655 static void
05656 s390_mainpool_cancel (struct constant_pool *pool)
05657 {
05658
05659
05660 s390_free_pool (pool);
05661 }
05662
05663
05664
05665
05666 #define S390_POOL_CHUNK_MIN 0xc00
05667 #define S390_POOL_CHUNK_MAX 0xe00
05668
05669 static struct constant_pool *
05670 s390_chunkify_start (void)
05671 {
05672 struct constant_pool *curr_pool = NULL, *pool_list = NULL;
05673 int extra_size = 0;
05674 bitmap far_labels;
05675 rtx pending_ltrel = NULL_RTX;
05676 rtx insn;
05677
05678 rtx (*gen_reload_base) (rtx, rtx) =
05679 TARGET_CPU_ZARCH? gen_reload_base_64 : gen_reload_base_31;
05680
05681
05682
05683
05684 shorten_branches (get_insns ());
05685
05686
05687
05688 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
05689 {
05690
05691 if (INSN_P (insn))
05692 {
05693 rtx ltrel_base = find_ltrel_base (PATTERN (insn));
05694 if (ltrel_base)
05695 {
05696 if (ltrel_base == pending_ltrel)
05697 pending_ltrel = NULL_RTX;
05698 else
05699 abort ();
05700 }
05701 }
05702
05703 if (s390_execute_label (insn))
05704 {
05705 if (!curr_pool)
05706 curr_pool = s390_start_pool (&pool_list, insn);
05707
05708 s390_add_execute (curr_pool, insn);
05709 s390_add_pool_insn (curr_pool, insn);
05710 }
05711 else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
05712 {
05713 rtx pool_ref = NULL_RTX;
05714 find_constant_pool_ref (PATTERN (insn), &pool_ref);
05715 if (pool_ref)
05716 {
05717 rtx constant = get_pool_constant (pool_ref);
05718 enum machine_mode mode = get_pool_mode (pool_ref);
05719
05720 if (!curr_pool)
05721 curr_pool = s390_start_pool (&pool_list, insn);
05722
05723 s390_add_constant (curr_pool, constant, mode);
05724 s390_add_pool_insn (curr_pool, insn);
05725
05726
05727
05728 if (GET_CODE (constant) == CONST
05729 && GET_CODE (XEXP (constant, 0)) == UNSPEC
05730 && XINT (XEXP (constant, 0), 1) == UNSPEC_LTREL_OFFSET)
05731 {
05732 if (pending_ltrel)
05733 abort ();
05734 pending_ltrel = pool_ref;
05735 }
05736 }
05737 }
05738
05739 if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL)
05740 {
05741 if (curr_pool)
05742 s390_add_pool_insn (curr_pool, insn);
05743
05744 if (pending_ltrel)
05745 abort ();
05746 }
05747
05748 if (!curr_pool
05749 || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
05750 || INSN_ADDRESSES (INSN_UID (insn)) == -1)
05751 continue;
05752
05753 if (TARGET_CPU_ZARCH)
05754 {
05755 if (curr_pool->size < S390_POOL_CHUNK_MAX)
05756 continue;
05757
05758 s390_end_pool (curr_pool, NULL_RTX);
05759 curr_pool = NULL;
05760 }
05761 else
05762 {
05763 int chunk_size = INSN_ADDRESSES (INSN_UID (insn))
05764 - INSN_ADDRESSES (INSN_UID (curr_pool->first_insn))
05765 + extra_size;
05766
05767
05768
05769
05770
05771 if (GET_CODE (insn) == CODE_LABEL)
05772 extra_size += 6;
05773
05774 if (chunk_size < S390_POOL_CHUNK_MIN
05775 && curr_pool->size < S390_POOL_CHUNK_MIN)
05776 continue;
05777
05778
05779 if (GET_CODE (insn) == BARRIER)
05780 {
05781 s390_end_pool (curr_pool, insn);
05782 curr_pool = NULL;
05783 extra_size = 0;
05784 }
05785
05786
05787 else if ((chunk_size > S390_POOL_CHUNK_MAX
05788 || curr_pool->size > S390_POOL_CHUNK_MAX))
05789 {
05790 rtx label, jump, barrier;
05791
05792
05793 if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
05794 continue;
05795 if (get_attr_length (insn) == 0)
05796 continue;
05797
05798
05799
05800 if (pending_ltrel)
05801 continue;
05802
05803 label = gen_label_rtx ();
05804 jump = emit_jump_insn_after (gen_jump (label), insn);
05805 barrier = emit_barrier_after (jump);
05806 insn = emit_label_after (label, barrier);
05807 JUMP_LABEL (jump) = label;
05808 LABEL_NUSES (label) = 1;
05809
05810 INSN_ADDRESSES_NEW (jump, -1);
05811 INSN_ADDRESSES_NEW (barrier, -1);
05812 INSN_ADDRESSES_NEW (insn, -1);
05813
05814 s390_end_pool (curr_pool, barrier);
05815 curr_pool = NULL;
05816 extra_size = 0;
05817 }
05818 }
05819 }
05820
05821 if (curr_pool)
05822 s390_end_pool (curr_pool, NULL_RTX);
05823 if (pending_ltrel)
05824 abort ();
05825
05826
05827
05828
05829
05830 far_labels = BITMAP_ALLOC (NULL);
05831
05832 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
05833 {
05834
05835
05836
05837
05838
05839
05840
05841 if (GET_CODE (insn) == CODE_LABEL
05842 && (LABEL_PRESERVE_P (insn) || LABEL_NAME (insn)))
05843 {
05844 rtx vec_insn = next_real_insn (insn);
05845 rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
05846 PATTERN (vec_insn) : NULL_RTX;
05847 if (!vec_pat
05848 || !(GET_CODE (vec_pat) == ADDR_VEC
05849 || GET_CODE (vec_pat) == ADDR_DIFF_VEC))
05850 bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (insn));
05851 }
05852
05853
05854
05855 else if (GET_CODE (insn) == JUMP_INSN)
05856 {
05857 rtx pat = PATTERN (insn);
05858 if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2)
05859 pat = XVECEXP (pat, 0, 0);
05860
05861 if (GET_CODE (pat) == SET)
05862 {
05863 rtx label = JUMP_LABEL (insn);
05864 if (label)
05865 {
05866 if (s390_find_pool (pool_list, label)
05867 != s390_find_pool (pool_list, insn))
05868 bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
05869 }
05870 }
05871 else if (GET_CODE (pat) == PARALLEL
05872 && XVECLEN (pat, 0) == 2
05873 && GET_CODE (XVECEXP (pat, 0, 0)) == SET
05874 && GET_CODE (XVECEXP (pat, 0, 1)) == USE
05875 && GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == LABEL_REF)
05876 {
05877
05878 rtx vec_label = XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0);
05879 rtx vec_insn = next_real_insn (vec_label);
05880 rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
05881 PATTERN (vec_insn) : NULL_RTX;
05882 if (vec_pat
05883 && (GET_CODE (vec_pat) == ADDR_VEC
05884 || GET_CODE (vec_pat) == ADDR_DIFF_VEC))
05885 {
05886 int i, diff_p = GET_CODE (vec_pat) == ADDR_DIFF_VEC;
05887
05888 for (i = 0; i < XVECLEN (vec_pat, diff_p); i++)
05889 {
05890 rtx label = XEXP (XVECEXP (vec_pat, diff_p, i), 0);
05891
05892 if (s390_find_pool (pool_list, label)
05893 != s390_find_pool (pool_list, insn))
05894 bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
05895 }
05896 }
05897 }
05898 }
05899 }
05900
05901
05902
05903 for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
05904 {
05905 rtx new_insn = gen_reload_base (cfun->machine->base_reg,
05906 curr_pool->label);
05907 rtx insn = curr_pool->first_insn;
05908 INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
05909 }
05910
05911
05912
05913 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
05914 if (GET_CODE (insn) == CODE_LABEL
05915 && bitmap_bit_p (far_labels, CODE_LABEL_NUMBER (insn)))
05916 {
05917 struct constant_pool *pool = s390_find_pool (pool_list, insn);
05918 if (pool)
05919 {
05920 rtx new_insn = gen_reload_base (cfun->machine->base_reg,
05921 pool->label);
05922 INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
05923 }
05924 }
05925
05926
05927 BITMAP_FREE (far_labels);
05928
05929
05930
05931
05932 init_insn_lengths ();
05933 shorten_branches (get_insns ());
05934
05935 return pool_list;
05936 }
05937
05938
05939
05940
05941
05942 static void
05943 s390_chunkify_finish (struct constant_pool *pool_list)
05944 {
05945 struct constant_pool *curr_pool = NULL;
05946 rtx insn;
05947
05948
05949
05950
05951 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
05952 {
05953 if (INSN_P (insn))
05954 replace_ltrel_base (&PATTERN (insn));
05955
05956 curr_pool = s390_find_pool (pool_list, insn);
05957 if (!curr_pool)
05958 continue;
05959
05960 if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
05961 {
05962 rtx addr, pool_ref = NULL_RTX;
05963 find_constant_pool_ref (PATTERN (insn), &pool_ref);
05964 if (pool_ref)
05965 {
05966 if (s390_execute_label (insn))
05967 addr = s390_find_execute (curr_pool, insn);
05968 else
05969 addr = s390_find_constant (curr_pool,
05970 get_pool_constant (pool_ref),
05971 get_pool_mode (pool_ref));
05972
05973 replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
05974 INSN_CODE (insn) = -1;
05975 }
05976 }
05977 }
05978
05979
05980
05981 for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
05982 s390_dump_pool (curr_pool, 0);
05983
05984
05985
05986 while (pool_list)
05987 {
05988 struct constant_pool *next = pool_list->next;
05989 s390_free_pool (pool_list);
05990 pool_list = next;
05991 }
05992 }
05993
05994
05995
05996
05997
05998 static void
05999 s390_chunkify_cancel (struct constant_pool *pool_list)
06000 {
06001 struct constant_pool *curr_pool = NULL;
06002 rtx insn;
06003
06004
06005
06006 for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
06007 {
06008
06009 rtx barrier = PREV_INSN (curr_pool->pool_insn);
06010 rtx jump = barrier? PREV_INSN (barrier) : NULL_RTX;
06011 rtx label = NEXT_INSN (curr_pool->pool_insn);
06012
06013 if (jump && GET_CODE (jump) == JUMP_INSN
06014 && barrier && GET_CODE (barrier) == BARRIER
06015 && label && GET_CODE (label) == CODE_LABEL
06016 && GET_CODE (PATTERN (jump)) == SET
06017 && SET_DEST (PATTERN (jump)) == pc_rtx
06018 && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
06019 && XEXP (SET_SRC (PATTERN (jump)), 0) == label)
06020 {
06021 remove_insn (jump);
06022 remove_insn (barrier);
06023 remove_insn (label);
06024 }
06025
06026 remove_insn (curr_pool->pool_insn);
06027 }
06028
06029
06030
06031 for (insn = get_insns (); insn; )
06032 {
06033 rtx next_insn = NEXT_INSN (insn);
06034
06035 if (GET_CODE (insn) == INSN
06036 && GET_CODE (PATTERN (insn)) == SET
06037 && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
06038 && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_RELOAD_BASE)
06039 remove_insn (insn);
06040
06041 insn = next_insn;
06042 }
06043
06044
06045
06046 while (pool_list)
06047 {
06048 struct constant_pool *next = pool_list->next;
06049 s390_free_pool (pool_list);
06050 pool_list = next;
06051 }
06052 }
06053
06054
06055
06056
06057 void
06058 s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align)
06059 {
06060 REAL_VALUE_TYPE r;
06061
06062 switch (GET_MODE_CLASS (mode))
06063 {
06064 case MODE_FLOAT:
06065 if (GET_CODE (exp) != CONST_DOUBLE)
06066 abort ();
06067
06068 REAL_VALUE_FROM_CONST_DOUBLE (r, exp);
06069 assemble_real (r, mode, align);
06070 break;
06071
06072 case MODE_INT:
06073 assemble_integer (exp, GET_MODE_SIZE (mode), align, 1);
06074 break;
06075
06076 default:
06077 abort ();
06078 }
06079 }
06080
06081
06082
06083
06084
06085 static void
06086 s390_optimize_prologue (void)
06087 {
06088 rtx insn, new_insn, next_insn;
06089
06090
06091
06092 s390_update_frame_layout ();
06093
06094
06095
06096
06097 if (cfun_frame_layout.first_save_gpr <= BASE_REGNUM
06098 && cfun_frame_layout.last_save_gpr >= BASE_REGNUM
06099 && (TARGET_CPU_ZARCH
06100 || (cfun_frame_layout.first_save_gpr <= RETURN_REGNUM
06101 && cfun_frame_layout.last_save_gpr >= RETURN_REGNUM)))
06102 return;
06103
06104
06105
06106 for (insn = get_insns (); insn; insn = next_insn)
06107 {
06108 int first, last, off;
06109 rtx set, base, offset;
06110
06111 next_insn = NEXT_INSN (insn);
06112
06113 if (GET_CODE (insn) != INSN)
06114 continue;
06115
06116 if (GET_CODE (PATTERN (insn)) == PARALLEL
06117 && store_multiple_operation (PATTERN (insn), VOIDmode))
06118 {
06119 set = XVECEXP (PATTERN (insn), 0, 0);
06120 first = REGNO (SET_SRC (set));
06121 last = first + XVECLEN (PATTERN (insn), 0) - 1;
06122 offset = const0_rtx;
06123 base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
06124 off = INTVAL (offset);
06125
06126 if (GET_CODE (base) != REG || off < 0)
06127 continue;
06128 if (cfun_frame_layout.first_save_gpr != -1
06129 && (cfun_frame_layout.first_save_gpr < first
06130 || cfun_frame_layout.last_save_gpr > last))
06131 continue;
06132 if (REGNO (base) != STACK_POINTER_REGNUM
06133 && REGNO (base) != HARD_FRAME_POINTER_REGNUM)
06134 continue;
06135 if (first > BASE_REGNUM || last < BASE_REGNUM)
06136 continue;
06137
06138 if (cfun_frame_layout.first_save_gpr != -1)
06139 {
06140 new_insn = save_gprs (base,
06141 off + (cfun_frame_layout.first_save_gpr
06142 - first) * UNITS_PER_WORD,
06143 cfun_frame_layout.first_save_gpr,
06144 cfun_frame_layout.last_save_gpr);
06145 new_insn = emit_insn_before (new_insn, insn);
06146 INSN_ADDRESSES_NEW (new_insn, -1);
06147 }
06148
06149 remove_insn (insn);
06150 continue;
06151 }
06152
06153 if (cfun_frame_layout.first_save_gpr == -1
06154 && GET_CODE (PATTERN (insn)) == SET
06155 && GET_CODE (SET_SRC (PATTERN (insn))) == REG
06156 && (REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM
06157 || (!TARGET_CPU_ZARCH
06158 && REGNO (SET_SRC (PATTERN (insn))) == RETURN_REGNUM))
06159 && GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
06160 {
06161 set = PATTERN (insn);
06162 first = REGNO (SET_SRC (set));
06163 offset = const0_rtx;
06164 base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
06165 off = INTVAL (offset);
06166
06167 if (GET_CODE (base) != REG || off < 0)
06168 continue;
06169 if (REGNO (base) != STACK_POINTER_REGNUM
06170 && REGNO (base) != HARD_FRAME_POINTER_REGNUM)
06171 continue;
06172
06173 remove_insn (insn);
06174 continue;
06175 }
06176
06177 if (GET_CODE (PATTERN (insn)) == PARALLEL
06178 && load_multiple_operation (PATTERN (insn), VOIDmode))
06179 {
06180 set = XVECEXP (PATTERN (insn), 0, 0);
06181 first = REGNO (SET_DEST (set));
06182 last = first + XVECLEN (PATTERN (insn), 0) - 1;
06183 offset = const0_rtx;
06184 base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
06185 off = INTVAL (offset);
06186
06187 if (GET_CODE (base) != REG || off < 0)
06188 continue;
06189 if (cfun_frame_layout.first_restore_gpr != -1
06190 && (cfun_frame_layout.first_restore_gpr < first
06191 || cfun_frame_layout.last_restore_gpr > last))
06192 continue;
06193 if (REGNO (base) != STACK_POINTER_REGNUM
06194 && REGNO (base) != HARD_FRAME_POINTER_REGNUM)
06195 continue;
06196 if (first > BASE_REGNUM || last < BASE_REGNUM)
06197 continue;
06198
06199 if (cfun_frame_layout.first_restore_gpr != -1)
06200 {
06201 new_insn = restore_gprs (base,
06202 off + (cfun_frame_layout.first_restore_gpr
06203 - first) * UNITS_PER_WORD,
06204 cfun_frame_layout.first_restore_gpr,
06205 cfun_frame_layout.last_restore_gpr);
06206 new_insn = emit_insn_before (new_insn, insn);
06207 INSN_ADDRESSES_NEW (new_insn, -1);
06208 }
06209
06210 remove_insn (insn);
06211 continue;
06212 }
06213
06214 if (cfun_frame_layout.first_restore_gpr == -1
06215 && GET_CODE (PATTERN (insn)) == SET
06216 && GET_CODE (SET_DEST (PATTERN (insn))) == REG
06217 && (REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM
06218 || (!TARGET_CPU_ZARCH
06219 && REGNO (SET_DEST (PATTERN (insn))) == RETURN_REGNUM))
06220 && GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
06221 {
06222 set = PATTERN (insn);
06223 first = REGNO (SET_DEST (set));
06224 offset = const0_rtx;
06225 base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
06226 off = INTVAL (offset);
06227
06228 if (GET_CODE (base) != REG || off < 0)
06229 continue;
06230 if (REGNO (base) != STACK_POINTER_REGNUM
06231 && REGNO (base) != HARD_FRAME_POINTER_REGNUM)
06232 continue;
06233
06234 remove_insn (insn);
06235 continue;
06236 }
06237 }
06238 }
06239
06240
06241
06242 static void
06243 s390_reorg (void)
06244 {
06245 bool pool_overflow = false;
06246
06247
06248
06249 split_all_insns_noflow ();
06250
06251
06252
06253
06254
06255
06256
06257
06258
06259
06260
06261
06262
06263
06264
06265
06266
06267
06268
06269
06270
06271
06272
06273
06274
06275
06276
06277
06278
06279
06280
06281
06282
06283
06284
06285 for (;;)
06286 {
06287 struct constant_pool *pool = NULL;
06288
06289
06290 if (!pool_overflow)
06291 {
06292 pool = s390_mainpool_start ();
06293 if (!pool)
06294 pool_overflow = true;
06295 }
06296
06297
06298 if (pool_overflow)
06299 pool = s390_chunkify_start ();
06300
06301
06302
06303
06304
06305 if (!TARGET_CPU_ZARCH && s390_split_branches ())
06306 {
06307 if (pool_overflow)
06308 s390_chunkify_cancel (pool);
06309 else
06310 s390_mainpool_cancel (pool);
06311
06312 continue;
06313 }
06314
06315
06316
06317 if (pool_overflow)
06318 s390_chunkify_finish (pool);
06319 else
06320 s390_mainpool_finish (pool);
06321
06322
06323 cfun->machine->split_branches_pending_p = false;
06324 break;
06325 }
06326
06327 s390_optimize_prologue ();
06328 }
06329
06330
06331
06332
06333
06334
06335 rtx
06336 s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
06337 {
06338 int offset;
06339 rtx addr;
06340
06341
06342
06343 if (!TARGET_BACKCHAIN && count > 0)
06344 return NULL_RTX;
06345
06346
06347
06348
06349 if (count == 0)
06350 {
06351 cfun_frame_layout.save_return_addr_p = true;
06352 return gen_rtx_MEM (Pmode, return_address_pointer_rtx);
06353 }
06354
06355 if (TARGET_PACKED_STACK)
06356 offset = -2 * UNITS_PER_WORD;
06357 else
06358 offset = RETURN_REGNUM * UNITS_PER_WORD;
06359
06360 addr = plus_constant (frame, offset);
06361 addr = memory_address (Pmode, addr);
06362 return gen_rtx_MEM (Pmode, addr);
06363 }
06364
06365
06366
06367
06368 rtx
06369 s390_back_chain_rtx (void)
06370 {
06371 rtx chain;
06372
06373 gcc_assert (TARGET_BACKCHAIN);
06374
06375 if (TARGET_PACKED_STACK)
06376 chain = plus_constant (stack_pointer_rtx,
06377 STACK_POINTER_OFFSET - UNITS_PER_WORD);
06378 else
06379 chain = stack_pointer_rtx;
06380
06381 chain = gen_rtx_MEM (Pmode, chain);
06382 return chain;
06383 }
06384
06385
06386
06387
06388
06389 static int
06390 find_unused_clobbered_reg (void)
06391 {
06392 int i;
06393 for (i = 0; i < 6; i++)
06394 if (!regs_ever_live[i])
06395 return i;
06396 return 0;
06397 }
06398
06399
06400
06401
06402
06403
06404
06405 static void
06406 s390_frame_area (int *area_bottom, int *area_top)
06407 {
06408 int b, t;
06409 int i;
06410
06411 b = INT_MAX;
06412 t = INT_MIN;
06413
06414 if (cfun_frame_layout.first_restore_gpr != -1)
06415 {
06416 b = (cfun_frame_layout.gprs_offset
06417 + cfun_frame_layout.first_restore_gpr * UNITS_PER_WORD);
06418 t = b + (cfun_frame_layout.last_restore_gpr
06419 - cfun_frame_layout.first_restore_gpr + 1) * UNITS_PER_WORD;
06420 }
06421
06422 if (TARGET_64BIT && cfun_save_high_fprs_p)
06423 {
06424 b = MIN (b, cfun_frame_layout.f8_offset);
06425 t = MAX (t, (cfun_frame_layout.f8_offset
06426 + cfun_frame_layout.high_fprs * 8));
06427 }
06428
06429 if (!TARGET_64BIT)
06430 for (i = 2; i < 4; i++)
06431 if (cfun_fpr_bit_p (i))
06432 {
06433 b = MIN (b, cfun_frame_layout.f4_offset + (i - 2) * 8);
06434 t = MAX (t, cfun_frame_layout.f4_offset + (i - 1) * 8);
06435 }
06436
06437 *area_bottom = b;
06438 *area_top = t;
06439 }
06440
06441
06442
06443
06444 static void
06445 s390_register_info (int live_regs[])
06446 {
06447 int i, j;
06448
06449
06450 cfun_frame_layout.fpr_bitmap = 0;
06451 cfun_frame_layout.high_fprs = 0;
06452 if (TARGET_64BIT)
06453 for (i = 24; i < 32; i++)
06454 if (regs_ever_live[i] && !global_regs[i])
06455 {
06456 cfun_set_fpr_bit (i - 16);
06457 cfun_frame_layout.high_fprs++;
06458 }
06459
06460
06461
06462
06463
06464
06465
06466 for (i = 0; i < 16; i++)
06467 live_regs[i] = regs_ever_live[i] && !global_regs[i];
06468
06469 if (flag_pic)
06470 live_regs[PIC_OFFSET_TABLE_REGNUM]
06471 = regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
06472
06473 live_regs[BASE_REGNUM]
06474 = cfun->machine->base_reg
06475 && REGNO (cfun->machine->base_reg) == BASE_REGNUM;
06476
06477 live_regs[RETURN_REGNUM]
06478 = cfun->machine->split_branches_pending_p
06479 || cfun_frame_layout.save_return_addr_p;
06480
06481 live_regs[STACK_POINTER_REGNUM]
06482 = !current_function_is_leaf
06483 || TARGET_TPF_PROFILING
06484 || cfun_save_high_fprs_p
06485 || get_frame_size () > 0
06486 || current_function_calls_alloca
06487 || current_function_stdarg;
06488
06489 for (i = 6; i < 16; i++)
06490 if (live_regs[i])
06491 break;
06492 for (j = 15; j > i; j--)
06493 if (live_regs[j])
06494 break;
06495
06496 if (i == 16)
06497 {
06498
06499 cfun_frame_layout.first_save_gpr = -1;
06500 cfun_frame_layout.first_restore_gpr = -1;
06501 cfun_frame_layout.last_save_gpr = -1;
06502 cfun_frame_layout.last_restore_gpr = -1;
06503 }
06504 else
06505 {
06506
06507 cfun_frame_layout.first_save_gpr = i;
06508 cfun_frame_layout.first_restore_gpr = i;
06509 cfun_frame_layout.last_save_gpr = j;
06510 cfun_frame_layout.last_restore_gpr = j;
06511 }
06512
06513 if (current_function_stdarg)
06514 {
06515
06516 if (cfun_frame_layout.first_save_gpr == -1
06517 || cfun_frame_layout.first_save_gpr > 2)
06518 cfun_frame_layout.first_save_gpr = 2;
06519
06520 if (cfun_frame_layout.last_save_gpr == -1
06521 || cfun_frame_layout.last_save_gpr < 6)
06522 cfun_frame_layout.last_save_gpr = 6;
06523
06524
06525 if (TARGET_HARD_FLOAT)
06526 for (i = 0; i < (TARGET_64BIT ? 4 : 2); i++)
06527 cfun_set_fpr_bit (i);
06528 }
06529
06530 if (!TARGET_64BIT)
06531 for (i = 2; i < 4; i++)
06532 if (regs_ever_live[i + 16] && !global_regs[i + 16])
06533 cfun_set_fpr_bit (i);
06534 }
06535
06536
06537
06538 static void
06539 s390_frame_info (void)
06540 {
06541 int i;
06542
06543 cfun_frame_layout.frame_size = get_frame_size ();
06544 if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000)
06545 fatal_error ("Total size of local variables exceeds architecture limit.");
06546
06547 if (!TARGET_PACKED_STACK)
06548 {
06549 cfun_frame_layout.backchain_offset = 0;
06550 cfun_frame_layout.f0_offset = 16 * UNITS_PER_WORD;
06551 cfun_frame_layout.f4_offset = cfun_frame_layout.f0_offset + 2 * 8;
06552 cfun_frame_layout.f8_offset = -cfun_frame_layout.high_fprs * 8;
06553 cfun_frame_layout.gprs_offset = (cfun_frame_layout.first_save_gpr
06554 * UNITS_PER_WORD);
06555 }
06556 else if (TARGET_BACKCHAIN)
06557 {
06558 cfun_frame_layout.backchain_offset = (STACK_POINTER_OFFSET
06559 - UNITS_PER_WORD);
06560 cfun_frame_layout.gprs_offset
06561 = (cfun_frame_layout.backchain_offset
06562 - (STACK_POINTER_REGNUM - cfun_frame_layout.first_save_gpr + 1)
06563 * UNITS_PER_WORD);
06564
06565 if (TARGET_64BIT)
06566 {
06567 cfun_frame_layout.f4_offset
06568 = (cfun_frame_layout.gprs_offset
06569 - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
06570
06571 cfun_frame_layout.f0_offset
06572 = (cfun_frame_layout.f4_offset
06573 - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
06574 }
06575 else
06576 {
06577
06578
06579 cfun_frame_layout.f0_offset
06580 = ((cfun_frame_layout.gprs_offset
06581 & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1))
06582 - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
06583
06584 cfun_frame_layout.f4_offset
06585 = (cfun_frame_layout.f0_offset
06586 - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
06587 }
06588 }
06589 else
06590 {
06591 cfun_frame_layout.f4_offset
06592 = (STACK_POINTER_OFFSET
06593 - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
06594
06595 cfun_frame_layout.f0_offset
06596 = (cfun_frame_layout.f4_offset
06597 - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
06598
06599 cfun_frame_layout.gprs_offset
06600 = cfun_frame_layout.f0_offset - cfun_gprs_save_area_size;
06601 }
06602
06603 if (current_function_is_leaf
06604 && !TARGET_TPF_PROFILING
06605 && cfun_frame_layout.frame_size == 0
06606 && !cfun_save_high_fprs_p
06607 && !current_function_calls_alloca
06608 && !current_function_stdarg)
06609 return;
06610
06611 if (!TARGET_PACKED_STACK)
06612 cfun_frame_layout.frame_size += (STARTING_FRAME_OFFSET
06613 + cfun_frame_layout.high_fprs * 8);
06614 else
06615 {
06616 if (TARGET_BACKCHAIN)
06617 cfun_frame_layout.frame_size += UNITS_PER_WORD;
06618
06619
06620
06621 cfun_frame_layout.f8_offset = (MIN (MIN (cfun_frame_layout.f0_offset,
06622 cfun_frame_layout.f4_offset),
06623 cfun_frame_layout.gprs_offset)
06624 - cfun_frame_layout.high_fprs * 8);
06625
06626 cfun_frame_layout.frame_size += cfun_frame_layout.high_fprs * 8;
06627
06628 for (i = 0; i < 8; i++)
06629 if (cfun_fpr_bit_p (i))
06630 cfun_frame_layout.frame_size += 8;
06631
06632 cfun_frame_layout.frame_size += cfun_gprs_save_area_size;
06633
06634
06635
06636 cfun_frame_layout.frame_size = ((cfun_frame_layout.frame_size +
06637 STACK_BOUNDARY / BITS_PER_UNIT - 1)
06638 & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1));
06639
06640 cfun_frame_layout.frame_size += current_function_outgoing_args_size;
06641 }
06642 }
06643
06644
06645
06646
06647
06648 static void
06649 s390_init_frame_layout (void)
06650 {
06651 HOST_WIDE_INT frame_size;
06652 int base_used;
06653 int live_regs[16];
06654
06655
06656 if (regs_ever_live[RETURN_REGNUM]
06657 || !current_function_is_leaf
06658 || TARGET_TPF_PROFILING
06659 || current_function_stdarg
06660 || current_function_calls_eh_return)
06661 cfun_frame_layout.save_return_addr_p = true;
06662
06663
06664
06665
06666
06667 if (!TARGET_CPU_ZARCH)
06668 cfun->machine->split_branches_pending_p = true;
06669
06670 do
06671 {
06672 frame_size = cfun_frame_layout.frame_size;
06673
06674
06675 base_used = cfun->machine->split_branches_pending_p
06676 || current_function_uses_const_pool
06677 || (!DISP_IN_RANGE (-frame_size)
06678 && !CONST_OK_FOR_CONSTRAINT_P (-frame_size, 'K', "K"));
06679
06680
06681
06682
06683 if (!base_used)
06684 cfun->machine->base_reg = NULL_RTX;
06685 else if (current_function_is_leaf && !regs_ever_live[5])
06686 cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
06687 else
06688 cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
06689
06690 s390_register_info (live_regs);
06691 s390_frame_info ();
06692 }
06693 while (frame_size != cfun_frame_layout.frame_size);
06694 }
06695
06696
06697
06698
06699
06700
06701 static void
06702 s390_update_frame_layout (void)
06703 {
06704 int live_regs[16];
06705
06706 s390_register_info (live_regs);
06707
06708 regs_ever_live[BASE_REGNUM] = live_regs[BASE_REGNUM];
06709 regs_ever_live[RETURN_REGNUM] = live_regs[RETURN_REGNUM];
06710 regs_ever_live[STACK_POINTER_REGNUM] = live_regs[STACK_POINTER_REGNUM];
06711
06712 if (cfun->machine->base_reg)
06713 regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
06714 }
06715
06716
06717
06718 bool
06719 s390_can_eliminate (int from, int to)
06720 {
06721 gcc_assert (to == STACK_POINTER_REGNUM
06722 || to == HARD_FRAME_POINTER_REGNUM);
06723
06724 gcc_assert (from == FRAME_POINTER_REGNUM
06725 || from == ARG_POINTER_REGNUM
06726 || from == RETURN_ADDRESS_POINTER_REGNUM);
06727
06728
06729 if (from == RETURN_ADDRESS_POINTER_REGNUM)
06730 if (!current_function_calls_eh_return
06731 && !current_function_stdarg
06732 && !cfun_frame_layout.save_return_addr_p)
06733 return false;
06734
06735 return true;
06736 }
06737
06738
06739
06740 HOST_WIDE_INT
06741 s390_initial_elimination_offset (int from, int to)
06742 {
06743 HOST_WIDE_INT offset;
06744 int index;
06745
06746
06747 if (!s390_can_eliminate (from, to))
06748 return 0;
06749
06750 switch (from)
06751 {
06752 case FRAME_POINTER_REGNUM:
06753 offset = 0;
06754 break;
06755
06756 case ARG_POINTER_REGNUM:
06757 s390_init_frame_layout ();
06758 offset = cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
06759 break;
06760
06761 case RETURN_ADDRESS_POINTER_REGNUM:
06762 s390_init_frame_layout ();
06763 index = RETURN_REGNUM - cfun_frame_layout.first_save_gpr;
06764 gcc_assert (index >= 0);
06765 offset = cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset;
06766 offset += index * UNITS_PER_WORD;
06767 break;
06768
06769 default:
06770 gcc_unreachable ();
06771 }
06772
06773 return offset;
06774 }
06775
06776
06777
06778
06779 static rtx
06780 save_fpr (rtx base, int offset, int regnum)
06781 {
06782 rtx addr;
06783 addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
06784 set_mem_alias_set (addr, s390_sr_alias_set);
06785
06786 return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum));
06787 }
06788
06789
06790
06791
06792 static rtx
06793 restore_fpr (rtx base, int offset, int regnum)
06794 {
06795 rtx addr;
06796 addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
06797 set_mem_alias_set (addr, s390_sr_alias_set);
06798
06799 return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr);
06800 }
06801
06802
06803
06804
06805
06806 static rtx
06807 save_gprs (rtx base, int offset, int first, int last)
06808 {
06809 rtx addr, insn, note;
06810 int i;
06811
06812 addr = plus_constant (base, offset);
06813 addr = gen_rtx_MEM (Pmode, addr);
06814 set_mem_alias_set (addr, s390_sr_alias_set);
06815
06816
06817 if (first == last)
06818 {
06819 if (TARGET_64BIT)
06820 insn = gen_movdi (addr, gen_rtx_REG (Pmode, first));
06821 else
06822 insn = gen_movsi (addr, gen_rtx_REG (Pmode, first));
06823
06824 RTX_FRAME_RELATED_P (insn) = 1;
06825 return insn;
06826 }
06827
06828
06829 insn = gen_store_multiple (addr,
06830 gen_rtx_REG (Pmode, first),
06831 GEN_INT (last - first + 1));
06832
06833
06834
06835
06836
06837
06838
06839
06840
06841
06842
06843
06844
06845
06846 if (first >= 6)
06847 {
06848 rtx pat = PATTERN (insn);
06849
06850 for (i = 0; i < XVECLEN (pat, 0); i++)
06851 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
06852 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
06853
06854 RTX_FRAME_RELATED_P (insn) = 1;
06855 }
06856 else if (last >= 6)
06857 {
06858 addr = plus_constant (base, offset + (6 - first) * UNITS_PER_WORD);
06859 note = gen_store_multiple (gen_rtx_MEM (Pmode, addr),
06860 gen_rtx_REG (Pmode, 6),
06861 GEN_INT (last - 6 + 1));
06862 note = PATTERN (note);
06863
06864 REG_NOTES (insn) =
06865 gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
06866 note, REG_NOTES (insn));
06867
06868 for (i = 0; i < XVECLEN (note, 0); i++)
06869 if (GET_CODE (XVECEXP (note, 0, i)) == SET)
06870 RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1;
06871
06872 RTX_FRAME_RELATED_P (insn) = 1;
06873 }
06874
06875 return insn;
06876 }
06877
06878
06879
06880
06881
06882 static rtx
06883 restore_gprs (rtx base, int offset, int first, int last)
06884 {
06885 rtx addr, insn;
06886
06887 addr = plus_constant (base, offset);
06888 addr = gen_rtx_MEM (Pmode, addr);
06889 set_mem_alias_set (addr, s390_sr_alias_set);
06890
06891
06892 if (first == last)
06893 {
06894 if (TARGET_64BIT)
06895 insn = gen_movdi (gen_rtx_REG (Pmode, first), addr);
06896 else
06897 insn = gen_movsi (gen_rtx_REG (Pmode, first), addr);
06898
06899 return insn;
06900 }
06901
06902 insn = gen_load_multiple (gen_rtx_REG (Pmode, first),
06903 addr,
06904 GEN_INT (last - first + 1));
06905 return insn;
06906 }
06907
06908
06909
06910 static GTY(()) rtx got_symbol;
06911 rtx
06912 s390_load_got (void)
06913 {
06914 rtx insns;
06915
06916 if (!got_symbol)
06917 {
06918 got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
06919 SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL;
06920 }
06921
06922 start_sequence ();
06923
06924 if (TARGET_CPU_ZARCH)
06925 {
06926 emit_move_insn (pic_offset_table_rtx, got_symbol);
06927 }
06928 else
06929 {
06930 rtx offset;
06931
06932 offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol),
06933 UNSPEC_LTREL_OFFSET);
06934 offset = gen_rtx_CONST (Pmode, offset);
06935 offset = force_const_mem (Pmode, offset);
06936
06937 emit_move_insn (pic_offset_table_rtx, offset);
06938
06939 offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)),
06940 UNSPEC_LTREL_BASE);
06941 offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset);
06942
06943 emit_move_insn (pic_offset_table_rtx, offset);
06944 }
06945
06946 insns = get_insns ();
06947 end_sequence ();
06948 return insns;
06949 }
06950
06951
06952
06953 void
06954 s390_emit_prologue (void)
06955 {
06956 rtx insn, addr;
06957 rtx temp_reg;
06958 int i;
06959 int offset;
06960 int next_fpr = 0;
06961
06962
06963
06964 s390_update_frame_layout ();
06965
06966
06967
06968
06969 push_topmost_sequence ();
06970
06971 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
06972 if (INSN_P (insn))
06973 annotate_constant_pool_refs (&PATTERN (insn));
06974
06975 pop_topmost_sequence ();
06976
06977
06978
06979
06980 if (!current_function_is_leaf && !TARGET_TPF_PROFILING)
06981 temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
06982 else
06983 temp_reg = gen_rtx_REG (Pmode, 1);
06984
06985
06986 if (cfun_frame_layout.first_save_gpr != -1)
06987 {
06988 insn = save_gprs (stack_pointer_rtx,
06989 cfun_frame_layout.gprs_offset,
06990 cfun_frame_layout.first_save_gpr,
06991 cfun_frame_layout.last_save_gpr);
06992 emit_insn (insn);
06993 }
06994
06995
06996
06997 if (cfun->machine->base_reg)
06998 emit_insn (gen_main_pool (cfun->machine->base_reg));
06999
07000 offset = cfun_frame_layout.f0_offset;
07001
07002
07003 for (i = 0; i < 2; i++)
07004 {
07005 if (cfun_fpr_bit_p (i))
07006 {
07007 save_fpr (stack_pointer_rtx, offset, i + 16);
07008 offset += 8;
07009 }
07010 else if (!TARGET_PACKED_STACK)
07011 offset += 8;
07012 }
07013
07014
07015 offset = cfun_frame_layout.f4_offset;
07016 for (i = 2; i < 4; i++)
07017 {
07018 if (cfun_fpr_bit_p (i))
07019 {
07020 insn = save_fpr (stack_pointer_rtx, offset, i + 16);
07021 offset += 8;
07022
07023
07024
07025 if (!call_really_used_regs[i + 16])
07026 RTX_FRAME_RELATED_P (insn) = 1;
07027 }
07028 else if (!TARGET_PACKED_STACK)
07029 offset += 8;
07030 }
07031
07032 if (TARGET_PACKED_STACK
07033 && cfun_save_high_fprs_p
07034 && cfun_frame_layout.f8_offset + cfun_frame_layout.high_fprs * 8 > 0)
07035 {
07036 offset = (cfun_frame_layout.f8_offset
07037 + (cfun_frame_layout.high_fprs - 1) * 8);
07038
07039 for (i = 15; i > 7 && offset >= 0; i--)
07040 if (cfun_fpr_bit_p (i))
07041 {
07042 insn = save_fpr (stack_pointer_rtx, offset, i + 16);
07043
07044 RTX_FRAME_RELATED_P (insn) = 1;
07045 offset -= 8;
07046 }
07047 if (offset >= cfun_frame_layout.f8_offset)
07048 next_fpr = i + 16;
07049 }
07050
07051 if (!TARGET_PACKED_STACK)
07052 next_fpr = cfun_save_high_fprs_p ? 31 : 0;
07053
07054
07055
07056 if (cfun_frame_layout.frame_size > 0)
07057 {
07058 rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size);
07059
07060 if (s390_stack_size)
07061 {
07062 HOST_WIDE_INT stack_check_mask = ((s390_stack_size - 1)
07063 & ~(s390_stack_guard - 1));
07064 rtx t = gen_rtx_AND (Pmode, stack_pointer_rtx,
07065 GEN_INT (stack_check_mask));
07066
07067 if (TARGET_64BIT)
07068 gen_cmpdi (t, const0_rtx);
07069 else
07070 gen_cmpsi (t, const0_rtx);
07071
07072 emit_insn (gen_conditional_trap (gen_rtx_EQ (CCmode,
07073 gen_rtx_REG (CCmode,
07074 CC_REGNUM),
07075 const0_rtx),
07076 const0_rtx));
07077 }
07078
07079 if (s390_warn_framesize > 0
07080 && cfun_frame_layout.frame_size >= s390_warn_framesize)
07081 warning ("frame size of %qs is " HOST_WIDE_INT_PRINT_DEC " bytes",
07082 current_function_name (), cfun_frame_layout.frame_size);
07083
07084 if (s390_warn_dynamicstack_p && cfun->calls_alloca)
07085 warning ("%qs uses dynamic stack allocation", current_function_name ());
07086
07087
07088 if (TARGET_BACKCHAIN || next_fpr)
07089 insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
07090
07091
07092
07093 if (DISP_IN_RANGE (INTVAL (frame_off)))
07094 {
07095 insn = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
07096 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
07097 frame_off));
07098 insn = emit_insn (insn);
07099 }
07100 else
07101 {
07102 if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K"))
07103 frame_off = force_const_mem (Pmode, frame_off);
07104
07105 insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
07106 annotate_constant_pool_refs (&PATTERN (insn));
07107 }
07108
07109 RTX_FRAME_RELATED_P (insn) = 1;
07110 REG_NOTES (insn) =
07111 gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
07112 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
07113 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
07114 GEN_INT (-cfun_frame_layout.frame_size))),
07115 REG_NOTES (insn));
07116
07117
07118
07119 if (TARGET_BACKCHAIN)
07120 {
07121 if (cfun_frame_layout.backchain_offset)
07122 addr = gen_rtx_MEM (Pmode,
07123 plus_constant (stack_pointer_rtx,
07124 cfun_frame_layout.backchain_offset));
07125 else
07126 addr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
07127 set_mem_alias_set (addr, s390_sr_alias_set);
07128 insn = emit_insn (gen_move_insn (addr, temp_reg));
07129 }
07130
07131
07132
07133
07134
07135 if (TARGET_BACKCHAIN && flag_non_call_exceptions)
07136 {
07137 addr = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode));
07138 emit_insn (gen_rtx_CLOBBER (VOIDmode, addr));
07139 }
07140 }
07141
07142
07143
07144 if (cfun_save_high_fprs_p && next_fpr)
07145 {
07146 insn = emit_insn (gen_add2_insn (temp_reg,
07147 GEN_INT (cfun_frame_layout.f8_offset)));
07148
07149 offset = 0;
07150
07151 for (i = 24; i <= next_fpr; i++)
07152 if (cfun_fpr_bit_p (i - 16))
07153 {
07154 rtx addr = plus_constant (stack_pointer_rtx,
07155 cfun_frame_layout.frame_size
07156 + cfun_frame_layout.f8_offset
07157 + offset);
07158
07159 insn = save_fpr (temp_reg, offset, i);
07160 offset += 8;
07161 RTX_FRAME_RELATED_P (insn) = 1;
07162 REG_NOTES (insn) =
07163 gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
07164 gen_rtx_SET (VOIDmode,
07165 gen_rtx_MEM (DFmode, addr),
07166 gen_rtx_REG (DFmode, i)),
07167 REG_NOTES (insn));
07168 }
07169 }
07170
07171
07172
07173 if (frame_pointer_needed)
07174 {
07175 insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
07176 RTX_FRAME_RELATED_P (insn) = 1;
07177 }
07178
07179
07180
07181 if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
07182 {
07183 rtx insns = s390_load_got ();
07184
07185 for (insn = insns; insn; insn = NEXT_INSN (insn))
07186 {
07187 annotate_constant_pool_refs (&PATTERN (insn));
07188
07189 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
07190 REG_NOTES (insn));
07191 }
07192
07193 emit_insn (insns);
07194 }
07195
07196 if (TARGET_TPF_PROFILING)
07197 {
07198
07199
07200
07201 emit_insn (gen_prologue_tpf ());
07202
07203
07204
07205 emit_insn (gen_blockage ());
07206 }
07207 }
07208
07209
07210
07211 void
07212 s390_emit_epilogue (bool sibcall)
07213 {
07214 rtx frame_pointer, return_reg;
07215 int area_bottom, area_top, offset = 0;
07216 int next_offset;
07217 rtvec p;
07218 int i;
07219
07220 if (TARGET_TPF_PROFILING)
07221 {
07222
07223
07224
07225
07226
07227
07228
07229 emit_insn (gen_blockage ());
07230
07231 emit_insn (gen_epilogue_tpf ());
07232 }
07233
07234
07235
07236 frame_pointer = (frame_pointer_needed
07237 ? hard_frame_pointer_rtx : stack_pointer_rtx);
07238
07239 s390_frame_area (&area_bottom, &area_top);
07240
07241
07242
07243
07244 if (area_top <= area_bottom)
07245 {
07246
07247 }
07248 else if (DISP_IN_RANGE (cfun_frame_layout.frame_size + area_bottom)
07249 && DISP_IN_RANGE (cfun_frame_layout.frame_size + area_top - 1))
07250 {
07251
07252 offset = cfun_frame_layout.frame_size;
07253 }
07254 else
07255 {
07256 rtx insn, frame_off;
07257
07258 offset = area_bottom < 0 ? -area_bottom : 0;
07259 frame_off = GEN_INT (cfun_frame_layout.frame_size - offset);
07260
07261 if (DISP_IN_RANGE (INTVAL (frame_off)))
07262 {
07263 insn = gen_rtx_SET (VOIDmode, frame_pointer,
07264 gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
07265 insn = emit_insn (insn);
07266 }
07267 else
07268 {
07269 if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K"))
07270 frame_off = force_const_mem (Pmode, frame_off);
07271
07272 insn = emit_insn (gen_add2_insn (frame_pointer, frame_off));
07273 annotate_constant_pool_refs (&PATTERN (insn));
07274 }
07275 }
07276
07277
07278
07279 if (TARGET_64BIT)
07280 {
07281 if (cfun_save_high_fprs_p)
07282 {
07283 next_offset = cfun_frame_layout.f8_offset;
07284 for (i = 24; i < 32; i++)
07285 {
07286 if (cfun_fpr_bit_p (i - 16))
07287 {
07288 restore_fpr (frame_pointer,
07289 offset + next_offset, i);
07290 next_offset += 8;
07291 }
07292 }
07293 }
07294
07295 }
07296 else
07297 {
07298 next_offset = cfun_frame_layout.f4_offset;
07299 for (i = 18; i < 20; i++)
07300 {
07301 if (cfun_fpr_bit_p (i - 16))
07302 {
07303 restore_fpr (frame_pointer,
07304 offset + next_offset, i);
07305 next_offset += 8;
07306 }
07307 else if (!TARGET_PACKED_STACK)
07308 next_offset += 8;
07309 }
07310
07311 }
07312
07313
07314
07315 return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
07316
07317
07318
07319 if (cfun_frame_layout.first_restore_gpr != -1)
07320 {
07321 rtx insn, addr;
07322 int i;
07323
07324
07325
07326
07327 for (i = cfun_frame_layout.first_restore_gpr;
07328 i <= cfun_frame_layout.last_restore_gpr;
07329 i++)
07330 {
07331
07332
07333 if (i == STACK_POINTER_REGNUM
07334 || i == RETURN_REGNUM
07335 || i == BASE_REGNUM
07336 || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
07337 continue;
07338
07339 if (global_regs[i])
07340 {
07341 addr = plus_constant (frame_pointer,
07342 offset + cfun_frame_layout.gprs_offset
07343 + (i - cfun_frame_layout.first_save_gpr)
07344 * UNITS_PER_WORD);
07345 addr = gen_rtx_MEM (Pmode, addr);
07346 set_mem_alias_set (addr, s390_sr_alias_set);
07347 emit_move_insn (addr, gen_rtx_REG (Pmode, i));
07348 }
07349 }
07350
07351 if (! sibcall)
07352 {
07353
07354
07355
07356 if (cfun_frame_layout.save_return_addr_p
07357 || (cfun_frame_layout.first_restore_gpr < BASE_REGNUM
07358 && cfun_frame_layout.last_restore_gpr > RETURN_REGNUM))
07359 {
07360 int return_regnum = find_unused_clobbered_reg();
07361 if (!return_regnum)
07362 return_regnum = 4;
07363 return_reg = gen_rtx_REG (Pmode, return_regnum);
07364
07365 addr = plus_constant (frame_pointer,
07366 offset + cfun_frame_layout.gprs_offset
07367 + (RETURN_REGNUM
07368 - cfun_frame_layout.first_save_gpr)
07369 * UNITS_PER_WORD);
07370 addr = gen_rtx_MEM (Pmode, addr);
07371 set_mem_alias_set (addr, s390_sr_alias_set);
07372 emit_move_insn (return_reg, addr);
07373 }
07374 }
07375
07376 insn = restore_gprs (frame_pointer,
07377 offset + cfun_frame_layout.gprs_offset
07378 + (cfun_frame_layout.first_restore_gpr
07379 - cfun_frame_layout.first_save_gpr)
07380 * UNITS_PER_WORD,
07381 cfun_frame_layout.first_restore_gpr,
07382 cfun_frame_layout.last_restore_gpr);
07383 emit_insn (insn);
07384 }
07385
07386 if (! sibcall)
07387 {
07388
07389
07390
07391 p = rtvec_alloc (2);
07392
07393 RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
07394 RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
07395 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
07396 }
07397 }
07398
07399
07400
07401
07402
07403
07404 static int
07405 s390_function_arg_size (enum machine_mode mode, tree type)
07406 {
07407 if (type)
07408 return int_size_in_bytes (type);
07409
07410
07411 if (mode != BLKmode)
07412 return GET_MODE_SIZE (mode);
07413
07414
07415 abort ();
07416 }
07417
07418
07419
07420
07421 static bool
07422 s390_function_arg_float (enum machine_mode mode, tree type)
07423 {
07424 int size = s390_function_arg_size (mode, type);
07425 if (size > 8)
07426 return false;
07427
07428
07429 if (TARGET_SOFT_FLOAT)
07430 return false;
07431
07432
07433 if (!type)
07434 return mode == SFmode || mode == DFmode;
07435
07436
07437
07438 while (TREE_CODE (type) == RECORD_TYPE)
07439 {
07440 tree field, single = NULL_TREE;
07441
07442 for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
07443 {
07444 if (TREE_CODE (field) != FIELD_DECL)
07445 continue;
07446
07447 if (single == NULL_TREE)
07448 single = TREE_TYPE (field);
07449 else
07450 return false;
07451 }
07452
07453 if (single == NULL_TREE)
07454 return false;
07455 else
07456 type = single;
07457 }
07458
07459 return TREE_CODE (type) == REAL_TYPE;
07460 }
07461
07462
07463
07464
07465
07466 static bool
07467 s390_function_arg_integer (enum machine_mode mode, tree type)
07468 {
07469 int size = s390_function_arg_size (mode, type);
07470 if (size > 8)
07471 return false;
07472
07473
07474 if (!type)
07475 return GET_MODE_CLASS (mode) == MODE_INT
07476 || (TARGET_SOFT_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT);
07477
07478
07479 if (INTEGRAL_TYPE_P (type)
07480 || POINTER_TYPE_P (type)
07481 || TREE_CODE (type) == OFFSET_TYPE
07482 || (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE))
07483 return true;
07484
07485
07486
07487 if (AGGREGATE_TYPE_P (type)
07488 && exact_log2 (size) >= 0
07489 && !s390_function_arg_float (mode, type))
07490 return true;
07491
07492 return false;
07493 }
07494
07495
07496
07497
07498
07499
07500
07501 static bool
07502 s390_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
07503 enum machine_mode mode, tree type,
07504 bool named ATTRIBUTE_UNUSED)
07505 {
07506 int size = s390_function_arg_size (mode, type);
07507 if (size > 8)
07508 return true;
07509
07510 if (type)
07511 {
07512 if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0)
07513 return 1;
07514
07515 if (TREE_CODE (type) == COMPLEX_TYPE
07516 || TREE_CODE (type) == VECTOR_TYPE)
07517 return 1;
07518 }
07519
07520 return 0;
07521 }
07522
07523
07524
07525
07526
07527
07528
07529 void
07530 s390_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
07531 tree type, int named ATTRIBUTE_UNUSED)
07532 {
07533 if (s390_function_arg_float (mode, type))
07534 {
07535 cum->fprs += 1;
07536 }
07537 else if (s390_function_arg_integer (mode, type))
07538 {
07539 int size = s390_function_arg_size (mode, type);
07540 cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
07541 }
07542 else
07543 abort ();
07544 }
07545
07546
07547
07548
07549
07550
07551
07552
07553
07554
07555
07556
07557
07558
07559
07560
07561
07562
07563
07564
07565 rtx
07566 s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
07567 int named ATTRIBUTE_UNUSED)
07568 {
07569 if (s390_function_arg_float (mode, type))
07570 {
07571 if (cum->fprs + 1 > (TARGET_64BIT? 4 : 2))
07572 return 0;
07573 else
07574 return gen_rtx_REG (mode, cum->fprs + 16);
07575 }
07576 else if (s390_function_arg_integer (mode, type))
07577 {
07578 int size = s390_function_arg_size (mode, type);
07579 int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD;
07580
07581 if (cum->gprs + n_gprs > 5)
07582 return 0;
07583 else
07584 return gen_rtx_REG (mode, cum->gprs + 2);
07585 }
07586
07587
07588
07589
07590
07591
07592 else if (type == void_type_node)
07593 return const0_rtx;
07594
07595 abort ();
07596 }
07597
07598
07599
07600
07601
07602 static bool
07603 s390_return_in_memory (tree type, tree fundecl ATTRIBUTE_UNUSED)
07604 {
07605
07606 if (INTEGRAL_TYPE_P (type)
07607 || POINTER_TYPE_P (type)
07608 || TREE_CODE (type) == OFFSET_TYPE
07609 || TREE_CODE (type) == REAL_TYPE)
07610 return int_size_in_bytes (type) > 8;
07611
07612
07613
07614 if (AGGREGATE_TYPE_P (type)
07615 || TREE_CODE (type) == COMPLEX_TYPE
07616 || TREE_CODE (type) == VECTOR_TYPE)
07617 return true;
07618
07619
07620
07621
07622 return true;
07623 }
07624
07625
07626
07627
07628
07629 rtx
07630 s390_function_value (tree type, enum machine_mode mode)
07631 {
07632 if (type)
07633 {
07634 int unsignedp = TYPE_UNSIGNED (type);
07635 mode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
07636 }
07637
07638 if (GET_MODE_CLASS (mode) != MODE_INT
07639 && GET_MODE_CLASS (mode) != MODE_FLOAT)
07640 abort ();
07641 if (GET_MODE_SIZE (mode) > 8)
07642 abort ();
07643
07644 if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
07645 return gen_rtx_REG (mode, 16);
07646 else
07647 return gen_rtx_REG (mode, 2);
07648 }
07649
07650
07651
07652
07653
07654
07655
07656
07657
07658
07659
07660
07661
07662
07663
07664
07665
07666
07667
07668
07669
07670
07671
07672 static tree
07673 s390_build_builtin_va_list (void)
07674 {
07675 tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
07676
07677 record = lang_hooks.types.make_type (RECORD_TYPE);
07678
07679 type_decl =
07680 build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
07681
07682 f_gpr = build_decl (FIELD_DECL, get_identifier ("__gpr"),
07683 long_integer_type_node);
07684 f_fpr = build_decl (FIELD_DECL, get_identifier ("__fpr"),
07685 long_integer_type_node);
07686 f_ovf = build_decl (FIELD_DECL, get_identifier ("__overflow_arg_area"),
07687 ptr_type_node);
07688 f_sav = build_decl (FIELD_DECL, get_identifier ("__reg_save_area"),
07689 ptr_type_node);
07690
07691 DECL_FIELD_CONTEXT (f_gpr) = record;
07692 DECL_FIELD_CONTEXT (f_fpr) = record;
07693 DECL_FIELD_CONTEXT (f_ovf) = record;
07694 DECL_FIELD_CONTEXT (f_sav) = record;
07695
07696 TREE_CHAIN (record) = type_decl;
07697 TYPE_NAME (record) = type_decl;
07698 TYPE_FIELDS (record) = f_gpr;
07699 TREE_CHAIN (f_gpr) = f_fpr;
07700 TREE_CHAIN (f_fpr) = f_ovf;
07701 TREE_CHAIN (f_ovf) = f_sav;
07702
07703 layout_type (record);
07704
07705
07706 return build_array_type (record, build_index_type (size_zero_node));
07707 }
07708
07709
07710
07711
07712
07713
07714
07715
07716
07717
07718
07719
07720
07721
07722 void
07723 s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
07724 {
07725 HOST_WIDE_INT n_gpr, n_fpr;
07726 int off;
07727 tree f_gpr, f_fpr, f_ovf, f_sav;
07728 tree gpr, fpr, ovf, sav, t;
07729
07730 f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
07731 f_fpr = TREE_CHAIN (f_gpr);
07732 f_ovf = TREE_CHAIN (f_fpr);
07733 f_sav = TREE_CHAIN (f_ovf);
07734
07735 valist = build_va_arg_indirect_ref (valist);
07736 gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
07737 fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
07738 ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
07739 sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
07740
07741
07742
07743 n_gpr = current_function_args_info.gprs;
07744 n_fpr = current_function_args_info.fprs;
07745
07746 t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
07747 build_int_cst (NULL_TREE, n_gpr));
07748 TREE_SIDE_EFFECTS (t) = 1;
07749 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
07750
07751 t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
07752 build_int_cst (NULL_TREE, n_fpr));
07753 TREE_SIDE_EFFECTS (t) = 1;
07754 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
07755
07756
07757 t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
07758
07759 off = INTVAL (current_function_arg_offset_rtx);
07760 off = off < 0 ? 0 : off;
07761 if (TARGET_DEBUG_ARG)
07762 fprintf (stderr, "va_start: n_gpr = %d, n_fpr = %d off %d\n",
07763 (int)n_gpr, (int)n_fpr, off);
07764
07765 t = build (PLUS_EXPR, TREE_TYPE (ovf), t, build_int_cst (NULL_TREE, off));
07766
07767 t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
07768 TREE_SIDE_EFFECTS (t) = 1;
07769 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
07770
07771
07772 t = make_tree (TREE_TYPE (sav), return_address_pointer_rtx);
07773 t = build (PLUS_EXPR, TREE_TYPE (sav), t,
07774 build_int_cst (NULL_TREE, -RETURN_REGNUM * UNITS_PER_WORD));
07775
07776 t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
07777 TREE_SIDE_EFFECTS (t) = 1;
07778 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
07779 }
07780
07781
07782
07783
07784
07785
07786
07787
07788
07789
07790
07791
07792
07793
07794
07795
07796
07797
07798
07799
07800
07801
07802
07803
07804
07805 tree
07806 s390_gimplify_va_arg (tree valist, tree type, tree *pre_p,
07807 tree *post_p ATTRIBUTE_UNUSED)
07808 {
07809 tree f_gpr, f_fpr, f_ovf, f_sav;
07810 tree gpr, fpr, ovf, sav, reg, t, u;
07811 int indirect_p, size, n_reg, sav_ofs, sav_scale, max_reg;
07812 tree lab_false, lab_over, addr;
07813
07814 f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
07815 f_fpr = TREE_CHAIN (f_gpr);
07816 f_ovf = TREE_CHAIN (f_fpr);
07817 f_sav = TREE_CHAIN (f_ovf);
07818
07819 valist = build_va_arg_indirect_ref (valist);
07820 gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
07821 fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
07822 ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
07823 sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
07824
07825 size = int_size_in_bytes (type);
07826
07827 if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
07828 {
07829 if (TARGET_DEBUG_ARG)
07830 {
07831 fprintf (stderr, "va_arg: aggregate type");
07832 debug_tree (type);
07833 }
07834
07835
07836 indirect_p = 1;
07837 reg = gpr;
07838 n_reg = 1;
07839
07840
07841
07842
07843 sav_ofs = 2 * UNITS_PER_WORD;
07844 sav_scale = UNITS_PER_WORD;
07845 size = UNITS_PER_WORD;
07846 max_reg = 4;
07847 }
07848 else if (s390_function_arg_float (TYPE_MODE (type), type))
07849 {
07850 if (TARGET_DEBUG_ARG)
07851 {
07852 fprintf (stderr, "va_arg: float type");
07853 debug_tree (type);
07854 }
07855
07856
07857 indirect_p = 0;
07858 reg = fpr;
07859 n_reg = 1;
07860 sav_ofs = 16 * UNITS_PER_WORD;
07861 sav_scale = 8;
07862
07863 max_reg = TARGET_64BIT ? 3 : 1;
07864 }
07865 else
07866 {
07867 if (TARGET_DEBUG_ARG)
07868 {
07869 fprintf (stderr, "va_arg: other type");
07870 debug_tree (type);
07871 }
07872
07873
07874 indirect_p = 0;
07875 reg = gpr;
07876 n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
07877
07878
07879
07880
07881 sav_ofs = 2 * UNITS_PER_WORD;
07882
07883 if (size < UNITS_PER_WORD)
07884 sav_ofs += UNITS_PER_WORD - size;
07885
07886 sav_scale = UNITS_PER_WORD;
07887 if (n_reg > 1)
07888 max_reg = 3;
07889 else
07890 max_reg = 4;
07891 }
07892
07893
07894
07895 lab_false = create_artificial_label ();
07896 lab_over = create_artificial_label ();
07897 addr = create_tmp_var (ptr_type_node, "addr");
07898 DECL_POINTER_ALIAS_SET (addr) = s390_sr_alias_set;
07899
07900 t = fold_convert (TREE_TYPE (reg), size_int (max_reg));
07901 t = build2 (GT_EXPR, boolean_type_node, reg, t);
07902 u = build1 (GOTO_EXPR, void_type_node, lab_false);
07903 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
07904 gimplify_and_add (t, pre_p);
07905
07906 t = build2 (PLUS_EXPR, ptr_type_node, sav,
07907 fold_convert (ptr_type_node, size_int (sav_ofs)));
07908 u = build2 (MULT_EXPR, TREE_TYPE (reg), reg,
07909 fold_convert (TREE_TYPE (reg), size_int (sav_scale)));
07910 t = build2 (PLUS_EXPR, ptr_type_node, t, fold_convert (ptr_type_node, u));
07911
07912 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
07913 gimplify_and_add (t, pre_p);
07914
07915 t = build1 (GOTO_EXPR, void_type_node, lab_over);
07916 gimplify_and_add (t, pre_p);
07917
07918 t = build1 (LABEL_EXPR, void_type_node, lab_false);
07919 append_to_statement_list (t, pre_p);
07920
07921
07922
07923
07924 t = ovf;
07925 if (size < UNITS_PER_WORD)
07926 t = build2 (PLUS_EXPR, ptr_type_node, t,
07927 fold_convert (ptr_type_node, size_int (UNITS_PER_WORD - size)));
07928
07929 gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
07930
07931 u = build2 (MODIFY_EXPR, void_type_node, addr, t);
07932 gimplify_and_add (u, pre_p);
07933
07934 t = build2 (PLUS_EXPR, ptr_type_node, t,
07935 fold_convert (ptr_type_node, size_int (size)));
07936 t = build2 (MODIFY_EXPR, ptr_type_node, ovf, t);
07937 gimplify_and_add (t, pre_p);
07938
07939 t = build1 (LABEL_EXPR, void_type_node, lab_over);
07940 append_to_statement_list (t, pre_p);
07941
07942
07943
07944
07945 u = build2 (PREINCREMENT_EXPR, TREE_TYPE (reg), reg,
07946 fold_convert (TREE_TYPE (reg), size_int (n_reg)));
07947 gimplify_and_add (u, pre_p);
07948
07949 if (indirect_p)
07950 {
07951 t = build_pointer_type (build_pointer_type (type));
07952 addr = fold_convert (t, addr);
07953 addr = build_va_arg_indirect_ref (addr);
07954 }
07955 else
07956 {
07957 t = build_pointer_type (type);
07958 addr = fold_convert (t, addr);
07959 }
07960
07961 return build_va_arg_indirect_ref (addr);
07962 }
07963
07964
07965
07966
07967 enum s390_builtin
07968 {
07969 S390_BUILTIN_THREAD_POINTER,
07970 S390_BUILTIN_SET_THREAD_POINTER,
07971
07972 S390_BUILTIN_max
07973 };
07974
07975 static unsigned int const code_for_builtin_64[S390_BUILTIN_max] = {
07976 CODE_FOR_get_tp_64,
07977 CODE_FOR_set_tp_64
07978 };
07979
07980 static unsigned int const code_for_builtin_31[S390_BUILTIN_max] = {
07981 CODE_FOR_get_tp_31,
07982 CODE_FOR_set_tp_31
07983 };
07984
07985 static void
07986 s390_init_builtins (void)
07987 {
07988 tree ftype;
07989
07990 ftype = build_function_type (ptr_type_node, void_list_node);
07991 lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
07992 S390_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
07993 NULL, NULL_TREE);
07994
07995 ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
07996 lang_hooks.builtin_function ("__builtin_set_thread_pointer", ftype,
07997 S390_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
07998 NULL, NULL_TREE);
07999 }
08000
08001
08002
08003
08004
08005
08006
08007 static rtx
08008 s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
08009 enum machine_mode mode ATTRIBUTE_UNUSED,
08010 int ignore ATTRIBUTE_UNUSED)
08011 {
08012 #define MAX_ARGS 2
08013
08014 unsigned int const *code_for_builtin =
08015 TARGET_64BIT ? code_for_builtin_64 : code_for_builtin_31;
08016
08017 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
08018 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
08019 tree arglist = TREE_OPERAND (exp, 1);
08020 enum insn_code icode;
08021 rtx op[MAX_ARGS], pat;
08022 int arity;
08023 bool nonvoid;
08024
08025 if (fcode >= S390_BUILTIN_max)
08026 internal_error ("bad builtin fcode");
08027 icode = code_for_builtin[fcode];
08028 if (icode == 0)
08029 internal_error ("bad builtin fcode");
08030
08031 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
08032
08033 for (arglist = TREE_OPERAND (exp, 1), arity = 0;
08034 arglist;
08035 arglist = TREE_CHAIN (arglist), arity++)
08036 {
08037 const struct insn_operand_data *insn_op;
08038
08039 tree arg = TREE_VALUE (arglist);
08040 if (arg == error_mark_node)
08041 return NULL_RTX;
08042 if (arity > MAX_ARGS)
08043 return NULL_RTX;
08044
08045 insn_op = &insn_data[icode].operand[arity + nonvoid];
08046
08047 op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, 0);
08048
08049 if (!(*insn_op->predicate) (op[arity], insn_op->mode))
08050 op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
08051 }
08052
08053 if (nonvoid)
08054 {
08055 enum machine_mode tmode = insn_data[icode].operand[0].mode;
08056 if (!target
08057 || GET_MODE (target) != tmode
08058 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
08059 target = gen_reg_rtx (tmode);
08060 }
08061
08062 switch (arity)
08063 {
08064 case 0:
08065 pat = GEN_FCN (icode) (target);
08066 break;
08067 case 1:
08068 if (nonvoid)
08069 pat = GEN_FCN (icode) (target, op[0]);
08070 else
08071 pat = GEN_FCN (icode) (op[0]);
08072 break;
08073 case 2:
08074 pat = GEN_FCN (icode) (target, op[0], op[1]);
08075 break;
08076 default:
08077 abort ();
08078 }
08079 if (!pat)
08080 return NULL_RTX;
08081 emit_insn (pat);
08082
08083 if (nonvoid)
08084 return target;
08085 else
08086 return const0_rtx;
08087 }
08088
08089
08090
08091
08092
08093
08094
08095
08096 void
08097 s390_trampoline_template (FILE *file)
08098 {
08099 rtx op[2];
08100 op[0] = gen_rtx_REG (Pmode, 0);
08101 op[1] = gen_rtx_REG (Pmode, 1);
08102
08103 if (TARGET_64BIT)
08104 {
08105 output_asm_insn ("basr\t%1,0", op);
08106 output_asm_insn ("lmg\t%0,%1,14(%1)", op);
08107 output_asm_insn ("br\t%1", op);
08108 ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 10));
08109 }
08110 else
08111 {
08112 output_asm_insn ("basr\t%1,0", op);
08113 output_asm_insn ("lm\t%0,%1,6(%1)", op);
08114 output_asm_insn ("br\t%1", op);
08115 ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 8));
08116 }
08117 }
08118
08119
08120
08121
08122
08123 void
08124 s390_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
08125 {
08126 emit_move_insn (gen_rtx_MEM (Pmode,
08127 memory_address (Pmode,
08128 plus_constant (addr, (TARGET_64BIT ? 16 : 8)))), cxt);
08129 emit_move_insn (gen_rtx_MEM (Pmode,
08130 memory_address (Pmode,
08131 plus_constant (addr, (TARGET_64BIT ? 24 : 12)))), fnaddr);
08132 }
08133
08134
08135
08136
08137 rtx
08138 s390_gen_rtx_const_DI (int high, int low)
08139 {
08140 #if HOST_BITS_PER_WIDE_INT >= 64
08141 HOST_WIDE_INT val;
08142 val = (HOST_WIDE_INT)high;
08143 val <<= 32;
08144 val |= (HOST_WIDE_INT)low;
08145
08146 return GEN_INT (val);
08147 #else
08148 #if HOST_BITS_PER_WIDE_INT >= 32
08149 return immed_double_const ((HOST_WIDE_INT)low, (HOST_WIDE_INT)high, DImode);
08150 #else
08151 abort ();
08152 #endif
08153 #endif
08154 }
08155
08156
08157
08158
08159 void
08160 s390_function_profiler (FILE *file, int labelno)
08161 {
08162 rtx op[7];
08163
08164 char label[128];
08165 ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
08166
08167 fprintf (file, "# function profiler \n");
08168
08169 op[0] = gen_rtx_REG (Pmode, RETURN_REGNUM);
08170 op[1] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
08171 op[1] = gen_rtx_MEM (Pmode, plus_constant (op[1], UNITS_PER_WORD));
08172
08173 op[2] = gen_rtx_REG (Pmode, 1);
08174 op[3] = gen_rtx_SYMBOL_REF (Pmode, label);
08175 SYMBOL_REF_FLAGS (op[3]) = SYMBOL_FLAG_LOCAL;
08176
08177 op[4] = gen_rtx_SYMBOL_REF (Pmode, "_mcount");
08178 if (flag_pic)
08179 {
08180 op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), UNSPEC_PLT);
08181 op[4] = gen_rtx_CONST (Pmode, op[4]);
08182 }
08183
08184 if (TARGET_64BIT)
08185 {
08186 output_asm_insn ("stg\t%0,%1", op);
08187 output_asm_insn ("larl\t%2,%3", op);
08188 output_asm_insn ("brasl\t%0,%4", op);
08189 output_asm_insn ("lg\t%0,%1", op);
08190 }
08191 else if (!flag_pic)
08192 {
08193 op[6] = gen_label_rtx ();
08194
08195 output_asm_insn ("st\t%0,%1", op);
08196 output_asm_insn ("bras\t%2,%l6", op);
08197 output_asm_insn (".long\t%4", op);
08198 output_asm_insn (".long\t%3", op);
08199 targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6]));
08200 output_asm_insn ("l\t%0,0(%2)", op);
08201 output_asm_insn ("l\t%2,4(%2)", op);
08202 output_asm_insn ("basr\t%0,%0", op);
08203 output_asm_insn ("l\t%0,%1", op);
08204 }
08205 else
08206 {
08207 op[5] = gen_label_rtx ();
08208 op[6] = gen_label_rtx ();
08209
08210 output_asm_insn ("st\t%0,%1", op);
08211 output_asm_insn ("bras\t%2,%l6", op);
08212 targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[5]));
08213 output_asm_insn (".long\t%4-%l5", op);
08214 output_asm_insn (".long\t%3-%l5", op);
08215 targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6]));
08216 output_asm_insn ("lr\t%0,%2", op);
08217 output_asm_insn ("a\t%0,0(%2)", op);
08218 output_asm_insn ("a\t%2,4(%2)", op);
08219 output_asm_insn ("basr\t%0,%0", op);
08220 output_asm_insn ("l\t%0,%1", op);
08221 }
08222 }
08223
08224
08225
08226
08227 static void
08228 s390_encode_section_info (tree decl, rtx rtl, int first)
08229 {
08230 default_encode_section_info (decl, rtl, first);
08231
08232
08233
08234 if (TREE_CODE (decl) == VAR_DECL
08235 && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16)
08236 SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1;
08237 }
08238
08239
08240
08241
08242
08243
08244
08245 static void
08246 s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
08247 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
08248 tree function)
08249 {
08250 rtx op[10];
08251 int nonlocal = 0;
08252
08253
08254 op[0] = XEXP (DECL_RTL (function), 0);
08255 if (flag_pic && !SYMBOL_REF_LOCAL_P (op[0]))
08256 {
08257 nonlocal = 1;
08258 op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]),
08259 TARGET_64BIT ? UNSPEC_PLT : UNSPEC_GOT);
08260 op[0] = gen_rtx_CONST (Pmode, op[0]);
08261 }
08262
08263
08264 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
08265 op[1] = gen_rtx_REG (Pmode, 3);
08266 else
08267 op[1] = gen_rtx_REG (Pmode, 2);
08268
08269
08270 op[2] = GEN_INT (delta);
08271
08272
08273 op[3] = GEN_INT (vcall_offset);
08274
08275
08276 op[4] = gen_rtx_REG (Pmode, 1);
08277
08278
08279 op[5] = NULL_RTX;
08280 op[6] = NULL_RTX;
08281 op[7] = NULL_RTX;
08282 op[8] = NULL_RTX;
08283
08284
08285 op[9] = NULL_RTX;
08286
08287
08288 if (TARGET_64BIT)
08289 {
08290
08291 if ((!DISP_IN_RANGE (delta)
08292 && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
08293 || (!DISP_IN_RANGE (vcall_offset)
08294 && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")))
08295 {
08296 op[5] = gen_label_rtx ();
08297 output_asm_insn ("larl\t%4,%5", op);
08298 }
08299
08300
08301 if (delta)
08302 {
08303 if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J"))
08304 output_asm_insn ("la\t%1,%2(%1)", op);
08305 else if (DISP_IN_RANGE (delta))
08306 output_asm_insn ("lay\t%1,%2(%1)", op);
08307 else if (CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
08308 output_asm_insn ("aghi\t%1,%2", op);
08309 else
08310 {
08311 op[6] = gen_label_rtx ();
08312 output_asm_insn ("agf\t%1,%6-%5(%4)", op);
08313 }
08314 }
08315
08316
08317 if (vcall_offset)
08318 {
08319 if (DISP_IN_RANGE (vcall_offset))
08320 {
08321 output_asm_insn ("lg\t%4,0(%1)", op);
08322 output_asm_insn ("ag\t%1,%3(%4)", op);
08323 }
08324 else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))
08325 {
08326 output_asm_insn ("lghi\t%4,%3", op);
08327 output_asm_insn ("ag\t%4,0(%1)", op);
08328 output_asm_insn ("ag\t%1,0(%4)", op);
08329 }
08330 else
08331 {
08332 op[7] = gen_label_rtx ();
08333 output_asm_insn ("llgf\t%4,%7-%5(%4)", op);
08334 output_asm_insn ("ag\t%4,0(%1)", op);
08335 output_asm_insn ("ag\t%1,0(%4)", op);
08336 }
08337 }
08338
08339
08340 output_asm_insn ("jg\t%0", op);
08341
08342
08343 if (op[5])
08344 {
08345 output_asm_insn (".align\t4", op);
08346 targetm.asm_out.internal_label (file, "L",
08347 CODE_LABEL_NUMBER (op[5]));
08348 }
08349 if (op[6])
08350 {
08351 targetm.asm_out.internal_label (file, "L",
08352 CODE_LABEL_NUMBER (op[6]));
08353 output_asm_insn (".long\t%2", op);
08354 }
08355 if (op[7])
08356 {
08357 targetm.asm_out.internal_label (file, "L",
08358 CODE_LABEL_NUMBER (op[7]));
08359 output_asm_insn (".long\t%3", op);
08360 }
08361 }
08362 else
08363 {
08364
08365 if (!vcall_offset
08366 || (!DISP_IN_RANGE (delta)
08367 && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
08368 || (!DISP_IN_RANGE (delta)
08369 && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")))
08370 {
08371 op[5] = gen_label_rtx ();
08372 output_asm_insn ("basr\t%4,0", op);
08373 targetm.asm_out.internal_label (file, "L",
08374 CODE_LABEL_NUMBER (op[5]));
08375 }
08376
08377
08378 if (delta)
08379 {
08380 if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J"))
08381 output_asm_insn ("la\t%1,%2(%1)", op);
08382 else if (DISP_IN_RANGE (delta))
08383 output_asm_insn ("lay\t%1,%2(%1)", op);
08384 else if (CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
08385 output_asm_insn ("ahi\t%1,%2", op);
08386 else
08387 {
08388 op[6] = gen_label_rtx ();
08389 output_asm_insn ("a\t%1,%6-%5(%4)", op);
08390 }
08391 }
08392
08393
08394 if (vcall_offset)
08395 {
08396 if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'J', "J"))
08397 {
08398 output_asm_insn ("l\t%4,0(%1)", op);
08399 output_asm_insn ("a\t%1,%3(%4)", op);
08400 }
08401 else if (DISP_IN_RANGE (vcall_offset))
08402 {
08403 output_asm_insn ("l\t%4,0(%1)", op);
08404 output_asm_insn ("ay\t%1,%3(%4)", op);
08405 }
08406 else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))
08407 {
08408 output_asm_insn ("lhi\t%4,%3", op);
08409 output_asm_insn ("a\t%4,0(%1)", op);
08410 output_asm_insn ("a\t%1,0(%4)", op);
08411 }
08412 else
08413 {
08414 op[7] = gen_label_rtx ();
08415 output_asm_insn ("l\t%4,%7-%5(%4)", op);
08416 output_asm_insn ("a\t%4,0(%1)", op);
08417 output_asm_insn ("a\t%1,0(%4)", op);
08418 }
08419
08420
08421
08422 op[5] = gen_label_rtx ();
08423 output_asm_insn ("basr\t%4,0", op);
08424 targetm.asm_out.internal_label (file, "L",
08425 CODE_LABEL_NUMBER (op[5]));
08426 }
08427
08428
08429 op[8] = gen_label_rtx ();
08430
08431 if (!flag_pic)
08432 output_asm_insn ("l\t%4,%8-%5(%4)", op);
08433 else if (!nonlocal)
08434 output_asm_insn ("a\t%4,%8-%5(%4)", op);
08435
08436 else if (flag_pic == 1)
08437 {
08438 output_asm_insn ("a\t%4,%8-%5(%4)", op);
08439 output_asm_insn ("l\t%4,%0(%4)", op);
08440 }
08441 else if (flag_pic == 2)
08442 {
08443 op[9] = gen_rtx_REG (Pmode, 0);
08444 output_asm_insn ("l\t%9,%8-4-%5(%4)", op);
08445 output_asm_insn ("a\t%4,%8-%5(%4)", op);
08446 output_asm_insn ("ar\t%4,%9", op);
08447 output_asm_insn ("l\t%4,0(%4)", op);
08448 }
08449
08450 output_asm_insn ("br\t%4", op);
08451
08452
08453 output_asm_insn (".align\t4", op);
08454
08455 if (nonlocal && flag_pic == 2)
08456 output_asm_insn (".long\t%0", op);
08457 if (nonlocal)
08458 {
08459 op[0] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
08460 SYMBOL_REF_FLAGS (op[0]) = SYMBOL_FLAG_LOCAL;
08461 }
08462
08463 targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[8]));
08464 if (!flag_pic)
08465 output_asm_insn (".long\t%0", op);
08466 else
08467 output_asm_insn (".long\t%0-%5", op);
08468
08469 if (op[6])
08470 {
08471 targetm.asm_out.internal_label (file, "L",
08472 CODE_LABEL_NUMBER (op[6]));
08473 output_asm_insn (".long\t%2", op);
08474 }
08475 if (op[7])
08476 {
08477 targetm.asm_out.internal_label (file, "L",
08478 CODE_LABEL_NUMBER (op[7]));
08479 output_asm_insn (".long\t%3", op);
08480 }
08481 }
08482 }
08483
08484 bool
08485 s390_valid_pointer_mode (enum machine_mode mode)
08486 {
08487 return (mode == SImode || (TARGET_64BIT && mode == DImode));
08488 }
08489
08490
08491
08492 static struct machine_function *
08493 s390_init_machine_status (void)
08494 {
08495 return ggc_alloc_cleared (sizeof (struct machine_function));
08496 }
08497
08498
08499
08500
08501
08502
08503 static bool
08504 s390_call_saved_register_used (tree argument_list)
08505 {
08506 CUMULATIVE_ARGS cum;
08507 tree parameter;
08508 enum machine_mode mode;
08509 tree type;
08510 rtx parm_rtx;
08511 int reg;
08512
08513 INIT_CUMULATIVE_ARGS (cum, NULL, NULL, 0, 0);
08514
08515 while (argument_list)
08516 {
08517 parameter = TREE_VALUE (argument_list);
08518 argument_list = TREE_CHAIN (argument_list);
08519
08520 if (!parameter)
08521 abort();
08522
08523
08524
08525 if (TREE_CODE (parameter) == ERROR_MARK)
08526 return true;
08527
08528 if (! (type = TREE_TYPE (parameter)))
08529 abort();
08530
08531 if (! (mode = TYPE_MODE (TREE_TYPE (parameter))))
08532 abort();
08533
08534 if (pass_by_reference (&cum, mode, type, true))
08535 {
08536 mode = Pmode;
08537 type = build_pointer_type (type);
08538 }
08539
08540 parm_rtx = s390_function_arg (&cum, mode, type, 0);
08541
08542 s390_function_arg_advance (&cum, mode, type, 0);
08543
08544 if (parm_rtx && REG_P (parm_rtx))
08545 {
08546 for (reg = 0;
08547 reg < HARD_REGNO_NREGS (REGNO (parm_rtx), GET_MODE (parm_rtx));
08548 reg++)
08549 if (! call_used_regs[reg + REGNO (parm_rtx)])
08550 return true;
08551 }
08552 }
08553 return false;
08554 }
08555
08556
08557
08558
08559
08560
08561 static bool
08562 s390_function_ok_for_sibcall (tree decl, tree exp)
08563 {
08564
08565 if (TARGET_TPF_PROFILING)
08566 return false;
08567
08568
08569
08570 if (!TARGET_64BIT && flag_pic && decl && TREE_PUBLIC (decl))
08571 return false;
08572
08573
08574
08575
08576 if (TREE_OPERAND (exp, 1)
08577 && s390_call_saved_register_used (TREE_OPERAND (exp, 1)))
08578 return false;
08579
08580 return true;
08581 }
08582
08583
08584
08585 static bool
08586 s390_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
08587 {
08588 *p1 = CC_REGNUM;
08589 *p2 = INVALID_REGNUM;
08590
08591 return true;
08592 }
08593
08594
08595
08596
08597
08598 static enum machine_mode
08599 s390_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
08600 {
08601 if (m1 == m2)
08602 return m1;
08603
08604 switch (m1)
08605 {
08606 case CCZmode:
08607 if (m2 == CCUmode || m2 == CCTmode
08608 || m2 == CCSmode || m2 == CCSRmode || m2 == CCURmode)
08609 return m2;
08610 return VOIDmode;
08611
08612 case CCSmode:
08613 case CCUmode:
08614 case CCTmode:
08615 case CCSRmode:
08616 case CCURmode:
08617 if (m2 == CCZmode)
08618 return m1;
08619
08620 return VOIDmode;
08621
08622 default:
08623 return VOIDmode;
08624 }
08625 return VOIDmode;
08626 }
08627
08628
08629
08630
08631
08632
08633
08634
08635
08636
08637
08638 rtx
08639 s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg,
08640 rtx retaddr_reg)
08641 {
08642 bool plt_call = false;
08643 rtx insn;
08644 rtx call;
08645 rtx clobber;
08646 rtvec vec;
08647
08648
08649 if (GET_CODE (addr_location) == SYMBOL_REF)
08650 {
08651
08652
08653 if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location))
08654 {
08655 addr_location = gen_rtx_UNSPEC (Pmode,
08656 gen_rtvec (1, addr_location),
08657 UNSPEC_PLT);
08658 addr_location = gen_rtx_CONST (Pmode, addr_location);
08659 plt_call = true;
08660 }
08661
08662
08663
08664 if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
08665 {
08666 if (flag_pic)
08667 addr_location = legitimize_pic_address (addr_location, 0);
08668 else
08669 addr_location = force_reg (Pmode, addr_location);
08670 }
08671 }
08672
08673
08674
08675
08676 if (retaddr_reg == NULL_RTX
08677 && GET_CODE (addr_location) != SYMBOL_REF
08678 && !plt_call)
08679 {
08680 emit_move_insn (gen_rtx_REG (Pmode, SIBCALL_REGNUM), addr_location);
08681 addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM);
08682 }
08683
08684 addr_location = gen_rtx_MEM (QImode, addr_location);
08685 call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx);
08686
08687 if (result_reg != NULL_RTX)
08688 call = gen_rtx_SET (VOIDmode, result_reg, call);
08689
08690 if (retaddr_reg != NULL_RTX)
08691 {
08692 clobber = gen_rtx_CLOBBER (VOIDmode, retaddr_reg);
08693
08694 if (tls_call != NULL_RTX)
08695 vec = gen_rtvec (3, call, clobber,
08696 gen_rtx_USE (VOIDmode, tls_call));
08697 else
08698 vec = gen_rtvec (2, call, clobber);
08699
08700 call = gen_rtx_PARALLEL (VOIDmode, vec);
08701 }
08702
08703 insn = emit_call_insn (call);
08704
08705
08706 if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX)
08707 {
08708
08709
08710 if (retaddr_reg == NULL_RTX)
08711 abort ();
08712
08713 use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
08714 }
08715 return insn;
08716 }
08717
08718
08719
08720 void
08721 s390_conditional_register_usage (void)
08722 {
08723 int i;
08724
08725 if (flag_pic)
08726 {
08727 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
08728 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
08729 }
08730 if (TARGET_CPU_ZARCH)
08731 {
08732 fixed_regs[RETURN_REGNUM] = 0;
08733 call_used_regs[RETURN_REGNUM] = 0;
08734 }
08735 if (TARGET_64BIT)
08736 {
08737 for (i = 24; i < 32; i++)
08738 call_used_regs[i] = call_really_used_regs[i] = 0;
08739 }
08740 else
08741 {
08742 for (i = 18; i < 20; i++)
08743 call_used_regs[i] = call_really_used_regs[i] = 0;
08744 }
08745
08746 if (TARGET_SOFT_FLOAT)
08747 {
08748 for (i = 16; i < 32; i++)
08749 call_used_regs[i] = fixed_regs[i] = 1;
08750 }
08751 }
08752
08753
08754
08755 static GTY(()) rtx s390_tpf_eh_return_symbol;
08756 void
08757 s390_emit_tpf_eh_return (rtx target)
08758 {
08759 rtx insn, reg;
08760
08761 if (!s390_tpf_eh_return_symbol)
08762 s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return");
08763
08764 reg = gen_rtx_REG (Pmode, 2);
08765
08766 emit_move_insn (reg, target);
08767 insn = s390_emit_call (s390_tpf_eh_return_symbol, NULL_RTX, reg,
08768 gen_rtx_REG (Pmode, RETURN_REGNUM));
08769 use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg);
08770
08771 emit_move_insn (EH_RETURN_HANDLER_RTX, reg);
08772 }
08773
08774 #include "gt-s390.h"