00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024 #include "system.h"
00025 #include "rtl.h"
00026 #include "tree.h"
00027 #include "tm_p.h"
00028 #include "regs.h"
00029 #include "hard-reg-set.h"
00030 #include "real.h"
00031 #include "insn-config.h"
00032 #include "conditions.h"
00033 #include "output.h"
00034 #include "insn-attr.h"
00035 #include "flags.h"
00036 #include "except.h"
00037 #include "function.h"
00038 #include "recog.h"
00039 #include "expr.h"
00040 #include "reload.h"
00041 #include "toplev.h"
00042 #include "basic-block.h"
00043 #include "integrate.h"
00044 #include "ggc.h"
00045 #include "target.h"
00046 #include "target-def.h"
00047 #include "debug.h"
00048
00049
00050 static bool s390_assemble_integer PARAMS ((rtx, unsigned int, int));
00051 static int s390_adjust_cost PARAMS ((rtx, rtx, rtx, int));
00052 static int s390_adjust_priority PARAMS ((rtx, int));
00053
00054 #undef TARGET_ASM_ALIGNED_HI_OP
00055 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
00056 #undef TARGET_ASM_ALIGNED_DI_OP
00057 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
00058 #undef TARGET_ASM_INTEGER
00059 #define TARGET_ASM_INTEGER s390_assemble_integer
00060
00061 #undef TARGET_ASM_FUNCTION_PROLOGUE
00062 #define TARGET_ASM_FUNCTION_PROLOGUE s390_function_prologue
00063
00064 #undef TARGET_ASM_FUNCTION_EPILOGUE
00065 #define TARGET_ASM_FUNCTION_EPILOGUE s390_function_epilogue
00066
00067 #undef TARGET_ASM_OPEN_PAREN
00068 #define TARGET_ASM_OPEN_PAREN ""
00069
00070 #undef TARGET_ASM_CLOSE_PAREN
00071 #define TARGET_ASM_CLOSE_PAREN ""
00072
00073 #undef TARGET_SCHED_ADJUST_COST
00074 #define TARGET_SCHED_ADJUST_COST s390_adjust_cost
00075
00076 #undef TARGET_SCHED_ADJUST_PRIORITY
00077 #define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority
00078
00079 struct gcc_target targetm = TARGET_INITIALIZER;
00080
00081 extern int reload_completed;
00082
00083
00084 static int s390_sr_alias_set = 0;
00085
00086
00087 int s390_function_count = 0;
00088
00089
00090
00091 rtx s390_compare_op0, s390_compare_op1;
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 struct s390_address
00103 {
00104 rtx base;
00105 rtx indx;
00106 rtx disp;
00107 int pointer;
00108 };
00109
00110
00111
00112 struct s390_frame
00113 {
00114 int frame_pointer_p;
00115 int return_reg_saved_p;
00116 int save_fprs_p;
00117 int first_save_gpr;
00118 int first_restore_gpr;
00119 int last_save_gpr;
00120 int arg_frame_offset;
00121
00122 HOST_WIDE_INT frame_size;
00123 };
00124
00125 static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));
00126 static int s390_branch_condition_mask PARAMS ((rtx));
00127 static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int));
00128 static int check_mode PARAMS ((rtx, enum machine_mode *));
00129 static int general_s_operand PARAMS ((rtx, enum machine_mode, int));
00130 static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));
00131 static int reg_used_in_mem_p PARAMS ((int, rtx));
00132 static int addr_generation_dependency_p PARAMS ((rtx, rtx));
00133 static void s390_split_branches PARAMS ((void));
00134 static void find_constant_pool_ref PARAMS ((rtx, rtx *));
00135 static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));
00136 static void s390_chunkify_pool PARAMS ((void));
00137 static int save_fprs_p PARAMS ((void));
00138 static int find_unused_clobbered_reg PARAMS ((void));
00139 static void s390_frame_info PARAMS ((struct s390_frame *));
00140 static rtx save_fpr PARAMS ((rtx, int, int));
00141 static rtx restore_fpr PARAMS ((rtx, int, int));
00142 static int s390_function_arg_size PARAMS ((enum machine_mode, tree));
00143
00144
00145
00146
00147
00148
00149 static int
00150 s390_match_ccmode_set (set, req_mode)
00151 rtx set;
00152 enum machine_mode req_mode;
00153 {
00154 enum machine_mode set_mode;
00155
00156 if (GET_CODE (set) != SET)
00157 abort ();
00158
00159 if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set))))
00160 return 1;
00161
00162 set_mode = GET_MODE (SET_DEST (set));
00163 switch (set_mode)
00164 {
00165 case CCSmode:
00166 if (req_mode != CCSmode)
00167 return 0;
00168 break;
00169 case CCUmode:
00170 if (req_mode != CCUmode)
00171 return 0;
00172 break;
00173 case CCLmode:
00174 if (req_mode != CCLmode)
00175 return 0;
00176 break;
00177 case CCZmode:
00178 if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode)
00179 return 0;
00180 break;
00181
00182 default:
00183 abort ();
00184 }
00185
00186 return (GET_MODE (SET_SRC (set)) == set_mode);
00187 }
00188
00189
00190
00191
00192
00193 int
00194 s390_match_ccmode (insn, req_mode)
00195 rtx insn;
00196 enum machine_mode req_mode;
00197 {
00198 int i;
00199
00200 if (GET_CODE (PATTERN (insn)) == SET)
00201 return s390_match_ccmode_set (PATTERN (insn), req_mode);
00202
00203 if (GET_CODE (PATTERN (insn)) == PARALLEL)
00204 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
00205 {
00206 rtx set = XVECEXP (PATTERN (insn), 0, i);
00207 if (GET_CODE (set) == SET)
00208 if (!s390_match_ccmode_set (set, req_mode))
00209 return 0;
00210 }
00211
00212 return 1;
00213 }
00214
00215
00216
00217
00218
00219 enum machine_mode
00220 s390_select_ccmode (code, op0, op1)
00221 enum rtx_code code;
00222 rtx op0;
00223 rtx op1;
00224 {
00225 switch (code)
00226 {
00227 case EQ:
00228 case NE:
00229 if (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
00230 || GET_CODE (op1) == NEG)
00231 return CCLmode;
00232
00233 return CCZmode;
00234
00235 case LE:
00236 case LT:
00237 case GE:
00238 case GT:
00239 case UNORDERED:
00240 case ORDERED:
00241 case UNEQ:
00242 case UNLE:
00243 case UNLT:
00244 case UNGE:
00245 case UNGT:
00246 case LTGT:
00247 return CCSmode;
00248
00249 case LEU:
00250 case LTU:
00251 case GEU:
00252 case GTU:
00253 return CCUmode;
00254
00255 default:
00256 abort ();
00257 }
00258 }
00259
00260
00261
00262
00263 static int
00264 s390_branch_condition_mask (code)
00265 rtx code;
00266 {
00267 const int CC0 = 1 << 3;
00268 const int CC1 = 1 << 2;
00269 const int CC2 = 1 << 1;
00270 const int CC3 = 1 << 0;
00271
00272 if (GET_CODE (XEXP (code, 0)) != REG
00273 || REGNO (XEXP (code, 0)) != CC_REGNUM
00274 || XEXP (code, 1) != const0_rtx)
00275 abort ();
00276
00277 switch (GET_MODE (XEXP (code, 0)))
00278 {
00279 case CCZmode:
00280 switch (GET_CODE (code))
00281 {
00282 case EQ: return CC0;
00283 case NE: return CC1 | CC2 | CC3;
00284 default:
00285 abort ();
00286 }
00287 break;
00288
00289 case CCLmode:
00290 switch (GET_CODE (code))
00291 {
00292 case EQ: return CC0 | CC2;
00293 case NE: return CC1 | CC3;
00294 case UNORDERED: return CC2 | CC3;
00295 case ORDERED: return CC0 | CC1;
00296 default:
00297 abort ();
00298 }
00299 break;
00300
00301 case CCUmode:
00302 switch (GET_CODE (code))
00303 {
00304 case EQ: return CC0;
00305 case NE: return CC1 | CC2 | CC3;
00306 case LTU: return CC1;
00307 case GTU: return CC2;
00308 case LEU: return CC0 | CC1;
00309 case GEU: return CC0 | CC2;
00310 default:
00311 abort ();
00312 }
00313 break;
00314
00315 case CCSmode:
00316 switch (GET_CODE (code))
00317 {
00318 case EQ: return CC0;
00319 case NE: return CC1 | CC2 | CC3;
00320 case LT: return CC1;
00321 case GT: return CC2;
00322 case LE: return CC0 | CC1;
00323 case GE: return CC0 | CC2;
00324 case UNORDERED: return CC3;
00325 case ORDERED: return CC0 | CC1 | CC2;
00326 case UNEQ: return CC0 | CC3;
00327 case UNLT: return CC1 | CC3;
00328 case UNGT: return CC2 | CC3;
00329 case UNLE: return CC0 | CC1 | CC3;
00330 case UNGE: return CC0 | CC2 | CC3;
00331 case LTGT: return CC1 | CC2;
00332 default:
00333 abort ();
00334 }
00335
00336 default:
00337 abort ();
00338 }
00339 }
00340
00341
00342
00343
00344
00345 static const char *
00346 s390_branch_condition_mnemonic (code, inv)
00347 rtx code;
00348 int inv;
00349 {
00350 static const char *mnemonic[16] =
00351 {
00352 NULL, "o", "h", "nle",
00353 "l", "nhe", "lh", "ne",
00354 "e", "nlh", "he", "nl",
00355 "le", "nh", "no", NULL
00356 };
00357
00358 int mask = s390_branch_condition_mask (code);
00359
00360 if (inv)
00361 mask ^= 15;
00362
00363 if (mask < 1 || mask > 14)
00364 abort ();
00365
00366 return mnemonic[mask];
00367 }
00368
00369
00370
00371
00372
00373
00374 int
00375 s390_single_hi (op, mode, def)
00376 rtx op;
00377 enum machine_mode mode;
00378 int def;
00379 {
00380 if (GET_CODE (op) == CONST_INT)
00381 {
00382 unsigned HOST_WIDE_INT value;
00383 int n_parts = GET_MODE_SIZE (mode) / 2;
00384 int i, part = -1;
00385
00386 for (i = 0; i < n_parts; i++)
00387 {
00388 if (i == 0)
00389 value = (unsigned HOST_WIDE_INT) INTVAL (op);
00390 else
00391 value >>= 16;
00392
00393 if ((value & 0xffff) != (unsigned)(def & 0xffff))
00394 {
00395 if (part != -1)
00396 return -1;
00397 else
00398 part = i;
00399 }
00400 }
00401
00402 return part == -1 ? 0 : (n_parts - 1 - part);
00403 }
00404
00405 else if (GET_CODE (op) == CONST_DOUBLE
00406 && GET_MODE (op) == VOIDmode)
00407 {
00408 unsigned HOST_WIDE_INT value;
00409 int n_parts = GET_MODE_SIZE (mode) / 2;
00410 int i, part = -1;
00411
00412 for (i = 0; i < n_parts; i++)
00413 {
00414 if (i == 0)
00415 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
00416 else if (i == HOST_BITS_PER_WIDE_INT / 16)
00417 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op);
00418 else
00419 value >>= 16;
00420
00421 if ((value & 0xffff) != (unsigned)(def & 0xffff))
00422 {
00423 if (part != -1)
00424 return -1;
00425 else
00426 part = i;
00427 }
00428 }
00429
00430 return part == -1 ? 0 : (n_parts - 1 - part);
00431 }
00432
00433 return -1;
00434 }
00435
00436
00437
00438
00439 int
00440 s390_extract_hi (op, mode, part)
00441 rtx op;
00442 enum machine_mode mode;
00443 int part;
00444 {
00445 int n_parts = GET_MODE_SIZE (mode) / 2;
00446 if (part < 0 || part >= n_parts)
00447 abort();
00448 else
00449 part = n_parts - 1 - part;
00450
00451 if (GET_CODE (op) == CONST_INT)
00452 {
00453 unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op);
00454 return ((value >> (16 * part)) & 0xffff);
00455 }
00456 else if (GET_CODE (op) == CONST_DOUBLE
00457 && GET_MODE (op) == VOIDmode)
00458 {
00459 unsigned HOST_WIDE_INT value;
00460 if (part < HOST_BITS_PER_WIDE_INT / 16)
00461 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
00462 else
00463 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op),
00464 part -= HOST_BITS_PER_WIDE_INT / 16;
00465
00466 return ((value >> (16 * part)) & 0xffff);
00467 }
00468
00469 abort ();
00470 }
00471
00472
00473
00474
00475
00476
00477 int
00478 s390_single_qi (op, mode, def)
00479 rtx op;
00480 enum machine_mode mode;
00481 int def;
00482 {
00483 if (GET_CODE (op) == CONST_INT)
00484 {
00485 unsigned HOST_WIDE_INT value;
00486 int n_parts = GET_MODE_SIZE (mode);
00487 int i, part = -1;
00488
00489 for (i = 0; i < n_parts; i++)
00490 {
00491 if (i == 0)
00492 value = (unsigned HOST_WIDE_INT) INTVAL (op);
00493 else
00494 value >>= 8;
00495
00496 if ((value & 0xff) != (unsigned)(def & 0xff))
00497 {
00498 if (part != -1)
00499 return -1;
00500 else
00501 part = i;
00502 }
00503 }
00504
00505 return part == -1 ? 0 : (n_parts - 1 - part);
00506 }
00507
00508 else if (GET_CODE (op) == CONST_DOUBLE
00509 && GET_MODE (op) == VOIDmode)
00510 {
00511 unsigned HOST_WIDE_INT value;
00512 int n_parts = GET_MODE_SIZE (mode);
00513 int i, part = -1;
00514
00515 for (i = 0; i < n_parts; i++)
00516 {
00517 if (i == 0)
00518 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
00519 else if (i == HOST_BITS_PER_WIDE_INT / 8)
00520 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op);
00521 else
00522 value >>= 8;
00523
00524 if ((value & 0xff) != (unsigned)(def & 0xff))
00525 {
00526 if (part != -1)
00527 return -1;
00528 else
00529 part = i;
00530 }
00531 }
00532
00533 return part == -1 ? 0 : (n_parts - 1 - part);
00534 }
00535
00536 return -1;
00537 }
00538
00539
00540
00541
00542 int
00543 s390_extract_qi (op, mode, part)
00544 rtx op;
00545 enum machine_mode mode;
00546 int part;
00547 {
00548 int n_parts = GET_MODE_SIZE (mode);
00549 if (part < 0 || part >= n_parts)
00550 abort();
00551 else
00552 part = n_parts - 1 - part;
00553
00554 if (GET_CODE (op) == CONST_INT)
00555 {
00556 unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op);
00557 return ((value >> (8 * part)) & 0xff);
00558 }
00559 else if (GET_CODE (op) == CONST_DOUBLE
00560 && GET_MODE (op) == VOIDmode)
00561 {
00562 unsigned HOST_WIDE_INT value;
00563 if (part < HOST_BITS_PER_WIDE_INT / 8)
00564 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
00565 else
00566 value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op),
00567 part -= HOST_BITS_PER_WIDE_INT / 8;
00568
00569 return ((value >> (8 * part)) & 0xff);
00570 }
00571
00572 abort ();
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 void
00585 optimization_options (level, size)
00586 int level ATTRIBUTE_UNUSED;
00587 int size ATTRIBUTE_UNUSED;
00588 {
00589 #ifdef HAVE_decrement_and_branch_on_count
00590
00591 if (level >= 1)
00592 flag_branch_on_count_reg = 1;
00593 #endif
00594 }
00595
00596 void
00597 override_options ()
00598 {
00599
00600 s390_sr_alias_set = new_alias_set ();
00601 }
00602
00603
00604
00605
00606 enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
00607 { GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
00608 ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
00609 ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
00610 ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
00611 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00612 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00613 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00614 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00615 ADDR_REGS, NO_REGS, ADDR_REGS
00616 };
00617
00618
00619
00620
00621
00622
00623 int
00624 const0_operand (op, mode)
00625 register rtx op;
00626 enum machine_mode mode;
00627 {
00628 return op == CONST0_RTX (mode);
00629 }
00630
00631
00632
00633
00634
00635 int
00636 consttable_operand (op, mode)
00637 rtx op;
00638 enum machine_mode mode ATTRIBUTE_UNUSED;
00639 {
00640 return CONSTANT_P (op);
00641 }
00642
00643
00644
00645
00646 static int
00647 check_mode (op, mode)
00648 register rtx op;
00649 enum machine_mode *mode;
00650 {
00651 if (*mode == VOIDmode)
00652 *mode = GET_MODE (op);
00653 else
00654 {
00655 if (GET_MODE (op) != VOIDmode && GET_MODE (op) != *mode)
00656 return 0;
00657 }
00658 return 1;
00659 }
00660
00661
00662
00663
00664
00665 int
00666 larl_operand (op, mode)
00667 register rtx op;
00668 enum machine_mode mode;
00669 {
00670 if (! check_mode (op, &mode))
00671 return 0;
00672
00673
00674 if (GET_CODE (op) == LABEL_REF)
00675 return 1;
00676 if (GET_CODE (op) == SYMBOL_REF
00677 && (!flag_pic || SYMBOL_REF_FLAG (op)
00678 || CONSTANT_POOL_ADDRESS_P (op)))
00679 return 1;
00680
00681
00682 if (GET_CODE (op) != CONST)
00683 return 0;
00684 op = XEXP (op, 0);
00685
00686
00687 if (GET_CODE (op) == PLUS)
00688 {
00689 if (GET_CODE (XEXP (op, 1)) != CONST_INT
00690 || (INTVAL (XEXP (op, 1)) & 1) != 0)
00691 return 0;
00692 op = XEXP (op, 0);
00693 }
00694
00695
00696 if (GET_CODE (op) == LABEL_REF)
00697 return 1;
00698 if (GET_CODE (op) == SYMBOL_REF
00699 && (!flag_pic || SYMBOL_REF_FLAG (op)
00700 || CONSTANT_POOL_ADDRESS_P (op)))
00701 return 1;
00702
00703
00704 if (GET_CODE (op) == UNSPEC
00705 && XINT (op, 1) == 111)
00706 return 1;
00707 if (GET_CODE (op) == UNSPEC
00708 && XINT (op, 1) == 113)
00709 return 1;
00710
00711 return 0;
00712 }
00713
00714
00715
00716
00717
00718 int
00719 fp_operand (op, mode)
00720 register rtx op;
00721 enum machine_mode mode;
00722 {
00723 register enum rtx_code code = GET_CODE (op);
00724 if (! check_mode (op, &mode))
00725 return 0;
00726 if (code == REG && REGNO_OK_FOR_FP_P (REGNO (op)))
00727 return 1;
00728 else
00729 return 0;
00730 }
00731
00732
00733
00734
00735
00736
00737
00738 static int
00739 general_s_operand (op, mode, allow_immediate)
00740 register rtx op;
00741 enum machine_mode mode;
00742 int allow_immediate;
00743 {
00744 struct s390_address addr;
00745
00746
00747
00748 if (!general_operand (op, mode))
00749 return 0;
00750
00751
00752
00753 if (reload_completed
00754 && GET_CODE (op) == SUBREG
00755 && GET_CODE (SUBREG_REG (op)) == MEM)
00756 op = SUBREG_REG (op);
00757
00758 switch (GET_CODE (op))
00759 {
00760
00761
00762
00763
00764
00765 case CONST_INT:
00766 case CONST_DOUBLE:
00767 if (!allow_immediate || reload_completed)
00768 break;
00769 if (!legitimate_reload_constant_p (op))
00770 return 1;
00771 if (!TARGET_64BIT)
00772 return 1;
00773 break;
00774
00775
00776
00777 case MEM:
00778 if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
00779 return 1;
00780 if (s390_decompose_address (XEXP (op, 0), &addr, FALSE)
00781 && !addr.indx)
00782 return 1;
00783 break;
00784
00785 default:
00786 break;
00787 }
00788
00789 return 0;
00790 }
00791
00792
00793
00794
00795
00796 int
00797 s_operand (op, mode)
00798 register rtx op;
00799 enum machine_mode mode;
00800 {
00801 return general_s_operand (op, mode, 0);
00802 }
00803
00804
00805
00806
00807
00808
00809
00810 int
00811 s_imm_operand (op, mode)
00812 register rtx op;
00813 enum machine_mode mode;
00814 {
00815 return general_s_operand (op, mode, 1);
00816 }
00817
00818
00819
00820
00821
00822 int
00823 bras_sym_operand (op, mode)
00824 register rtx op;
00825 enum machine_mode mode ATTRIBUTE_UNUSED;
00826 {
00827 register enum rtx_code code = GET_CODE (op);
00828
00829
00830 if (code == SYMBOL_REF)
00831 return 1;
00832
00833
00834 if (code == CONST
00835 && GET_CODE (XEXP (op, 0)) == UNSPEC
00836 && XINT (XEXP (op, 0), 1) == 113)
00837 return 1;
00838 return 0;
00839 }
00840
00841
00842
00843
00844
00845
00846
00847 int
00848 load_multiple_operation (op, mode)
00849 rtx op;
00850 enum machine_mode mode ATTRIBUTE_UNUSED;
00851 {
00852 int count = XVECLEN (op, 0);
00853 unsigned int dest_regno;
00854 rtx src_addr;
00855 int i, off;
00856
00857
00858
00859 if (count <= 1
00860 || GET_CODE (XVECEXP (op, 0, 0)) != SET
00861 || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
00862 || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
00863 return 0;
00864
00865 dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
00866 src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
00867
00868
00869
00870 if (GET_CODE (src_addr) == REG)
00871 off = 0;
00872 else if (GET_CODE (src_addr) == PLUS
00873 && GET_CODE (XEXP (src_addr, 0)) == REG
00874 && GET_CODE (XEXP (src_addr, 1)) == CONST_INT)
00875 {
00876 off = INTVAL (XEXP (src_addr, 1));
00877 src_addr = XEXP (src_addr, 0);
00878 }
00879 else
00880 return 0;
00881
00882 if (src_addr == frame_pointer_rtx || src_addr == arg_pointer_rtx)
00883 return 0;
00884
00885 for (i = 1; i < count; i++)
00886 {
00887 rtx elt = XVECEXP (op, 0, i);
00888
00889 if (GET_CODE (elt) != SET
00890 || GET_CODE (SET_DEST (elt)) != REG
00891 || GET_MODE (SET_DEST (elt)) != Pmode
00892 || REGNO (SET_DEST (elt)) != dest_regno + i
00893 || GET_CODE (SET_SRC (elt)) != MEM
00894 || GET_MODE (SET_SRC (elt)) != Pmode
00895 || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
00896 || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
00897 || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
00898 || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1))
00899 != off + i * UNITS_PER_WORD)
00900 return 0;
00901 }
00902
00903 return 1;
00904 }
00905
00906
00907
00908
00909
00910
00911 int
00912 store_multiple_operation (op, mode)
00913 rtx op;
00914 enum machine_mode mode ATTRIBUTE_UNUSED;
00915 {
00916 int count = XVECLEN (op, 0);
00917 unsigned int src_regno;
00918 rtx dest_addr;
00919 int i, off;
00920
00921
00922 if (count <= 1
00923 || GET_CODE (XVECEXP (op, 0, 0)) != SET
00924 || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
00925 || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
00926 return 0;
00927
00928 src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
00929 dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
00930
00931
00932
00933 if (GET_CODE (dest_addr) == REG)
00934 off = 0;
00935 else if (GET_CODE (dest_addr) == PLUS
00936 && GET_CODE (XEXP (dest_addr, 0)) == REG
00937 && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT)
00938 {
00939 off = INTVAL (XEXP (dest_addr, 1));
00940 dest_addr = XEXP (dest_addr, 0);
00941 }
00942 else
00943 return 0;
00944
00945 if (dest_addr == frame_pointer_rtx || dest_addr == arg_pointer_rtx)
00946 return 0;
00947
00948 for (i = 1; i < count; i++)
00949 {
00950 rtx elt = XVECEXP (op, 0, i);
00951
00952 if (GET_CODE (elt) != SET
00953 || GET_CODE (SET_SRC (elt)) != REG
00954 || GET_MODE (SET_SRC (elt)) != Pmode
00955 || REGNO (SET_SRC (elt)) != src_regno + i
00956 || GET_CODE (SET_DEST (elt)) != MEM
00957 || GET_MODE (SET_DEST (elt)) != Pmode
00958 || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
00959 || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
00960 || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
00961 || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1))
00962 != off + i * UNITS_PER_WORD)
00963 return 0;
00964 }
00965 return 1;
00966 }
00967
00968
00969
00970
00971 int
00972 symbolic_reference_mentioned_p (op)
00973 rtx op;
00974 {
00975 register const char *fmt;
00976 register int i;
00977
00978 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
00979 return 1;
00980
00981 fmt = GET_RTX_FORMAT (GET_CODE (op));
00982 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
00983 {
00984 if (fmt[i] == 'E')
00985 {
00986 register int j;
00987
00988 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
00989 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
00990 return 1;
00991 }
00992
00993 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
00994 return 1;
00995 }
00996
00997 return 0;
00998 }
00999
01000
01001
01002
01003
01004
01005 int
01006 legitimate_pic_operand_p (op)
01007 register rtx op;
01008 {
01009
01010 if (!SYMBOLIC_CONST (op))
01011 return 1;
01012
01013
01014
01015 return 0;
01016 }
01017
01018
01019
01020
01021 int
01022 legitimate_constant_p (op)
01023 register rtx op;
01024 {
01025
01026 if (!SYMBOLIC_CONST (op))
01027 return 1;
01028
01029
01030
01031
01032 if (flag_pic)
01033 return 1;
01034
01035
01036
01037 if (TARGET_64BIT)
01038 return larl_operand (op, VOIDmode);
01039
01040
01041
01042 return 0;
01043 }
01044
01045
01046
01047
01048
01049
01050
01051 int
01052 legitimate_reload_constant_p (op)
01053 register rtx op;
01054 {
01055
01056 if (GET_CODE (op) == CONST_INT
01057 && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'))
01058 return 1;
01059
01060
01061 if (TARGET_64BIT
01062 && s390_single_hi (op, DImode, 0) >= 0)
01063 return 1;
01064
01065
01066 if (TARGET_64BIT
01067 && larl_operand (op, VOIDmode))
01068 return 1;
01069
01070
01071
01072
01073
01074
01075
01076 if (reload_completed && !regs_ever_live[BASE_REGISTER])
01077 abort ();
01078
01079
01080 return 0;
01081 }
01082
01083
01084
01085
01086 enum reg_class
01087 s390_preferred_reload_class (op, class)
01088 rtx op;
01089 enum reg_class class;
01090 {
01091
01092
01093 if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
01094 && class != FP_REGS)
01095 return class;
01096
01097 switch (GET_CODE (op))
01098 {
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108 case CONST_DOUBLE:
01109 case CONST_INT:
01110 if (!legitimate_reload_constant_p (op))
01111 return NO_REGS;
01112
01113 if (TARGET_64BIT && current_function_is_leaf)
01114 return class;
01115
01116 return NO_REGS;
01117
01118
01119
01120
01121
01122 case PLUS:
01123 case LABEL_REF:
01124 case SYMBOL_REF:
01125 case CONST:
01126 if (reg_class_subset_p (ADDR_REGS, class))
01127 return ADDR_REGS;
01128 else
01129 return NO_REGS;
01130
01131 default:
01132 break;
01133 }
01134
01135 return class;
01136 }
01137
01138
01139
01140
01141
01142
01143
01144 enum reg_class
01145 s390_secondary_input_reload_class (class, mode, in)
01146 enum reg_class class ATTRIBUTE_UNUSED;
01147 enum machine_mode mode;
01148 rtx in;
01149 {
01150 if (s390_plus_operand (in, mode))
01151 return ADDR_REGS;
01152
01153 return NO_REGS;
01154 }
01155
01156
01157
01158
01159
01160
01161 int
01162 s390_plus_operand (op, mode)
01163 register rtx op;
01164 enum machine_mode mode;
01165 {
01166 if (!check_mode (op, &mode) || mode != Pmode)
01167 return FALSE;
01168
01169 if (GET_CODE (op) != PLUS)
01170 return FALSE;
01171
01172 if (legitimate_la_operand_p (op))
01173 return FALSE;
01174
01175 return TRUE;
01176 }
01177
01178
01179
01180
01181
01182 void
01183 s390_expand_plus_operand (target, src, scratch_in)
01184 register rtx target;
01185 register rtx src;
01186 register rtx scratch_in;
01187 {
01188 rtx sum1, sum2, scratch;
01189
01190
01191
01192
01193
01194
01195 scratch = gen_rtx_REG (Pmode, REGNO (scratch_in));
01196 if (rtx_equal_p (scratch, target))
01197 scratch = gen_rtx_REG (Pmode, REGNO (scratch_in) + 1);
01198
01199
01200 if (GET_CODE (src) != PLUS || GET_MODE (src) != Pmode)
01201 abort ();
01202
01203
01204
01205
01206 sum1 = find_replacement (&XEXP (src, 0));
01207 sum2 = find_replacement (&XEXP (src, 1));
01208
01209
01210
01211
01212 if (rtx_equal_p (target, sum2)
01213 || GET_CODE (sum1) == CONST_INT)
01214 {
01215 rtx tem = sum2;
01216 sum2 = sum1;
01217 sum1 = tem;
01218 }
01219
01220
01221
01222 if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15)
01223 {
01224 emit_move_insn (target, sum1);
01225 sum1 = target;
01226 }
01227
01228
01229
01230
01231
01232 if ((true_regnum (sum2) < 1 || true_regnum (sum2) > 15)
01233 && !(GET_CODE (sum2) == CONST_INT
01234 && INTVAL (sum2) >= 0 && INTVAL (sum2) < 4096))
01235 {
01236 if (!rtx_equal_p (target, sum1))
01237 {
01238 emit_move_insn (target, sum2);
01239 sum2 = target;
01240 }
01241 else
01242 {
01243 emit_move_insn (scratch, sum2);
01244 sum2 = scratch;
01245 }
01246 }
01247
01248
01249
01250
01251 src = gen_rtx_PLUS (Pmode, sum1, sum2);
01252 src = legitimize_la_operand (src);
01253 emit_insn (gen_rtx_SET (VOIDmode, target, src));
01254 }
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 static int
01269 s390_decompose_address (addr, out, strict)
01270 register rtx addr;
01271 struct s390_address *out;
01272 int strict;
01273 {
01274 rtx base = NULL_RTX;
01275 rtx indx = NULL_RTX;
01276 rtx disp = NULL_RTX;
01277 int pointer = FALSE;
01278
01279
01280
01281 if (GET_CODE (addr) == REG || GET_CODE (addr) == UNSPEC)
01282 base = addr;
01283
01284 else if (GET_CODE (addr) == PLUS)
01285 {
01286 rtx op0 = XEXP (addr, 0);
01287 rtx op1 = XEXP (addr, 1);
01288 enum rtx_code code0 = GET_CODE (op0);
01289 enum rtx_code code1 = GET_CODE (op1);
01290
01291 if (code0 == REG || code0 == UNSPEC)
01292 {
01293 if (code1 == REG || code1 == UNSPEC)
01294 {
01295 indx = op0;
01296 base = op1;
01297 }
01298
01299 else
01300 {
01301 base = op0;
01302 disp = op1;
01303 }
01304 }
01305
01306 else if (code0 == PLUS)
01307 {
01308 indx = XEXP (op0, 0);
01309 base = XEXP (op0, 1);
01310 disp = op1;
01311 }
01312
01313 else
01314 {
01315 return FALSE;
01316 }
01317 }
01318
01319 else
01320 disp = addr;
01321
01322
01323
01324 if (base)
01325 {
01326 if (GET_CODE (base) == UNSPEC)
01327 {
01328 if (XVECLEN (base, 0) != 1 || XINT (base, 1) != 101)
01329 return FALSE;
01330 base = XVECEXP (base, 0, 0);
01331 pointer = TRUE;
01332 }
01333
01334 if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
01335 return FALSE;
01336
01337 if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
01338 || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
01339 return FALSE;
01340
01341 if (REGNO (base) == BASE_REGISTER
01342 || REGNO (base) == STACK_POINTER_REGNUM
01343 || REGNO (base) == FRAME_POINTER_REGNUM
01344 || ((reload_completed || reload_in_progress)
01345 && frame_pointer_needed
01346 && REGNO (base) == HARD_FRAME_POINTER_REGNUM)
01347 || (flag_pic
01348 && REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
01349 pointer = TRUE;
01350 }
01351
01352
01353 if (indx)
01354 {
01355 if (GET_CODE (indx) == UNSPEC)
01356 {
01357 if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != 101)
01358 return FALSE;
01359 indx = XVECEXP (indx, 0, 0);
01360 pointer = TRUE;
01361 }
01362
01363 if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
01364 return FALSE;
01365
01366 if ((strict && ! REG_OK_FOR_BASE_STRICT_P (indx))
01367 || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (indx)))
01368 return FALSE;
01369
01370 if (REGNO (indx) == BASE_REGISTER
01371 || REGNO (indx) == STACK_POINTER_REGNUM
01372 || REGNO (indx) == FRAME_POINTER_REGNUM
01373 || ((reload_completed || reload_in_progress)
01374 && frame_pointer_needed
01375 && REGNO (indx) == HARD_FRAME_POINTER_REGNUM)
01376 || (flag_pic
01377 && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
01378 pointer = TRUE;
01379 }
01380
01381
01382 if (disp)
01383 {
01384
01385 if (GET_CODE (disp) == CONST_INT)
01386 {
01387 if (INTVAL (disp) < 0 || INTVAL (disp) >= 4096)
01388 return FALSE;
01389 }
01390
01391
01392
01393 else if (GET_CODE (disp) == CONST
01394 && GET_CODE (XEXP (disp, 0)) == UNSPEC
01395 && XINT (XEXP (disp, 0), 1) == 110)
01396 {
01397 if (flag_pic != 1)
01398 return FALSE;
01399
01400 pointer = TRUE;
01401 }
01402
01403
01404 else if (GET_CODE (disp) == CONST
01405 && GET_CODE (XEXP (disp, 0)) == MINUS
01406 && GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF
01407 && GET_CODE (XEXP (XEXP (disp, 0), 1)) == LABEL_REF)
01408 {
01409 pointer = TRUE;
01410 }
01411
01412
01413 else if (GET_CODE (disp) == CONST
01414 && GET_CODE (XEXP (disp, 0)) == PLUS
01415 && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT
01416 && GET_CODE (XEXP (XEXP (disp, 0), 0)) == MINUS
01417 && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 0)) == LABEL_REF
01418 && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 1)) == LABEL_REF)
01419 {
01420 pointer = TRUE;
01421 }
01422
01423
01424
01425 else
01426 {
01427
01428
01429
01430 unsigned int offset = 0;
01431
01432 if (GET_CODE (disp) == CONST
01433 && GET_CODE (XEXP (disp, 0)) == PLUS
01434 && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
01435 {
01436 offset = INTVAL (XEXP (XEXP (disp, 0), 1));
01437 disp = XEXP (XEXP (disp, 0), 0);
01438 }
01439
01440
01441 if (GET_CODE (disp) != SYMBOL_REF
01442 || !CONSTANT_POOL_ADDRESS_P (disp))
01443 return FALSE;
01444
01445
01446
01447 if (TARGET_64BIT && flag_pic
01448 && SYMBOLIC_CONST (get_pool_constant (disp)))
01449 return FALSE;
01450
01451
01452
01453 if (offset && offset >= GET_MODE_SIZE (get_pool_mode (disp)))
01454 return FALSE;
01455
01456
01457
01458 if (base && indx)
01459 return FALSE;
01460
01461
01462 if (base)
01463 indx = gen_rtx_REG (Pmode, BASE_REGISTER);
01464 else
01465 base = gen_rtx_REG (Pmode, BASE_REGISTER);
01466
01467 disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp), 100);
01468 disp = gen_rtx_CONST (Pmode, disp);
01469
01470 if (offset)
01471 disp = plus_constant (disp, offset);
01472
01473 pointer = TRUE;
01474 }
01475 }
01476
01477 if (!base && !indx)
01478 pointer = TRUE;
01479
01480 if (out)
01481 {
01482 out->base = base;
01483 out->indx = indx;
01484 out->disp = disp;
01485 out->pointer = pointer;
01486 }
01487
01488 return TRUE;
01489 }
01490
01491
01492
01493
01494 int
01495 legitimate_address_p (mode, addr, strict)
01496 enum machine_mode mode ATTRIBUTE_UNUSED;
01497 register rtx addr;
01498 int strict;
01499 {
01500 return s390_decompose_address (addr, NULL, strict);
01501 }
01502
01503
01504
01505
01506
01507 int
01508 legitimate_la_operand_p (op)
01509 register rtx op;
01510 {
01511 struct s390_address addr;
01512 if (!s390_decompose_address (op, &addr, FALSE))
01513 return FALSE;
01514
01515 if (TARGET_64BIT || addr.pointer)
01516 return TRUE;
01517
01518 return FALSE;
01519 }
01520
01521
01522
01523
01524 rtx
01525 legitimize_la_operand (op)
01526 register rtx op;
01527 {
01528 struct s390_address addr;
01529 if (!s390_decompose_address (op, &addr, FALSE))
01530 abort ();
01531
01532 if (TARGET_64BIT || addr.pointer)
01533 return op;
01534
01535 if (!addr.base)
01536 abort ();
01537
01538 op = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr.base), 101);
01539 if (addr.indx)
01540 op = gen_rtx_PLUS (Pmode, op, addr.indx);
01541 if (addr.disp)
01542 op = gen_rtx_PLUS (Pmode, op, addr.disp);
01543
01544 return op;
01545 }
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565 rtx
01566 legitimize_pic_address (orig, reg)
01567 rtx orig;
01568 rtx reg;
01569 {
01570 rtx addr = orig;
01571 rtx new = orig;
01572 rtx base;
01573
01574 if (GET_CODE (addr) == LABEL_REF
01575 || (GET_CODE (addr) == SYMBOL_REF
01576 && (SYMBOL_REF_FLAG (addr)
01577 || CONSTANT_POOL_ADDRESS_P (addr))))
01578 {
01579
01580 if (TARGET_64BIT)
01581 {
01582
01583
01584
01585 }
01586 else
01587 {
01588
01589
01590 rtx temp = reg? reg : gen_reg_rtx (Pmode);
01591
01592 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 100);
01593 addr = gen_rtx_CONST (SImode, addr);
01594 addr = force_const_mem (SImode, addr);
01595 emit_move_insn (temp, addr);
01596
01597 base = gen_rtx_REG (Pmode, BASE_REGISTER);
01598 base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101);
01599 new = gen_rtx_PLUS (Pmode, base, temp);
01600
01601 if (reg != 0)
01602 {
01603 emit_move_insn (reg, new);
01604 new = reg;
01605 }
01606 }
01607 }
01608 else if (GET_CODE (addr) == SYMBOL_REF)
01609 {
01610 if (reg == 0)
01611 reg = gen_reg_rtx (Pmode);
01612
01613 if (flag_pic == 1)
01614 {
01615
01616
01617
01618 current_function_uses_pic_offset_table = 1;
01619
01620 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 110);
01621 new = gen_rtx_CONST (Pmode, new);
01622 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
01623 new = gen_rtx_MEM (Pmode, new);
01624 RTX_UNCHANGING_P (new) = 1;
01625 emit_move_insn (reg, new);
01626 new = reg;
01627 }
01628 else if (TARGET_64BIT)
01629 {
01630
01631
01632
01633 rtx temp = gen_reg_rtx (Pmode);
01634
01635 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 111);
01636 new = gen_rtx_CONST (Pmode, new);
01637 emit_move_insn (temp, new);
01638
01639 new = gen_rtx_MEM (Pmode, temp);
01640 RTX_UNCHANGING_P (new) = 1;
01641 emit_move_insn (reg, new);
01642 new = reg;
01643 }
01644 else
01645 {
01646
01647
01648
01649 rtx temp = gen_reg_rtx (Pmode);
01650
01651 current_function_uses_pic_offset_table = 1;
01652
01653 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 112);
01654 addr = gen_rtx_CONST (SImode, addr);
01655 addr = force_const_mem (SImode, addr);
01656 emit_move_insn (temp, addr);
01657
01658 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
01659 new = gen_rtx_MEM (Pmode, new);
01660 RTX_UNCHANGING_P (new) = 1;
01661 emit_move_insn (reg, new);
01662 new = reg;
01663 }
01664 }
01665 else
01666 {
01667 if (GET_CODE (addr) == CONST)
01668 {
01669 addr = XEXP (addr, 0);
01670 if (GET_CODE (addr) == UNSPEC)
01671 {
01672 if (XVECLEN (addr, 0) != 1)
01673 abort ();
01674 switch (XINT (addr, 1))
01675 {
01676
01677
01678 case 100:
01679 case 112:
01680 case 114:
01681 new = force_const_mem (SImode, orig);
01682 break;
01683
01684
01685 case 111:
01686 break;
01687
01688
01689
01690 case 113:
01691 if (!TARGET_64BIT)
01692 {
01693 rtx temp = reg? reg : gen_reg_rtx (Pmode);
01694
01695 addr = XVECEXP (addr, 0, 0);
01696 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 114);
01697 addr = gen_rtx_CONST (SImode, addr);
01698 addr = force_const_mem (SImode, addr);
01699 emit_move_insn (temp, addr);
01700
01701 base = gen_rtx_REG (Pmode, BASE_REGISTER);
01702 base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101);
01703 new = gen_rtx_PLUS (Pmode, base, temp);
01704
01705 if (reg != 0)
01706 {
01707 emit_move_insn (reg, new);
01708 new = reg;
01709 }
01710 }
01711 break;
01712
01713
01714 default:
01715 abort ();
01716 }
01717 }
01718 else if (GET_CODE (addr) != PLUS)
01719 abort ();
01720 }
01721 if (GET_CODE (addr) == PLUS)
01722 {
01723 rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
01724
01725
01726 if ((GET_CODE (op0) == LABEL_REF
01727 || (GET_CODE (op0) == SYMBOL_REF
01728 && (SYMBOL_REF_FLAG (op0)
01729 || CONSTANT_POOL_ADDRESS_P (op0))))
01730 && GET_CODE (op1) == CONST_INT)
01731 {
01732 if (TARGET_64BIT)
01733 {
01734 if (INTVAL (op1) & 1)
01735 {
01736
01737
01738 rtx temp = reg? reg : gen_reg_rtx (Pmode);
01739
01740 if (INTVAL (op1) < 0 || INTVAL (op1) >= 4096)
01741 {
01742 int even = INTVAL (op1) - 1;
01743 op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even));
01744 op0 = gen_rtx_CONST (Pmode, op0);
01745 op1 = GEN_INT (1);
01746 }
01747
01748 emit_move_insn (temp, op0);
01749 new = gen_rtx_PLUS (Pmode, temp, op1);
01750
01751 if (reg != 0)
01752 {
01753 emit_move_insn (reg, new);
01754 new = reg;
01755 }
01756 }
01757 else
01758 {
01759
01760
01761 }
01762 }
01763 else
01764 {
01765
01766
01767 rtx temp = reg? reg : gen_reg_rtx (Pmode);
01768
01769 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, op0), 100);
01770 addr = gen_rtx_PLUS (SImode, addr, op1);
01771 addr = gen_rtx_CONST (SImode, addr);
01772 addr = force_const_mem (SImode, addr);
01773 emit_move_insn (temp, addr);
01774
01775 base = gen_rtx_REG (Pmode, BASE_REGISTER);
01776 base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101);
01777 new = gen_rtx_PLUS (Pmode, base, temp);
01778
01779 if (reg != 0)
01780 {
01781 emit_move_insn (reg, new);
01782 new = reg;
01783 }
01784 }
01785 }
01786
01787
01788
01789
01790 else if (GET_CODE (op0) == UNSPEC
01791 && GET_CODE (op1) == CONST_INT)
01792 {
01793 if (XVECLEN (op0, 0) != 1)
01794 abort ();
01795 if (XINT (op0, 1) != 100)
01796 abort ();
01797
01798 new = force_const_mem (SImode, orig);
01799 }
01800
01801
01802 else
01803 {
01804 base = legitimize_pic_address (XEXP (addr, 0), reg);
01805 new = legitimize_pic_address (XEXP (addr, 1),
01806 base == reg ? NULL_RTX : reg);
01807 if (GET_CODE (new) == CONST_INT)
01808 new = plus_constant (base, INTVAL (new));
01809 else
01810 {
01811 if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1)))
01812 {
01813 base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0));
01814 new = XEXP (new, 1);
01815 }
01816 new = gen_rtx_PLUS (Pmode, base, new);
01817 }
01818
01819 if (GET_CODE (new) == CONST)
01820 new = XEXP (new, 0);
01821 new = force_operand (new, 0);
01822 }
01823 }
01824 }
01825 return new;
01826 }
01827
01828
01829
01830 void
01831 emit_pic_move (operands, mode)
01832 rtx *operands;
01833 enum machine_mode mode ATTRIBUTE_UNUSED;
01834 {
01835 rtx temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
01836
01837 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
01838 operands[1] = force_reg (Pmode, operands[1]);
01839 else
01840 operands[1] = legitimize_pic_address (operands[1], temp);
01841 }
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854 rtx
01855 legitimize_address (x, oldx, mode)
01856 register rtx x;
01857 register rtx oldx ATTRIBUTE_UNUSED;
01858 enum machine_mode mode ATTRIBUTE_UNUSED;
01859 {
01860 rtx constant_term = const0_rtx;
01861
01862 if (flag_pic)
01863 {
01864 if (SYMBOLIC_CONST (x)
01865 || (GET_CODE (x) == PLUS
01866 && (SYMBOLIC_CONST (XEXP (x, 0))
01867 || SYMBOLIC_CONST (XEXP (x, 1)))))
01868 x = legitimize_pic_address (x, 0);
01869
01870 if (legitimate_address_p (mode, x, FALSE))
01871 return x;
01872 }
01873
01874 x = eliminate_constant_term (x, &constant_term);
01875
01876 if (GET_CODE (x) == PLUS)
01877 {
01878 if (GET_CODE (XEXP (x, 0)) == REG)
01879 {
01880 register rtx temp = gen_reg_rtx (Pmode);
01881 register rtx val = force_operand (XEXP (x, 1), temp);
01882 if (val != temp)
01883 emit_move_insn (temp, val);
01884
01885 x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp);
01886 }
01887
01888 else if (GET_CODE (XEXP (x, 1)) == REG)
01889 {
01890 register rtx temp = gen_reg_rtx (Pmode);
01891 register rtx val = force_operand (XEXP (x, 0), temp);
01892 if (val != temp)
01893 emit_move_insn (temp, val);
01894
01895 x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1));
01896 }
01897 }
01898
01899 if (constant_term != const0_rtx)
01900 x = gen_rtx_PLUS (Pmode, x, constant_term);
01901
01902 return x;
01903 }
01904
01905
01906
01907
01908
01909 rtx
01910 s390_simplify_dwarf_addr (orig_x)
01911 rtx orig_x;
01912 {
01913 rtx x = orig_x, y;
01914
01915 if (GET_CODE (x) != MEM)
01916 return orig_x;
01917
01918 x = XEXP (x, 0);
01919 if (GET_CODE (x) == PLUS
01920 && GET_CODE (XEXP (x, 1)) == CONST
01921 && GET_CODE (XEXP (x, 0)) == REG
01922 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
01923 {
01924 y = XEXP (XEXP (x, 1), 0);
01925 if (GET_CODE (y) == UNSPEC
01926 && XINT (y, 1) == 110)
01927 return XVECEXP (y, 0, 0);
01928 return orig_x;
01929 }
01930
01931 if (GET_CODE (x) == CONST)
01932 {
01933 y = XEXP (x, 0);
01934 if (GET_CODE (y) == UNSPEC
01935 && XINT (y, 1) == 111)
01936 return XVECEXP (y, 0, 0);
01937 return orig_x;
01938 }
01939
01940 return orig_x;
01941 }
01942
01943
01944
01945
01946 void
01947 s390_output_symbolic_const (file, x)
01948 FILE *file;
01949 rtx x;
01950 {
01951 switch (GET_CODE (x))
01952 {
01953 case CONST:
01954 case ZERO_EXTEND:
01955 case SIGN_EXTEND:
01956 s390_output_symbolic_const (file, XEXP (x, 0));
01957 break;
01958
01959 case PLUS:
01960 s390_output_symbolic_const (file, XEXP (x, 0));
01961 fprintf (file, "+");
01962 s390_output_symbolic_const (file, XEXP (x, 1));
01963 break;
01964
01965 case MINUS:
01966 s390_output_symbolic_const (file, XEXP (x, 0));
01967 fprintf (file, "-");
01968 s390_output_symbolic_const (file, XEXP (x, 1));
01969 break;
01970
01971 case CONST_INT:
01972 case LABEL_REF:
01973 case CODE_LABEL:
01974 case SYMBOL_REF:
01975 output_addr_const (file, x);
01976 break;
01977
01978 case UNSPEC:
01979 if (XVECLEN (x, 0) != 1)
01980 output_operand_lossage ("invalid UNSPEC as operand (1)");
01981 switch (XINT (x, 1))
01982 {
01983 case 100:
01984 s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
01985 fprintf (file, "-.LT%X", s390_function_count);
01986 break;
01987 case 110:
01988 s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
01989 fprintf (file, "@GOT12");
01990 break;
01991 case 111:
01992 s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
01993 fprintf (file, "@GOTENT");
01994 break;
01995 case 112:
01996 s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
01997 fprintf (file, "@GOT");
01998 break;
01999 case 113:
02000 s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
02001 fprintf (file, "@PLT");
02002 break;
02003 case 114:
02004 s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
02005 fprintf (file, "@PLT-.LT%X", s390_function_count);
02006 break;
02007 default:
02008 output_operand_lossage ("invalid UNSPEC as operand (2)");
02009 break;
02010 }
02011 break;
02012
02013 default:
02014 fatal_insn ("UNKNOWN in s390_output_symbolic_const !?", x);
02015 break;
02016 }
02017 }
02018
02019
02020
02021
02022 void
02023 print_operand_address (file, addr)
02024 FILE *file;
02025 rtx addr;
02026 {
02027 struct s390_address ad;
02028
02029 if (!s390_decompose_address (addr, &ad, TRUE))
02030 output_operand_lossage ("Cannot decompose address.");
02031
02032 if (ad.disp)
02033 s390_output_symbolic_const (file, ad.disp);
02034 else
02035 fprintf (file, "0");
02036
02037 if (ad.base && ad.indx)
02038 fprintf (file, "(%s,%s)", reg_names[REGNO (ad.indx)],
02039 reg_names[REGNO (ad.base)]);
02040 else if (ad.base)
02041 fprintf (file, "(%s)", reg_names[REGNO (ad.base)]);
02042 }
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058
02059 void
02060 print_operand (file, x, code)
02061 FILE *file;
02062 rtx x;
02063 int code;
02064 {
02065 switch (code)
02066 {
02067 case 'C':
02068 fprintf (file, s390_branch_condition_mnemonic (x, FALSE));
02069 return;
02070
02071 case 'D':
02072 fprintf (file, s390_branch_condition_mnemonic (x, TRUE));
02073 return;
02074
02075 case 'O':
02076 {
02077 struct s390_address ad;
02078
02079 if (GET_CODE (x) != MEM
02080 || !s390_decompose_address (XEXP (x, 0), &ad, TRUE)
02081 || ad.indx)
02082 abort ();
02083
02084 if (ad.disp)
02085 s390_output_symbolic_const (file, ad.disp);
02086 else
02087 fprintf (file, "0");
02088 }
02089 return;
02090
02091 case 'R':
02092 {
02093 struct s390_address ad;
02094
02095 if (GET_CODE (x) != MEM
02096 || !s390_decompose_address (XEXP (x, 0), &ad, TRUE)
02097 || ad.indx)
02098 abort ();
02099
02100 if (ad.base)
02101 fprintf (file, "%s", reg_names[REGNO (ad.base)]);
02102 else
02103 fprintf (file, "0");
02104 }
02105 return;
02106
02107 case 'N':
02108 if (GET_CODE (x) == REG)
02109 x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1);
02110 else if (GET_CODE (x) == MEM)
02111 x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 4));
02112 else
02113 abort ();
02114 break;
02115
02116 case 'M':
02117 if (GET_CODE (x) == REG)
02118 x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1);
02119 else if (GET_CODE (x) == MEM)
02120 x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 8));
02121 else
02122 abort ();
02123 break;
02124 }
02125
02126 switch (GET_CODE (x))
02127 {
02128 case REG:
02129 fprintf (file, "%s", reg_names[REGNO (x)]);
02130 break;
02131
02132 case MEM:
02133 output_address (XEXP (x, 0));
02134 break;
02135
02136 case CONST:
02137 case CODE_LABEL:
02138 case LABEL_REF:
02139 case SYMBOL_REF:
02140 s390_output_symbolic_const (file, x);
02141 break;
02142
02143 case CONST_INT:
02144 if (code == 'b')
02145 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff);
02146 else if (code == 'x')
02147 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff);
02148 else if (code == 'h')
02149 fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000);
02150 else
02151 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
02152 break;
02153
02154 case CONST_DOUBLE:
02155 if (GET_MODE (x) != VOIDmode)
02156 abort ();
02157 if (code == 'b')
02158 fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xff);
02159 else if (code == 'x')
02160 fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xffff);
02161 else if (code == 'h')
02162 fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000);
02163 else
02164 abort ();
02165 break;
02166
02167 default:
02168 fatal_insn ("UNKNOWN in print_operand !?", x);
02169 break;
02170 }
02171 }
02172
02173
02174
02175
02176
02177 static bool
02178 s390_assemble_integer (x, size, aligned_p)
02179 rtx x;
02180 unsigned int size;
02181 int aligned_p;
02182 {
02183 if (size == 8 && aligned_p
02184 && GET_CODE (x) == CONST_INT && INTVAL (x) < INT_MIN)
02185 {
02186 fputs ("\t.quad\t", asm_out_file);
02187 fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
02188 putc ('\n', asm_out_file);
02189 return true;
02190 }
02191 return default_assemble_integer (x, size, aligned_p);
02192 }
02193
02194
02195 #define DEBUG_SCHED 0
02196
02197
02198
02199
02200 static int
02201 reg_used_in_mem_p (regno, x)
02202 int regno;
02203 rtx x;
02204 {
02205 enum rtx_code code = GET_CODE (x);
02206 int i, j;
02207 const char *fmt;
02208
02209 if (code == MEM)
02210 {
02211 if (refers_to_regno_p (regno, regno+1,
02212 XEXP (x, 0), 0))
02213 return 1;
02214 }
02215 else if (code == SET
02216 && GET_CODE (SET_DEST (x)) == PC)
02217 {
02218 if (refers_to_regno_p (regno, regno+1,
02219 SET_SRC (x), 0))
02220 return 1;
02221 }
02222
02223 fmt = GET_RTX_FORMAT (code);
02224 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
02225 {
02226 if (fmt[i] == 'e'
02227 && reg_used_in_mem_p (regno, XEXP (x, i)))
02228 return 1;
02229
02230 else if (fmt[i] == 'E')
02231 for (j = 0; j < XVECLEN (x, i); j++)
02232 if (reg_used_in_mem_p (regno, XVECEXP (x, i, j)))
02233 return 1;
02234 }
02235 return 0;
02236 }
02237
02238
02239
02240
02241 static int
02242 addr_generation_dependency_p (dep_rtx, insn)
02243 rtx dep_rtx;
02244 rtx insn;
02245 {
02246 rtx target, pat;
02247
02248 if (GET_CODE (dep_rtx) == SET)
02249 {
02250 target = SET_DEST (dep_rtx);
02251
02252 if (GET_CODE (target) == REG)
02253 {
02254 int regno = REGNO (target);
02255
02256 if (get_attr_type (insn) == TYPE_LA)
02257 {
02258 pat = PATTERN (insn);
02259 if (GET_CODE (pat) == PARALLEL)
02260 {
02261 if (XVECLEN (pat, 0) != 2)
02262 abort();
02263 pat = XVECEXP (pat, 0, 0);
02264 }
02265 if (GET_CODE (pat) == SET)
02266 return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0);
02267 else
02268 abort();
02269 }
02270 else if (get_attr_atype (insn) == ATYPE_MEM)
02271 return reg_used_in_mem_p (regno, PATTERN (insn));
02272 }
02273 }
02274 return 0;
02275 }
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285
02286
02287
02288
02289 static int
02290 s390_adjust_cost (insn, link, dep_insn, cost)
02291 rtx insn;
02292 rtx link;
02293 rtx dep_insn;
02294 int cost;
02295 {
02296 rtx dep_rtx;
02297 int i;
02298
02299
02300
02301
02302
02303 if (REG_NOTE_KIND (link) != 0)
02304 return 0;
02305
02306
02307 if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
02308 return cost;
02309
02310 dep_rtx = PATTERN (dep_insn);
02311
02312 if (GET_CODE (dep_rtx) == SET)
02313 {
02314 if (addr_generation_dependency_p (dep_rtx, insn))
02315 {
02316 cost += (get_attr_type (dep_insn) == TYPE_LA) ? 1 : 4;
02317 if (DEBUG_SCHED)
02318 {
02319 fprintf (stderr, "\n\nAddress dependency detected: cost %d\n",
02320 cost);
02321 debug_rtx (dep_insn);
02322 debug_rtx (insn);
02323 }
02324 }
02325 }
02326 else if (GET_CODE (dep_rtx) == PARALLEL)
02327 {
02328 for (i = 0; i < XVECLEN (dep_rtx, 0); i++)
02329 {
02330 if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i),
02331 insn))
02332 {
02333 cost += (get_attr_type (dep_insn) == TYPE_LA) ? 1 : 4;
02334 if (DEBUG_SCHED)
02335 {
02336 fprintf (stderr, "\n\nAddress dependency detected: cost %d\n"
02337 ,cost);
02338 debug_rtx (dep_insn);
02339 debug_rtx (insn);
02340 }
02341 }
02342 }
02343 }
02344
02345 return cost;
02346 }
02347
02348
02349
02350
02351
02352
02353
02354
02355
02356
02357 static int
02358 s390_adjust_priority (insn, priority)
02359 rtx insn ATTRIBUTE_UNUSED;
02360 int priority;
02361 {
02362 if (! INSN_P (insn))
02363 return priority;
02364
02365 if (GET_CODE (PATTERN (insn)) == USE
02366 || GET_CODE (PATTERN (insn)) == CLOBBER)
02367 return priority;
02368
02369 switch (get_attr_type (insn))
02370 {
02371 default:
02372 break;
02373
02374 case TYPE_LA:
02375 if (priority >= 0 && priority < 0x01000000)
02376 priority <<= 3;
02377 break;
02378 case TYPE_LM:
02379
02380
02381
02382
02383
02384 priority = 0x7fffffff;
02385 break;
02386 }
02387
02388 return priority;
02389 }
02390
02391
02392
02393
02394 static void
02395 s390_split_branches (void)
02396 {
02397 rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
02398 rtx insn, pat, label, target, jump, tmp;
02399
02400
02401
02402 if (TARGET_64BIT)
02403 return;
02404
02405
02406
02407 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
02408 {
02409 if (GET_CODE (insn) != JUMP_INSN)
02410 continue;
02411
02412 pat = PATTERN (insn);
02413 if (GET_CODE (pat) != SET)
02414 continue;
02415
02416 if (GET_CODE (SET_SRC (pat)) == LABEL_REF)
02417 {
02418 label = SET_SRC (pat);
02419 }
02420 else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
02421 {
02422 if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
02423 label = XEXP (SET_SRC (pat), 1);
02424 else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF)
02425 label = XEXP (SET_SRC (pat), 2);
02426 else
02427 continue;
02428 }
02429 else
02430 continue;
02431
02432 if (get_attr_length (insn) == 4)
02433 continue;
02434
02435 if (flag_pic)
02436 {
02437 target = gen_rtx_UNSPEC (SImode, gen_rtvec (1, label), 100);
02438 target = gen_rtx_CONST (SImode, target);
02439 target = force_const_mem (SImode, target);
02440 jump = gen_rtx_REG (Pmode, BASE_REGISTER);
02441 jump = gen_rtx_PLUS (Pmode, jump, temp_reg);
02442 }
02443 else
02444 {
02445 target = force_const_mem (Pmode, label);
02446 jump = temp_reg;
02447 }
02448
02449 if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
02450 {
02451 if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
02452 jump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (SET_SRC (pat), 0),
02453 jump, pc_rtx);
02454 else
02455 jump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (SET_SRC (pat), 0),
02456 pc_rtx, jump);
02457 }
02458
02459 tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn);
02460 INSN_ADDRESSES_NEW (tmp, -1);
02461
02462 tmp = emit_jump_insn_before (gen_rtx_SET (VOIDmode, pc_rtx, jump), insn);
02463 INSN_ADDRESSES_NEW (tmp, -1);
02464
02465 remove_insn (insn);
02466 insn = tmp;
02467 }
02468 }
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479 static void
02480 find_constant_pool_ref (x, ref)
02481 rtx x;
02482 rtx *ref;
02483 {
02484 int i, j;
02485 const char *fmt;
02486
02487 if (GET_CODE (x) == SYMBOL_REF
02488 && CONSTANT_POOL_ADDRESS_P (x))
02489 {
02490 if (*ref == NULL_RTX)
02491 *ref = x;
02492 else if (*ref != x)
02493 abort();
02494 }
02495
02496 fmt = GET_RTX_FORMAT (GET_CODE (x));
02497 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
02498 {
02499 if (fmt[i] == 'e')
02500 {
02501 find_constant_pool_ref (XEXP (x, i), ref);
02502 }
02503 else if (fmt[i] == 'E')
02504 {
02505 for (j = 0; j < XVECLEN (x, i); j++)
02506 find_constant_pool_ref (XVECEXP (x, i, j), ref);
02507 }
02508 }
02509 }
02510
02511
02512
02513
02514 static void
02515 replace_constant_pool_ref (x, ref, addr)
02516 rtx *x;
02517 rtx ref;
02518 rtx addr;
02519 {
02520 int i, j;
02521 const char *fmt;
02522
02523 if (*x == ref)
02524 abort ();
02525
02526
02527 if (GET_CODE (*x) == MEM)
02528 {
02529 rtx memref = XEXP (*x, 0);
02530
02531 if (memref == ref)
02532 {
02533 *x = replace_equiv_address (*x, addr);
02534 return;
02535 }
02536
02537 if (GET_CODE (memref) == CONST
02538 && GET_CODE (XEXP (memref, 0)) == PLUS
02539 && GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT
02540 && XEXP (XEXP (memref, 0), 0) == ref)
02541 {
02542 HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
02543 *x = replace_equiv_address (*x, plus_constant (addr, off));
02544 return;
02545 }
02546 }
02547
02548
02549 if (GET_CODE (*x) == SET)
02550 {
02551 rtx addrref = SET_SRC (*x);
02552
02553 if (addrref == ref)
02554 {
02555 SET_SRC (*x) = addr;
02556 return;
02557 }
02558
02559 if (GET_CODE (addrref) == CONST
02560 && GET_CODE (XEXP (addrref, 0)) == PLUS
02561 && GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT
02562 && XEXP (XEXP (addrref, 0), 0) == ref)
02563 {
02564 HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
02565 SET_SRC (*x) = plus_constant (addr, off);
02566 return;
02567 }
02568 }
02569
02570 fmt = GET_RTX_FORMAT (GET_CODE (*x));
02571 for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
02572 {
02573 if (fmt[i] == 'e')
02574 {
02575 replace_constant_pool_ref (&XEXP (*x, i), ref, addr);
02576 }
02577 else if (fmt[i] == 'E')
02578 {
02579 for (j = 0; j < XVECLEN (*x, i); j++)
02580 replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, addr);
02581 }
02582 }
02583 }
02584
02585
02586
02587
02588 #define NR_C_MODES 6
02589 enum machine_mode constant_modes[NR_C_MODES] =
02590 {
02591 DFmode, DImode,
02592 SFmode, SImode,
02593 HImode,
02594 QImode
02595 };
02596
02597 rtx (*gen_consttable[NR_C_MODES])(rtx) =
02598 {
02599 gen_consttable_df, gen_consttable_di,
02600 gen_consttable_sf, gen_consttable_si,
02601 gen_consttable_hi,
02602 gen_consttable_qi
02603 };
02604
02605 struct constant
02606 {
02607 struct constant *next;
02608 rtx value;
02609 rtx label;
02610 };
02611
02612 struct constant_pool
02613 {
02614 struct constant_pool *next;
02615 rtx first_insn;
02616 rtx last_insn;
02617
02618 struct constant *constants[NR_C_MODES];
02619 rtx label;
02620 int size;
02621 };
02622
02623 static struct constant_pool *s390_start_pool PARAMS ((struct constant_pool **, rtx));
02624 static void s390_end_pool PARAMS ((struct constant_pool *, rtx));
02625 static struct constant_pool *s390_find_pool PARAMS ((struct constant_pool *, rtx));
02626 static rtx s390_add_pool PARAMS ((struct constant_pool *, rtx, enum machine_mode));
02627 static rtx s390_dump_pool PARAMS ((struct constant_pool *));
02628 static void s390_free_pool PARAMS ((struct constant_pool *));
02629
02630
02631
02632
02633 static struct constant_pool *
02634 s390_start_pool (pool_list, insn)
02635 struct constant_pool **pool_list;
02636 rtx insn;
02637 {
02638 struct constant_pool *pool, **prev;
02639 int i;
02640
02641 pool = (struct constant_pool *) xmalloc (sizeof *pool);
02642 pool->next = NULL;
02643 for (i = 0; i < NR_C_MODES; i++)
02644 pool->constants[i] = NULL;
02645
02646 pool->label = gen_label_rtx ();
02647 pool->first_insn = insn;
02648 pool->last_insn = NULL_RTX;
02649 pool->size = 0;
02650
02651 for (prev = pool_list; *prev; prev = &(*prev)->next)
02652 ;
02653 *prev = pool;
02654
02655 return pool;
02656 }
02657
02658
02659
02660 static void
02661 s390_end_pool (pool, insn)
02662 struct constant_pool *pool;
02663 rtx insn;
02664 {
02665 pool->last_insn = insn;
02666 }
02667
02668
02669
02670 static struct constant_pool *
02671 s390_find_pool (pool_list, insn)
02672 struct constant_pool *pool_list;
02673 rtx insn;
02674 {
02675 int addr = INSN_ADDRESSES (INSN_UID (insn));
02676 struct constant_pool *pool;
02677
02678 if (addr == -1)
02679 return NULL;
02680
02681 for (pool = pool_list; pool; pool = pool->next)
02682 if (INSN_ADDRESSES (INSN_UID (pool->first_insn)) <= addr
02683 && (pool->last_insn == NULL_RTX
02684 || INSN_ADDRESSES (INSN_UID (pool->last_insn)) > addr))
02685 break;
02686
02687 return pool;
02688 }
02689
02690
02691
02692
02693
02694 static rtx
02695 s390_add_pool (pool, val, mode)
02696 struct constant_pool *pool;
02697 rtx val;
02698 enum machine_mode mode;
02699 {
02700 struct constant *c;
02701 rtx offset;
02702 int i;
02703
02704 for (i = 0; i < NR_C_MODES; i++)
02705 if (constant_modes[i] == mode)
02706 break;
02707 if (i == NR_C_MODES)
02708 abort ();
02709
02710 for (c = pool->constants[i]; c != NULL; c = c->next)
02711 if (rtx_equal_p (val, c->value))
02712 break;
02713
02714 if (c == NULL)
02715 {
02716 c = (struct constant *) xmalloc (sizeof *c);
02717 c->value = val;
02718 c->label = gen_label_rtx ();
02719 c->next = pool->constants[i];
02720 pool->constants[i] = c;
02721 pool->size += GET_MODE_SIZE (mode);
02722 }
02723
02724 offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
02725 gen_rtx_LABEL_REF (Pmode, pool->label));
02726 offset = gen_rtx_CONST (Pmode, offset);
02727 return offset;
02728 }
02729
02730
02731
02732 static rtx
02733 s390_dump_pool (pool)
02734 struct constant_pool *pool;
02735 {
02736 struct constant *c;
02737 rtx insn;
02738 int i;
02739
02740
02741 if (TARGET_64BIT)
02742 insn = get_last_insn ();
02743 else
02744 insn = pool->last_insn? pool->last_insn : get_last_insn ();
02745
02746
02747
02748 if (TARGET_64BIT)
02749 insn = emit_insn_after (gen_pool_start_64 (), insn);
02750 else
02751 insn = emit_insn_after (gen_pool_start_31 (), insn);
02752 INSN_ADDRESSES_NEW (insn, -1);
02753
02754 insn = emit_label_after (pool->label, insn);
02755 INSN_ADDRESSES_NEW (insn, -1);
02756
02757
02758
02759 for (i = 0; i < NR_C_MODES; i++)
02760 for (c = pool->constants[i]; c; c = c->next)
02761 {
02762 insn = emit_label_after (c->label, insn);
02763 INSN_ADDRESSES_NEW (insn, -1);
02764 insn = emit_insn_after (gen_consttable[i] (c->value), insn);
02765 INSN_ADDRESSES_NEW (insn, -1);
02766 }
02767
02768
02769
02770 if (TARGET_64BIT)
02771 insn = emit_insn_after (gen_pool_end_64 (), insn);
02772 else
02773 insn = emit_insn_after (gen_pool_end_31 (), insn);
02774 INSN_ADDRESSES_NEW (insn, -1);
02775
02776 insn = emit_barrier_after (insn);
02777 INSN_ADDRESSES_NEW (insn, -1);
02778
02779 return insn;
02780 }
02781
02782
02783
02784 static void
02785 s390_free_pool (pool)
02786 struct constant_pool *pool;
02787 {
02788 int i;
02789
02790 for (i = 0; i < NR_C_MODES; i++)
02791 {
02792 struct constant *c = pool->constants[i];
02793 while (c != NULL)
02794 {
02795 struct constant *next = c->next;
02796 free (c);
02797 c = next;
02798 }
02799 }
02800
02801 free (pool);
02802 }
02803
02804
02805 int s390_pool_overflow = 0;
02806
02807
02808
02809 #define S390_POOL_CHUNK_MIN 0xc00
02810 #define S390_POOL_CHUNK_MAX 0xe00
02811
02812 static void
02813 s390_chunkify_pool (void)
02814 {
02815 rtx base_reg = gen_rtx_REG (Pmode,
02816 TARGET_64BIT? BASE_REGISTER : RETURN_REGNUM);
02817
02818 struct constant_pool *curr_pool = NULL, *pool_list = NULL;
02819 int extra_size = 0;
02820 bitmap far_labels;
02821 rtx insn;
02822
02823
02824
02825 if (get_pool_size () < S390_POOL_CHUNK_MAX)
02826 return;
02827
02828
02829
02830
02831
02832 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
02833 {
02834 if (GET_CODE (insn) == INSN)
02835 {
02836 rtx addr, pool_ref = NULL_RTX;
02837 find_constant_pool_ref (PATTERN (insn), &pool_ref);
02838 if (pool_ref)
02839 {
02840 if (!curr_pool)
02841 curr_pool = s390_start_pool (&pool_list, insn);
02842
02843 addr = s390_add_pool (curr_pool, get_pool_constant (pool_ref),
02844 get_pool_mode (pool_ref));
02845
02846 addr = gen_rtx_PLUS (Pmode, base_reg, addr);
02847 replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
02848 INSN_CODE (insn) = -1;
02849 }
02850 }
02851
02852 if (!curr_pool
02853 || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
02854 || INSN_ADDRESSES (INSN_UID (insn)) == -1)
02855 continue;
02856
02857 if (TARGET_64BIT)
02858 {
02859 if (curr_pool->size < S390_POOL_CHUNK_MAX)
02860 continue;
02861
02862 s390_end_pool (curr_pool, insn);
02863 curr_pool = NULL;
02864 }
02865 else
02866 {
02867 int chunk_size = INSN_ADDRESSES (INSN_UID (insn))
02868 - INSN_ADDRESSES (INSN_UID (curr_pool->first_insn))
02869 + extra_size;
02870
02871
02872
02873
02874
02875 if (GET_CODE (insn) == CODE_LABEL
02876 || GET_CODE (insn) == JUMP_INSN)
02877 extra_size += 6;
02878 else if (GET_CODE (insn) == CALL_INSN)
02879 extra_size += 4;
02880
02881 if (chunk_size < S390_POOL_CHUNK_MIN
02882 && curr_pool->size < S390_POOL_CHUNK_MIN)
02883 continue;
02884
02885
02886 if (GET_CODE (insn) == BARRIER)
02887 {
02888 s390_end_pool (curr_pool, insn);
02889 curr_pool = NULL;
02890 extra_size = 0;
02891 }
02892
02893
02894 else if ((chunk_size > S390_POOL_CHUNK_MAX
02895 || curr_pool->size > S390_POOL_CHUNK_MAX)
02896 && (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN))
02897 {
02898 int addr = INSN_ADDRESSES (INSN_UID (insn));
02899 rtx label, jump, barrier;
02900
02901 label = gen_label_rtx ();
02902 jump = emit_jump_insn_after (gen_jump (label), insn);
02903 barrier = emit_barrier_after (jump);
02904 insn = emit_label_after (label, barrier);
02905 JUMP_LABEL (jump) = label;
02906 LABEL_NUSES (label) = 1;
02907
02908 INSN_ADDRESSES_NEW (jump, addr+1);
02909 INSN_ADDRESSES_NEW (barrier, addr+1);
02910 INSN_ADDRESSES_NEW (insn, -1);
02911
02912 s390_end_pool (curr_pool, barrier);
02913 curr_pool = NULL;
02914 extra_size = 0;
02915 }
02916 }
02917 }
02918
02919
02920
02921 for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
02922 s390_dump_pool (curr_pool);
02923
02924
02925
02926
02927
02928 far_labels = BITMAP_XMALLOC ();
02929
02930 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
02931 {
02932
02933
02934
02935
02936
02937
02938
02939 if (GET_CODE (insn) == CODE_LABEL
02940 && (LABEL_PRESERVE_P (insn) || LABEL_NAME (insn)))
02941 {
02942 rtx vec_insn = next_real_insn (insn);
02943 rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
02944 PATTERN (vec_insn) : NULL_RTX;
02945 if (!vec_pat
02946 || !(GET_CODE (vec_pat) == ADDR_VEC
02947 || GET_CODE (vec_pat) == ADDR_DIFF_VEC))
02948 bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (insn));
02949 }
02950
02951
02952
02953 else if (GET_CODE (insn) == JUMP_INSN)
02954 {
02955 rtx pat = PATTERN (insn);
02956 if (GET_CODE (pat) == SET)
02957 {
02958 rtx label = 0;
02959
02960 if (GET_CODE (SET_SRC (pat)) == LABEL_REF)
02961 {
02962 label = XEXP (SET_SRC (pat), 0);
02963 }
02964 else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
02965 {
02966 if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
02967 label = XEXP (XEXP (SET_SRC (pat), 1), 0);
02968 else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF)
02969 label = XEXP (XEXP (SET_SRC (pat), 2), 0);
02970 }
02971
02972 if (label)
02973 {
02974 if (s390_find_pool (pool_list, label)
02975 != s390_find_pool (pool_list, insn))
02976 bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
02977 }
02978 }
02979 else if (GET_CODE (pat) == PARALLEL
02980 && XVECLEN (pat, 0) == 2
02981 && GET_CODE (XVECEXP (pat, 0, 0)) == SET
02982 && GET_CODE (XVECEXP (pat, 0, 1)) == USE
02983 && GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == LABEL_REF)
02984 {
02985
02986 rtx vec_label = XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0);
02987 rtx vec_insn = next_real_insn (vec_label);
02988 rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
02989 PATTERN (vec_insn) : NULL_RTX;
02990 if (vec_pat
02991 && (GET_CODE (vec_pat) == ADDR_VEC
02992 || GET_CODE (vec_pat) == ADDR_DIFF_VEC))
02993 {
02994 int i, diff_p = GET_CODE (vec_pat) == ADDR_DIFF_VEC;
02995
02996 for (i = 0; i < XVECLEN (vec_pat, diff_p); i++)
02997 {
02998 rtx label = XEXP (XVECEXP (vec_pat, diff_p, i), 0);
02999
03000 if (s390_find_pool (pool_list, label)
03001 != s390_find_pool (pool_list, insn))
03002 bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
03003 }
03004 }
03005 }
03006 }
03007 }
03008
03009
03010
03011 for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
03012 if (TARGET_64BIT)
03013 {
03014 rtx pool_ref = gen_rtx_LABEL_REF (Pmode, curr_pool->label);
03015 rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
03016 rtx insn = curr_pool->first_insn;
03017 INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
03018 }
03019 else
03020 {
03021 rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
03022 rtx insn = curr_pool->first_insn;
03023 INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
03024 }
03025
03026
03027
03028 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
03029 if (GET_CODE (insn) == CODE_LABEL
03030 && bitmap_bit_p (far_labels, CODE_LABEL_NUMBER (insn)))
03031 {
03032 struct constant_pool *pool = s390_find_pool (pool_list, insn);
03033 if (pool)
03034 {
03035 if (TARGET_64BIT)
03036 {
03037 rtx pool_ref = gen_rtx_LABEL_REF (Pmode, pool->label);
03038 rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
03039 INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
03040 }
03041 else
03042 {
03043 rtx new_insn = gen_reload_base (base_reg, pool->label);
03044 INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
03045 }
03046 }
03047 }
03048
03049
03050
03051 if (REGNO (base_reg) == RETURN_REGNUM)
03052 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
03053 if (GET_CODE (insn) == CALL_INSN)
03054 {
03055 struct constant_pool *pool = s390_find_pool (pool_list, insn);
03056 if (pool)
03057 {
03058 rtx new_insn = gen_reload_base2 (base_reg, pool->label);
03059 INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
03060 }
03061 }
03062
03063
03064
03065
03066 s390_pool_overflow = 1;
03067 init_insn_lengths ();
03068 shorten_branches (get_insns ());
03069 s390_pool_overflow = 0;
03070
03071
03072
03073 if (!TARGET_64BIT)
03074 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
03075 if (GET_CODE (insn) == JUMP_INSN
03076 && GET_CODE (PATTERN (insn)) == SET
03077 && get_attr_length (insn) >= 12)
03078 {
03079 struct constant_pool *pool = s390_find_pool (pool_list, insn);
03080 if (pool)
03081 {
03082 rtx new_insn = gen_reload_base (base_reg, pool->label);
03083 INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
03084 }
03085 }
03086
03087
03088
03089
03090 while (pool_list)
03091 {
03092 struct constant_pool *next = pool_list->next;
03093 s390_free_pool (pool_list);
03094 pool_list = next;
03095 }
03096
03097 BITMAP_XFREE (far_labels);
03098 }
03099
03100
03101
03102
03103 int s390_pool_count = -1;
03104
03105
03106 int s390_nr_constants;
03107
03108
03109
03110 void
03111 s390_output_constant_pool (file)
03112 FILE *file;
03113 {
03114
03115 if (s390_nr_constants)
03116 {
03117 if (TARGET_64BIT)
03118 {
03119 fprintf (file, "\tlarl\t%s,.LT%X\n", reg_names[BASE_REGISTER],
03120 s390_function_count);
03121 readonly_data_section ();
03122 ASM_OUTPUT_ALIGN (file, 3);
03123 }
03124 else
03125 {
03126 fprintf (file, "\tbras\t%s,.LTN%X\n", reg_names[BASE_REGISTER],
03127 s390_function_count);
03128 }
03129 fprintf (file, ".LT%X:\n", s390_function_count);
03130
03131 s390_pool_count = 0;
03132 output_constant_pool (current_function_name, current_function_decl);
03133 s390_pool_count = -1;
03134
03135 if (TARGET_64BIT)
03136 function_section (current_function_decl);
03137 else
03138 fprintf (file, ".LTN%X:\n", s390_function_count);
03139 }
03140 }
03141
03142
03143
03144
03145 static int
03146 save_fprs_p ()
03147 {
03148 int i;
03149 if (!TARGET_64BIT)
03150 return 0;
03151 for (i=24; i<=31; i++)
03152 {
03153 if (regs_ever_live[i] == 1)
03154 return 1;
03155 }
03156 return 0;
03157 }
03158
03159
03160
03161
03162
03163 static int
03164 find_unused_clobbered_reg ()
03165 {
03166 int i;
03167 for (i = 0; i < 6; i++)
03168 if (!regs_ever_live[i])
03169 return i;
03170 return 0;
03171 }
03172
03173
03174
03175 static void
03176 s390_frame_info (frame)
03177 struct s390_frame *frame;
03178 {
03179 int i, j;
03180 HOST_WIDE_INT fsize = get_frame_size ();
03181
03182 if (fsize > 0x7fff0000)
03183 fatal_error ("Total size of local variables exceeds architecture limit.");
03184
03185
03186 frame->save_fprs_p = save_fprs_p ();
03187
03188 frame->frame_size = fsize + frame->save_fprs_p * 64;
03189
03190
03191
03192 if (! current_function_is_leaf
03193 || frame->frame_size > 0
03194 || current_function_calls_alloca
03195 || current_function_stdarg
03196 || current_function_varargs)
03197 frame->frame_size += STARTING_FRAME_OFFSET;
03198
03199
03200
03201 if (frame->frame_size > 0)
03202 regs_ever_live[STACK_POINTER_REGNUM] = 1;
03203
03204
03205
03206
03207 if (!TARGET_64BIT && get_pool_size () >= S390_POOL_CHUNK_MAX / 2)
03208 regs_ever_live[RETURN_REGNUM] = 1;
03209
03210
03211
03212
03213 if (get_pool_size ()
03214 || !CONST_OK_FOR_LETTER_P (frame->frame_size, 'K')
03215 || (!TARGET_64BIT && current_function_uses_pic_offset_table))
03216 regs_ever_live[BASE_REGISTER] = 1;
03217
03218
03219
03220 if (current_function_uses_pic_offset_table)
03221 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
03222
03223
03224
03225 frame->frame_pointer_p = frame_pointer_needed;
03226
03227
03228
03229 for (i = 6; i < 16; i++)
03230 if (regs_ever_live[i])
03231 break;
03232
03233 for (j = 15; j > i; j--)
03234 if (regs_ever_live[j])
03235 break;
03236
03237 if (i == 16)
03238 {
03239
03240 frame->first_save_gpr = -1;
03241 frame->first_restore_gpr = -1;
03242 frame->last_save_gpr = -1;
03243 frame->return_reg_saved_p = 0;
03244 }
03245 else
03246 {
03247
03248 frame->first_save_gpr = i;
03249 frame->first_restore_gpr = i;
03250 frame->last_save_gpr = j;
03251 frame->return_reg_saved_p = (j >= RETURN_REGNUM && i <= RETURN_REGNUM);
03252 }
03253
03254 if (current_function_stdarg || current_function_varargs)
03255 {
03256
03257 frame->first_save_gpr = 2;
03258 }
03259 }
03260
03261
03262
03263
03264 int
03265 s390_arg_frame_offset ()
03266 {
03267 struct s390_frame frame;
03268
03269
03270
03271 s390_frame_info (&frame);
03272
03273 return frame.frame_size + STACK_POINTER_OFFSET;
03274 }
03275
03276
03277
03278
03279 static rtx
03280 save_fpr (base, offset, regnum)
03281 rtx base;
03282 int offset;
03283 int regnum;
03284 {
03285 rtx addr;
03286 addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
03287 set_mem_alias_set (addr, s390_sr_alias_set);
03288
03289 return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum));
03290 }
03291
03292
03293
03294
03295 static rtx
03296 restore_fpr (base, offset, regnum)
03297 rtx base;
03298 int offset;
03299 int regnum;
03300 {
03301 rtx addr;
03302 addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
03303 set_mem_alias_set (addr, s390_sr_alias_set);
03304
03305 return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr);
03306 }
03307
03308
03309
03310
03311
03312 void
03313 s390_function_prologue (file, lsize)
03314 FILE *file ATTRIBUTE_UNUSED;
03315 HOST_WIDE_INT lsize ATTRIBUTE_UNUSED;
03316 {
03317 s390_chunkify_pool ();
03318 s390_split_branches ();
03319 }
03320
03321
03322
03323
03324
03325 void
03326 s390_function_epilogue (file, lsize)
03327 FILE *file ATTRIBUTE_UNUSED;
03328 HOST_WIDE_INT lsize ATTRIBUTE_UNUSED;
03329 {
03330 current_function_uses_pic_offset_table = 0;
03331 s390_function_count++;
03332 }
03333
03334
03335
03336 void
03337 s390_emit_prologue ()
03338 {
03339 struct s390_frame frame;
03340 rtx insn, addr;
03341 rtx temp_reg;
03342 int i;
03343
03344
03345
03346 s390_frame_info (&frame);
03347
03348
03349
03350 if (frame.return_reg_saved_p
03351 && !has_hard_reg_initial_val (Pmode, RETURN_REGNUM)
03352 && get_pool_size () < S390_POOL_CHUNK_MAX / 2)
03353 temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
03354 else
03355 temp_reg = gen_rtx_REG (Pmode, 1);
03356
03357
03358
03359 if (frame.first_save_gpr != -1)
03360 {
03361 addr = plus_constant (stack_pointer_rtx,
03362 frame.first_save_gpr * UNITS_PER_WORD);
03363 addr = gen_rtx_MEM (Pmode, addr);
03364 set_mem_alias_set (addr, s390_sr_alias_set);
03365
03366 if (frame.first_save_gpr != frame.last_save_gpr )
03367 {
03368 insn = emit_insn (gen_store_multiple (addr,
03369 gen_rtx_REG (Pmode, frame.first_save_gpr),
03370 GEN_INT (frame.last_save_gpr
03371 - frame.first_save_gpr + 1)));
03372
03373
03374
03375
03376
03377
03378
03379
03380
03381
03382
03383
03384
03385 if (frame.first_save_gpr >= 6)
03386 {
03387 rtx pat = PATTERN (insn);
03388
03389 for (i = 0; i < XVECLEN (pat, 0); i++)
03390 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
03391 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
03392
03393 RTX_FRAME_RELATED_P (insn) = 1;
03394 }
03395 else if (frame.last_save_gpr >= 6)
03396 {
03397 rtx note, naddr;
03398 naddr = plus_constant (stack_pointer_rtx, 6 * UNITS_PER_WORD);
03399 note = gen_store_multiple (gen_rtx_MEM (Pmode, naddr),
03400 gen_rtx_REG (Pmode, 6),
03401 GEN_INT (frame.last_save_gpr - 6 + 1));
03402 REG_NOTES (insn) =
03403 gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
03404 note, REG_NOTES (insn));
03405
03406 for (i = 0; i < XVECLEN (note, 0); i++)
03407 if (GET_CODE (XVECEXP (note, 0, i)) == SET)
03408 RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1;
03409
03410 RTX_FRAME_RELATED_P (insn) = 1;
03411 }
03412 }
03413 else
03414 {
03415 insn = emit_move_insn (addr,
03416 gen_rtx_REG (Pmode, frame.first_save_gpr));
03417 RTX_FRAME_RELATED_P (insn) = 1;
03418 }
03419 }
03420
03421
03422
03423 insn = emit_insn (gen_lit ());
03424
03425
03426
03427 if (current_function_stdarg || current_function_varargs)
03428 {
03429
03430
03431 save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 32, 16);
03432 save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 24, 17);
03433
03434 if (TARGET_64BIT)
03435 {
03436
03437
03438 save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18);
03439 save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19);
03440 }
03441 }
03442
03443
03444
03445 if (!TARGET_64BIT)
03446 {
03447
03448 if (regs_ever_live[18])
03449 {
03450 insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18);
03451 RTX_FRAME_RELATED_P (insn) = 1;
03452 }
03453 if (regs_ever_live[19])
03454 {
03455 insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19);
03456 RTX_FRAME_RELATED_P (insn) = 1;
03457 }
03458 }
03459
03460
03461
03462 if (frame.frame_size > 0)
03463 {
03464 rtx frame_off = GEN_INT (-frame.frame_size);
03465
03466
03467
03468 if (TARGET_BACKCHAIN || frame.save_fprs_p)
03469 {
03470 insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
03471 }
03472
03473
03474
03475 frame_off = GEN_INT (-frame.frame_size);
03476 if (!CONST_OK_FOR_LETTER_P (-frame.frame_size, 'K'))
03477 frame_off = force_const_mem (Pmode, frame_off);
03478
03479 insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
03480 RTX_FRAME_RELATED_P (insn) = 1;
03481 REG_NOTES (insn) =
03482 gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
03483 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
03484 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
03485 GEN_INT (-frame.frame_size))),
03486 REG_NOTES (insn));
03487
03488
03489
03490 if (TARGET_BACKCHAIN)
03491 {
03492 addr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
03493 set_mem_alias_set (addr, s390_sr_alias_set);
03494 insn = emit_insn (gen_move_insn (addr, temp_reg));
03495 }
03496 }
03497
03498
03499
03500 if (frame.save_fprs_p)
03501 {
03502 insn = emit_insn (gen_add2_insn (temp_reg, GEN_INT(-64)));
03503
03504 for (i = 24; i < 32; i++)
03505 if (regs_ever_live[i])
03506 {
03507 rtx addr = plus_constant (stack_pointer_rtx,
03508 frame.frame_size - 64 + (i-24)*8);
03509
03510 insn = save_fpr (temp_reg, (i-24)*8, i);
03511 RTX_FRAME_RELATED_P (insn) = 1;
03512 REG_NOTES (insn) =
03513 gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
03514 gen_rtx_SET (VOIDmode,
03515 gen_rtx_MEM (DFmode, addr),
03516 gen_rtx_REG (DFmode, i)),
03517 REG_NOTES (insn));
03518 }
03519 }
03520
03521
03522
03523 if (frame.frame_pointer_p)
03524 {
03525 insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
03526 RTX_FRAME_RELATED_P (insn) = 1;
03527 }
03528
03529
03530
03531 if (current_function_uses_pic_offset_table)
03532 {
03533 rtx got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
03534 SYMBOL_REF_FLAG (got_symbol) = 1;
03535
03536 if (TARGET_64BIT)
03537 {
03538 insn = emit_insn (gen_movdi (pic_offset_table_rtx,
03539 got_symbol));
03540
03541
03542 REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
03543 REG_NOTES (insn));
03544 }
03545 else
03546 {
03547 got_symbol = gen_rtx_UNSPEC (VOIDmode,
03548 gen_rtvec (1, got_symbol), 100);
03549 got_symbol = gen_rtx_CONST (VOIDmode, got_symbol);
03550 got_symbol = force_const_mem (Pmode, got_symbol);
03551 insn = emit_move_insn (pic_offset_table_rtx,
03552 got_symbol);
03553 REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
03554 REG_NOTES (insn));
03555
03556 insn = emit_insn (gen_add2_insn (pic_offset_table_rtx,
03557 gen_rtx_REG (Pmode, BASE_REGISTER)));
03558 REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
03559 REG_NOTES (insn));
03560 }
03561 }
03562 }
03563
03564
03565
03566 void
03567 s390_emit_epilogue ()
03568 {
03569 struct s390_frame frame;
03570 rtx frame_pointer, return_reg;
03571 int area_bottom, area_top, offset;
03572 rtvec p;
03573
03574
03575
03576 s390_frame_info (&frame);
03577
03578
03579
03580 frame_pointer = frame.frame_pointer_p ?
03581 hard_frame_pointer_rtx : stack_pointer_rtx;
03582
03583
03584
03585 if (frame.first_restore_gpr != -1)
03586 {
03587 area_bottom = frame.first_restore_gpr * UNITS_PER_WORD;
03588 area_top = (frame.last_save_gpr + 1) * UNITS_PER_WORD;
03589 }
03590 else
03591 {
03592 area_bottom = INT_MAX;
03593 area_top = INT_MIN;
03594 }
03595
03596 if (TARGET_64BIT)
03597 {
03598 if (frame.save_fprs_p)
03599 {
03600 if (area_bottom > -64)
03601 area_bottom = -64;
03602 if (area_top < 0)
03603 area_top = 0;
03604 }
03605 }
03606 else
03607 {
03608 if (regs_ever_live[18])
03609 {
03610 if (area_bottom > STACK_POINTER_OFFSET - 16)
03611 area_bottom = STACK_POINTER_OFFSET - 16;
03612 if (area_top < STACK_POINTER_OFFSET - 8)
03613 area_top = STACK_POINTER_OFFSET - 8;
03614 }
03615 if (regs_ever_live[19])
03616 {
03617 if (area_bottom > STACK_POINTER_OFFSET - 8)
03618 area_bottom = STACK_POINTER_OFFSET - 8;
03619 if (area_top < STACK_POINTER_OFFSET)
03620 area_top = STACK_POINTER_OFFSET;
03621 }
03622 }
03623
03624
03625
03626
03627 if (area_top <= area_bottom)
03628 {
03629
03630 }
03631 else if (frame.frame_size + area_bottom >= 0
03632 && frame.frame_size + area_top <= 4096)
03633 {
03634
03635 offset = frame.frame_size;
03636 }
03637 else
03638 {
03639 rtx insn, frame_off;
03640
03641 offset = area_bottom < 0 ? -area_bottom : 0;
03642 frame_off = GEN_INT (frame.frame_size - offset);
03643
03644 if (!CONST_OK_FOR_LETTER_P (INTVAL (frame_off), 'K'))
03645 frame_off = force_const_mem (Pmode, frame_off);
03646
03647 insn = emit_insn (gen_add2_insn (frame_pointer, frame_off));
03648 }
03649
03650
03651
03652 if (TARGET_64BIT)
03653 {
03654 int i;
03655
03656 if (frame.save_fprs_p)
03657 for (i = 24; i < 32; i++)
03658 if (regs_ever_live[i] && !global_regs[i])
03659 restore_fpr (frame_pointer,
03660 offset - 64 + (i-24) * 8, i);
03661 }
03662 else
03663 {
03664 if (regs_ever_live[18] && !global_regs[18])
03665 restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 16, 18);
03666 if (regs_ever_live[19] && !global_regs[19])
03667 restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 8, 19);
03668 }
03669
03670
03671
03672 return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
03673
03674
03675
03676 if (frame.first_restore_gpr != -1)
03677 {
03678 rtx addr;
03679 int i;
03680
03681
03682
03683
03684 for (i = frame.first_restore_gpr;
03685 i <= frame.last_save_gpr;
03686 i++)
03687 {
03688
03689
03690 if (i == STACK_POINTER_REGNUM
03691 || i == RETURN_REGNUM
03692 || i == BASE_REGISTER
03693 || (flag_pic && i == PIC_OFFSET_TABLE_REGNUM))
03694 continue;
03695
03696 if (global_regs[i])
03697 {
03698 addr = plus_constant (frame_pointer,
03699 offset + i * UNITS_PER_WORD);
03700 addr = gen_rtx_MEM (Pmode, addr);
03701 set_mem_alias_set (addr, s390_sr_alias_set);
03702 emit_move_insn (addr, gen_rtx_REG (Pmode, i));
03703 }
03704 }
03705
03706
03707
03708
03709 if (frame.last_save_gpr >= RETURN_REGNUM
03710 && frame.first_restore_gpr < RETURN_REGNUM)
03711 {
03712 int return_regnum = find_unused_clobbered_reg();
03713 if (!return_regnum)
03714 return_regnum = 4;
03715 return_reg = gen_rtx_REG (Pmode, return_regnum);
03716
03717 addr = plus_constant (frame_pointer,
03718 offset + RETURN_REGNUM * UNITS_PER_WORD);
03719 addr = gen_rtx_MEM (Pmode, addr);
03720 set_mem_alias_set (addr, s390_sr_alias_set);
03721 emit_move_insn (return_reg, addr);
03722 }
03723
03724
03725
03726
03727
03728 emit_insn (gen_blockage());
03729
03730 addr = plus_constant (frame_pointer,
03731 offset + frame.first_restore_gpr * UNITS_PER_WORD);
03732 addr = gen_rtx_MEM (Pmode, addr);
03733 set_mem_alias_set (addr, s390_sr_alias_set);
03734
03735 if (frame.first_restore_gpr != frame.last_save_gpr)
03736 {
03737 emit_insn (gen_load_multiple (
03738 gen_rtx_REG (Pmode, frame.first_restore_gpr),
03739 addr,
03740 GEN_INT (frame.last_save_gpr - frame.first_restore_gpr + 1)));
03741 }
03742 else
03743 {
03744 emit_move_insn (gen_rtx_REG (Pmode, frame.first_restore_gpr),
03745 addr);
03746 }
03747 }
03748
03749
03750
03751 p = rtvec_alloc (2);
03752
03753 RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
03754 RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
03755 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
03756 }
03757
03758
03759
03760
03761
03762
03763 static int
03764 s390_function_arg_size (mode, type)
03765 enum machine_mode mode;
03766 tree type;
03767 {
03768 if (type)
03769 return int_size_in_bytes (type);
03770
03771
03772 if (mode != BLKmode)
03773 return GET_MODE_SIZE (mode);
03774
03775
03776 abort ();
03777 }
03778
03779
03780
03781
03782
03783
03784
03785 int
03786 s390_function_arg_pass_by_reference (mode, type)
03787 enum machine_mode mode;
03788 tree type;
03789 {
03790 int size = s390_function_arg_size (mode, type);
03791
03792 if (type)
03793 {
03794 if (AGGREGATE_TYPE_P (type) &&
03795 size != 1 && size != 2 && size != 4 && size != 8)
03796 return 1;
03797
03798 if (TREE_CODE (type) == COMPLEX_TYPE)
03799 return 1;
03800 }
03801 return 0;
03802
03803 }
03804
03805
03806
03807
03808
03809
03810
03811 void
03812 s390_function_arg_advance (cum, mode, type, named)
03813 CUMULATIVE_ARGS *cum;
03814 enum machine_mode mode;
03815 tree type;
03816 int named ATTRIBUTE_UNUSED;
03817 {
03818 if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode))
03819 {
03820 cum->fprs++;
03821 }
03822 else if (s390_function_arg_pass_by_reference (mode, type))
03823 {
03824 cum->gprs += 1;
03825 }
03826 else
03827 {
03828 int size = s390_function_arg_size (mode, type);
03829 cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
03830 }
03831 }
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851
03852 rtx
03853 s390_function_arg (cum, mode, type, named)
03854 CUMULATIVE_ARGS *cum;
03855 enum machine_mode mode;
03856 tree type;
03857 int named ATTRIBUTE_UNUSED;
03858 {
03859 if (s390_function_arg_pass_by_reference (mode, type))
03860 return 0;
03861
03862 if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode))
03863 {
03864 if (cum->fprs + 1 > (TARGET_64BIT? 4 : 2))
03865 return 0;
03866 else
03867 return gen_rtx (REG, mode, cum->fprs + 16);
03868 }
03869 else
03870 {
03871 int size = s390_function_arg_size (mode, type);
03872 int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD;
03873
03874 if (cum->gprs + n_gprs > 5)
03875 return 0;
03876 else
03877 return gen_rtx (REG, mode, cum->gprs + 2);
03878 }
03879 }
03880
03881
03882
03883
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897
03898
03899
03900
03901
03902
03903
03904 tree
03905 s390_build_va_list ()
03906 {
03907 tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
03908
03909 record = make_lang_type (RECORD_TYPE);
03910
03911 type_decl =
03912 build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
03913
03914 f_gpr = build_decl (FIELD_DECL, get_identifier ("__gpr"),
03915 long_integer_type_node);
03916 f_fpr = build_decl (FIELD_DECL, get_identifier ("__fpr"),
03917 long_integer_type_node);
03918 f_ovf = build_decl (FIELD_DECL, get_identifier ("__overflow_arg_area"),
03919 ptr_type_node);
03920 f_sav = build_decl (FIELD_DECL, get_identifier ("__reg_save_area"),
03921 ptr_type_node);
03922
03923 DECL_FIELD_CONTEXT (f_gpr) = record;
03924 DECL_FIELD_CONTEXT (f_fpr) = record;
03925 DECL_FIELD_CONTEXT (f_ovf) = record;
03926 DECL_FIELD_CONTEXT (f_sav) = record;
03927
03928 TREE_CHAIN (record) = type_decl;
03929 TYPE_NAME (record) = type_decl;
03930 TYPE_FIELDS (record) = f_gpr;
03931 TREE_CHAIN (f_gpr) = f_fpr;
03932 TREE_CHAIN (f_fpr) = f_ovf;
03933 TREE_CHAIN (f_ovf) = f_sav;
03934
03935 layout_type (record);
03936
03937
03938 return build_array_type (record, build_index_type (size_zero_node));
03939 }
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954
03955 void
03956 s390_va_start (stdarg_p, valist, nextarg)
03957 int stdarg_p;
03958 tree valist;
03959 rtx nextarg ATTRIBUTE_UNUSED;
03960 {
03961 HOST_WIDE_INT n_gpr, n_fpr;
03962 int off;
03963 tree f_gpr, f_fpr, f_ovf, f_sav;
03964 tree gpr, fpr, ovf, sav, t;
03965
03966 f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
03967 f_fpr = TREE_CHAIN (f_gpr);
03968 f_ovf = TREE_CHAIN (f_fpr);
03969 f_sav = TREE_CHAIN (f_ovf);
03970
03971 valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
03972 gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
03973 fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
03974 ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
03975 sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
03976
03977
03978
03979 n_gpr = current_function_args_info.gprs;
03980 n_fpr = current_function_args_info.fprs;
03981
03982 t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
03983 TREE_SIDE_EFFECTS (t) = 1;
03984 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
03985
03986 t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
03987 TREE_SIDE_EFFECTS (t) = 1;
03988 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
03989
03990
03991 t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
03992
03993 off = INTVAL (current_function_arg_offset_rtx);
03994 off = off < 0 ? 0 : off;
03995 if (! stdarg_p)
03996 off = off > 0 ? off - UNITS_PER_WORD : off;
03997 if (TARGET_DEBUG_ARG)
03998 fprintf (stderr, "va_start: n_gpr = %d, n_fpr = %d off %d\n",
03999 (int)n_gpr, (int)n_fpr, off);
04000
04001 t = build (PLUS_EXPR, TREE_TYPE (ovf), t, build_int_2 (off, 0));
04002
04003 t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
04004 TREE_SIDE_EFFECTS (t) = 1;
04005 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
04006
04007
04008 t = make_tree (TREE_TYPE (sav), virtual_incoming_args_rtx);
04009 t = build (PLUS_EXPR, TREE_TYPE (sav), t,
04010 build_int_2 (-STACK_POINTER_OFFSET, -1));
04011 t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
04012 TREE_SIDE_EFFECTS (t) = 1;
04013 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
04014 }
04015
04016
04017
04018
04019
04020
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040 rtx
04041 s390_va_arg (valist, type)
04042 tree valist;
04043 tree type;
04044 {
04045 tree f_gpr, f_fpr, f_ovf, f_sav;
04046 tree gpr, fpr, ovf, sav, reg, t, u;
04047 int indirect_p, size, n_reg, sav_ofs, sav_scale, max_reg;
04048 rtx lab_false, lab_over, addr_rtx, r;
04049
04050 f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
04051 f_fpr = TREE_CHAIN (f_gpr);
04052 f_ovf = TREE_CHAIN (f_fpr);
04053 f_sav = TREE_CHAIN (f_ovf);
04054
04055 valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
04056 gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
04057 fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
04058 ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
04059 sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
04060
04061 size = int_size_in_bytes (type);
04062
04063 if (s390_function_arg_pass_by_reference (TYPE_MODE (type), type))
04064 {
04065 if (TARGET_DEBUG_ARG)
04066 {
04067 fprintf (stderr, "va_arg: aggregate type");
04068 debug_tree (type);
04069 }
04070
04071
04072 indirect_p = 1;
04073 reg = gpr;
04074 n_reg = 1;
04075 sav_ofs = 2 * UNITS_PER_WORD;
04076 sav_scale = UNITS_PER_WORD;
04077 size = UNITS_PER_WORD;
04078 max_reg = 4;
04079 }
04080 else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT)
04081 {
04082 if (TARGET_DEBUG_ARG)
04083 {
04084 fprintf (stderr, "va_arg: float type");
04085 debug_tree (type);
04086 }
04087
04088
04089 indirect_p = 0;
04090 reg = fpr;
04091 n_reg = 1;
04092 sav_ofs = 16 * UNITS_PER_WORD;
04093 sav_scale = 8;
04094
04095 max_reg = TARGET_64BIT ? 3 : 1;
04096 }
04097 else
04098 {
04099 if (TARGET_DEBUG_ARG)
04100 {
04101 fprintf (stderr, "va_arg: other type");
04102 debug_tree (type);
04103 }
04104
04105
04106 indirect_p = 0;
04107 reg = gpr;
04108 n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
04109 sav_ofs = 2 * UNITS_PER_WORD;
04110 if (TARGET_64BIT)
04111 sav_ofs += TYPE_MODE (type) == SImode ? 4 :
04112 TYPE_MODE (type) == HImode ? 6 :
04113 TYPE_MODE (type) == QImode ? 7 : 0;
04114 else
04115 sav_ofs += TYPE_MODE (type) == HImode ? 2 :
04116 TYPE_MODE (type) == QImode ? 3 : 0;
04117
04118 sav_scale = UNITS_PER_WORD;
04119 if (n_reg > 1)
04120 max_reg = 3;
04121 else
04122 max_reg = 4;
04123 }
04124
04125
04126
04127 lab_false = gen_label_rtx ();
04128 lab_over = gen_label_rtx ();
04129 addr_rtx = gen_reg_rtx (Pmode);
04130
04131 emit_cmp_and_jump_insns (expand_expr (reg, NULL_RTX, Pmode, EXPAND_NORMAL),
04132 GEN_INT (max_reg),
04133 GT, const1_rtx, Pmode, 0, lab_false);
04134
04135 if (sav_ofs)
04136 t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
04137 else
04138 t = sav;
04139
04140 u = build (MULT_EXPR, long_integer_type_node,
04141 reg, build_int_2 (sav_scale, 0));
04142 TREE_SIDE_EFFECTS (u) = 1;
04143
04144 t = build (PLUS_EXPR, ptr_type_node, t, u);
04145 TREE_SIDE_EFFECTS (t) = 1;
04146
04147 r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
04148 if (r != addr_rtx)
04149 emit_move_insn (addr_rtx, r);
04150
04151
04152 emit_jump_insn (gen_jump (lab_over));
04153 emit_barrier ();
04154 emit_label (lab_false);
04155
04156
04157
04158 t = save_expr (ovf);
04159
04160
04161
04162 if (size < UNITS_PER_WORD)
04163 {
04164 t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (UNITS_PER_WORD-size, 0));
04165 t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
04166 TREE_SIDE_EFFECTS (t) = 1;
04167 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
04168
04169 t = save_expr (ovf);
04170 }
04171
04172 r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
04173 if (r != addr_rtx)
04174 emit_move_insn (addr_rtx, r);
04175
04176 t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
04177 t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
04178 TREE_SIDE_EFFECTS (t) = 1;
04179 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
04180
04181 emit_label (lab_over);
04182
04183
04184
04185
04186 u = build (PREINCREMENT_EXPR, TREE_TYPE (reg), reg,
04187 build_int_2 (n_reg, 0));
04188 TREE_SIDE_EFFECTS (u) = 1;
04189 expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL);
04190
04191 if (indirect_p)
04192 {
04193 r = gen_rtx_MEM (Pmode, addr_rtx);
04194 set_mem_alias_set (r, get_varargs_alias_set ());
04195 emit_move_insn (addr_rtx, r);
04196 }
04197
04198
04199 return addr_rtx;
04200 }
04201
04202
04203
04204
04205
04206
04207
04208
04209 void
04210 s390_trampoline_template (file)
04211 FILE *file;
04212 {
04213 if (TARGET_64BIT)
04214 {
04215 fprintf (file, "larl\t%s,0f\n", reg_names[1]);
04216 fprintf (file, "lg\t%s,0(%s)\n", reg_names[0], reg_names[1]);
04217 fprintf (file, "lg\t%s,8(%s)\n", reg_names[1], reg_names[1]);
04218 fprintf (file, "br\t%s\n", reg_names[1]);
04219 fprintf (file, "0:\t.quad\t0\n");
04220 fprintf (file, ".quad\t0\n");
04221 }
04222 else
04223 {
04224 fprintf (file, "basr\t%s,0\n", reg_names[1]);
04225 fprintf (file, "l\t%s,10(%s)\n", reg_names[0], reg_names[1]);
04226 fprintf (file, "l\t%s,14(%s)\n", reg_names[1], reg_names[1]);
04227 fprintf (file, "br\t%s\n", reg_names[1]);
04228 fprintf (file, ".long\t0\n");
04229 fprintf (file, ".long\t0\n");
04230 }
04231 }
04232
04233
04234
04235
04236
04237 void
04238 s390_initialize_trampoline (addr, fnaddr, cxt)
04239 rtx addr;
04240 rtx fnaddr;
04241 rtx cxt;
04242 {
04243 emit_move_insn (gen_rtx
04244 (MEM, Pmode,
04245 memory_address (Pmode,
04246 plus_constant (addr, (TARGET_64BIT ? 20 : 12) ))), cxt);
04247 emit_move_insn (gen_rtx
04248 (MEM, Pmode,
04249 memory_address (Pmode,
04250 plus_constant (addr, (TARGET_64BIT ? 28 : 16) ))), fnaddr);
04251 }
04252
04253
04254
04255
04256 rtx
04257 s390_gen_rtx_const_DI (high, low)
04258 int high;
04259 int low;
04260 {
04261 #if HOST_BITS_PER_WIDE_INT >= 64
04262 HOST_WIDE_INT val;
04263 val = (HOST_WIDE_INT)high;
04264 val <<= 32;
04265 val |= (HOST_WIDE_INT)low;
04266
04267 return GEN_INT (val);
04268 #else
04269 #if HOST_BITS_PER_WIDE_INT >= 32
04270 return immed_double_const ((HOST_WIDE_INT)low, (HOST_WIDE_INT)high, DImode);
04271 #else
04272 abort ();
04273 #endif
04274 #endif
04275 }
04276
04277
04278
04279
04280 void
04281 s390_function_profiler (file, labelno)
04282 FILE *file;
04283 int labelno;
04284 {
04285 rtx op[7];
04286
04287 char label[128];
04288 sprintf (label, "%sP%d", LPREFIX, labelno);
04289
04290 fprintf (file, "# function profiler \n");
04291
04292 op[0] = gen_rtx_REG (Pmode, RETURN_REGNUM);
04293 op[1] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
04294 op[1] = gen_rtx_MEM (Pmode, plus_constant (op[1], UNITS_PER_WORD));
04295
04296 op[2] = gen_rtx_REG (Pmode, 1);
04297 op[3] = gen_rtx_SYMBOL_REF (Pmode, label);
04298 SYMBOL_REF_FLAG (op[3]) = 1;
04299
04300 op[4] = gen_rtx_SYMBOL_REF (Pmode, "_mcount");
04301 if (flag_pic)
04302 {
04303 op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), 113);
04304 op[4] = gen_rtx_CONST (Pmode, op[4]);
04305 }
04306
04307 if (TARGET_64BIT)
04308 {
04309 output_asm_insn ("stg\t%0,%1", op);
04310 output_asm_insn ("larl\t%2,%3", op);
04311 output_asm_insn ("brasl\t%0,%4", op);
04312 output_asm_insn ("lg\t%0,%1", op);
04313 }
04314 else if (!flag_pic)
04315 {
04316 op[6] = gen_label_rtx ();
04317
04318 output_asm_insn ("st\t%0,%1", op);
04319 output_asm_insn ("bras\t%2,%l6", op);
04320 output_asm_insn (".long\t%4", op);
04321 output_asm_insn (".long\t%3", op);
04322 ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6]));
04323 output_asm_insn ("l\t%0,0(%2)", op);
04324 output_asm_insn ("l\t%2,4(%2)", op);
04325 output_asm_insn ("basr\t%0,%0", op);
04326 output_asm_insn ("l\t%0,%1", op);
04327 }
04328 else
04329 {
04330 op[5] = gen_label_rtx ();
04331 op[6] = gen_label_rtx ();
04332
04333 output_asm_insn ("st\t%0,%1", op);
04334 output_asm_insn ("bras\t%2,%l6", op);
04335 ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5]));
04336 output_asm_insn (".long\t%4-%l5", op);
04337 output_asm_insn (".long\t%3-%l5", op);
04338 ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6]));
04339 output_asm_insn ("lr\t%0,%2", op);
04340 output_asm_insn ("a\t%0,0(%2)", op);
04341 output_asm_insn ("a\t%2,4(%2)", op);
04342 output_asm_insn ("basr\t%0,%0", op);
04343 output_asm_insn ("l\t%0,%1", op);
04344 }
04345 }
04346