1107590Sobrien/* Subroutines used for code generation on IBM S/390 and zSeries 2169689Skan Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 3132718Skan Free Software Foundation, Inc. 4107590Sobrien Contributed by Hartmut Penner (hpenner@de.ibm.com) and 5107590Sobrien Ulrich Weigand (uweigand@de.ibm.com). 6107590Sobrien 7132718SkanThis file is part of GCC. 8107590Sobrien 9132718SkanGCC is free software; you can redistribute it and/or modify it under 10132718Skanthe terms of the GNU General Public License as published by the Free 11132718SkanSoftware Foundation; either version 2, or (at your option) any later 12132718Skanversion. 13107590Sobrien 14132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 15132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 16132718SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17132718Skanfor more details. 18107590Sobrien 19107590SobrienYou should have received a copy of the GNU General Public License 20132718Skanalong with GCC; see the file COPYING. If not, write to the Free 21169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 22169689Skan02110-1301, USA. */ 23107590Sobrien 24107590Sobrien#include "config.h" 25107590Sobrien#include "system.h" 26132718Skan#include "coretypes.h" 27132718Skan#include "tm.h" 28107590Sobrien#include "rtl.h" 29107590Sobrien#include "tree.h" 30107590Sobrien#include "tm_p.h" 31107590Sobrien#include "regs.h" 32107590Sobrien#include "hard-reg-set.h" 33107590Sobrien#include "real.h" 34107590Sobrien#include "insn-config.h" 35107590Sobrien#include "conditions.h" 36107590Sobrien#include "output.h" 37107590Sobrien#include "insn-attr.h" 38107590Sobrien#include "flags.h" 39107590Sobrien#include "except.h" 40107590Sobrien#include "function.h" 41107590Sobrien#include "recog.h" 42107590Sobrien#include "expr.h" 43107590Sobrien#include "reload.h" 44107590Sobrien#include "toplev.h" 45107590Sobrien#include "basic-block.h" 46107590Sobrien#include "integrate.h" 47107590Sobrien#include "ggc.h" 48107590Sobrien#include "target.h" 49107590Sobrien#include "target-def.h" 50107590Sobrien#include "debug.h" 51117395Skan#include "langhooks.h" 52117395Skan#include "optabs.h" 53169689Skan#include "tree-gimple.h" 54107590Sobrien 55107590Sobrien 56169689Skan/* Define the specific costs for a given cpu. */ 57132718Skan 58169689Skanstruct processor_costs 59169689Skan{ 60169689Skan /* multiplication */ 61169689Skan const int m; /* cost of an M instruction. */ 62169689Skan const int mghi; /* cost of an MGHI instruction. */ 63169689Skan const int mh; /* cost of an MH instruction. */ 64169689Skan const int mhi; /* cost of an MHI instruction. */ 65169689Skan const int ml; /* cost of an ML instruction. */ 66169689Skan const int mr; /* cost of an MR instruction. */ 67169689Skan const int ms; /* cost of an MS instruction. */ 68169689Skan const int msg; /* cost of an MSG instruction. */ 69169689Skan const int msgf; /* cost of an MSGF instruction. */ 70169689Skan const int msgfr; /* cost of an MSGFR instruction. */ 71169689Skan const int msgr; /* cost of an MSGR instruction. */ 72169689Skan const int msr; /* cost of an MSR instruction. */ 73169689Skan const int mult_df; /* cost of multiplication in DFmode. */ 74169689Skan const int mxbr; 75169689Skan /* square root */ 76169689Skan const int sqxbr; /* cost of square root in TFmode. */ 77169689Skan const int sqdbr; /* cost of square root in DFmode. */ 78169689Skan const int sqebr; /* cost of square root in SFmode. */ 79169689Skan /* multiply and add */ 80169689Skan const int madbr; /* cost of multiply and add in DFmode. */ 81169689Skan const int maebr; /* cost of multiply and add in SFmode. */ 82169689Skan /* division */ 83169689Skan const int dxbr; 84169689Skan const int dxr; 85169689Skan const int ddbr; 86169689Skan const int ddr; 87169689Skan const int debr; 88169689Skan const int der; 89169689Skan const int dlgr; 90169689Skan const int dlr; 91169689Skan const int dr; 92169689Skan const int dsgfr; 93169689Skan const int dsgr; 94169689Skan}; 95132718Skan 96169689Skanconst struct processor_costs *s390_cost; 97132718Skan 98169689Skanstatic const 99169689Skanstruct processor_costs z900_cost = 100169689Skan{ 101169689Skan COSTS_N_INSNS (5), /* M */ 102169689Skan COSTS_N_INSNS (10), /* MGHI */ 103169689Skan COSTS_N_INSNS (5), /* MH */ 104169689Skan COSTS_N_INSNS (4), /* MHI */ 105169689Skan COSTS_N_INSNS (5), /* ML */ 106169689Skan COSTS_N_INSNS (5), /* MR */ 107169689Skan COSTS_N_INSNS (4), /* MS */ 108169689Skan COSTS_N_INSNS (15), /* MSG */ 109169689Skan COSTS_N_INSNS (7), /* MSGF */ 110169689Skan COSTS_N_INSNS (7), /* MSGFR */ 111169689Skan COSTS_N_INSNS (10), /* MSGR */ 112169689Skan COSTS_N_INSNS (4), /* MSR */ 113169689Skan COSTS_N_INSNS (7), /* multiplication in DFmode */ 114169689Skan COSTS_N_INSNS (13), /* MXBR */ 115169689Skan COSTS_N_INSNS (136), /* SQXBR */ 116169689Skan COSTS_N_INSNS (44), /* SQDBR */ 117169689Skan COSTS_N_INSNS (35), /* SQEBR */ 118169689Skan COSTS_N_INSNS (18), /* MADBR */ 119169689Skan COSTS_N_INSNS (13), /* MAEBR */ 120169689Skan COSTS_N_INSNS (134), /* DXBR */ 121169689Skan COSTS_N_INSNS (135), /* DXR */ 122169689Skan COSTS_N_INSNS (30), /* DDBR */ 123169689Skan COSTS_N_INSNS (30), /* DDR */ 124169689Skan COSTS_N_INSNS (27), /* DEBR */ 125169689Skan COSTS_N_INSNS (26), /* DER */ 126169689Skan COSTS_N_INSNS (220), /* DLGR */ 127169689Skan COSTS_N_INSNS (34), /* DLR */ 128169689Skan COSTS_N_INSNS (34), /* DR */ 129169689Skan COSTS_N_INSNS (32), /* DSGFR */ 130169689Skan COSTS_N_INSNS (32), /* DSGR */ 131169689Skan}; 132107590Sobrien 133169689Skanstatic const 134169689Skanstruct processor_costs z990_cost = 135169689Skan{ 136169689Skan COSTS_N_INSNS (4), /* M */ 137169689Skan COSTS_N_INSNS (2), /* MGHI */ 138169689Skan COSTS_N_INSNS (2), /* MH */ 139169689Skan COSTS_N_INSNS (2), /* MHI */ 140169689Skan COSTS_N_INSNS (4), /* ML */ 141169689Skan COSTS_N_INSNS (4), /* MR */ 142169689Skan COSTS_N_INSNS (5), /* MS */ 143169689Skan COSTS_N_INSNS (6), /* MSG */ 144169689Skan COSTS_N_INSNS (4), /* MSGF */ 145169689Skan COSTS_N_INSNS (4), /* MSGFR */ 146169689Skan COSTS_N_INSNS (4), /* MSGR */ 147169689Skan COSTS_N_INSNS (4), /* MSR */ 148169689Skan COSTS_N_INSNS (1), /* multiplication in DFmode */ 149169689Skan COSTS_N_INSNS (28), /* MXBR */ 150169689Skan COSTS_N_INSNS (130), /* SQXBR */ 151169689Skan COSTS_N_INSNS (66), /* SQDBR */ 152169689Skan COSTS_N_INSNS (38), /* SQEBR */ 153169689Skan COSTS_N_INSNS (1), /* MADBR */ 154169689Skan COSTS_N_INSNS (1), /* MAEBR */ 155169689Skan COSTS_N_INSNS (60), /* DXBR */ 156169689Skan COSTS_N_INSNS (72), /* DXR */ 157169689Skan COSTS_N_INSNS (40), /* DDBR */ 158169689Skan COSTS_N_INSNS (44), /* DDR */ 159169689Skan COSTS_N_INSNS (26), /* DDBR */ 160169689Skan COSTS_N_INSNS (28), /* DER */ 161169689Skan COSTS_N_INSNS (176), /* DLGR */ 162169689Skan COSTS_N_INSNS (31), /* DLR */ 163169689Skan COSTS_N_INSNS (31), /* DR */ 164169689Skan COSTS_N_INSNS (31), /* DSGFR */ 165169689Skan COSTS_N_INSNS (31), /* DSGR */ 166169689Skan}; 167107590Sobrien 168169689Skanstatic const 169169689Skanstruct processor_costs z9_109_cost = 170169689Skan{ 171169689Skan COSTS_N_INSNS (4), /* M */ 172169689Skan COSTS_N_INSNS (2), /* MGHI */ 173169689Skan COSTS_N_INSNS (2), /* MH */ 174169689Skan COSTS_N_INSNS (2), /* MHI */ 175169689Skan COSTS_N_INSNS (4), /* ML */ 176169689Skan COSTS_N_INSNS (4), /* MR */ 177169689Skan COSTS_N_INSNS (5), /* MS */ 178169689Skan COSTS_N_INSNS (6), /* MSG */ 179169689Skan COSTS_N_INSNS (4), /* MSGF */ 180169689Skan COSTS_N_INSNS (4), /* MSGFR */ 181169689Skan COSTS_N_INSNS (4), /* MSGR */ 182169689Skan COSTS_N_INSNS (4), /* MSR */ 183169689Skan COSTS_N_INSNS (1), /* multiplication in DFmode */ 184169689Skan COSTS_N_INSNS (28), /* MXBR */ 185169689Skan COSTS_N_INSNS (130), /* SQXBR */ 186169689Skan COSTS_N_INSNS (66), /* SQDBR */ 187169689Skan COSTS_N_INSNS (38), /* SQEBR */ 188169689Skan COSTS_N_INSNS (1), /* MADBR */ 189169689Skan COSTS_N_INSNS (1), /* MAEBR */ 190169689Skan COSTS_N_INSNS (60), /* DXBR */ 191169689Skan COSTS_N_INSNS (72), /* DXR */ 192169689Skan COSTS_N_INSNS (40), /* DDBR */ 193169689Skan COSTS_N_INSNS (37), /* DDR */ 194169689Skan COSTS_N_INSNS (26), /* DDBR */ 195169689Skan COSTS_N_INSNS (28), /* DER */ 196169689Skan COSTS_N_INSNS (30), /* DLGR */ 197169689Skan COSTS_N_INSNS (23), /* DLR */ 198169689Skan COSTS_N_INSNS (23), /* DR */ 199169689Skan COSTS_N_INSNS (24), /* DSGFR */ 200169689Skan COSTS_N_INSNS (24), /* DSGR */ 201169689Skan}; 202107590Sobrien 203107590Sobrienextern int reload_completed; 204107590Sobrien 205107590Sobrien/* Save information from a "cmpxx" operation until the branch or scc is 206107590Sobrien emitted. */ 207107590Sobrienrtx s390_compare_op0, s390_compare_op1; 208107590Sobrien 209169689Skan/* Save the result of a compare_and_swap until the branch or scc is 210169689Skan emitted. */ 211169689Skanrtx s390_compare_emitted = NULL_RTX; 212169689Skan 213107590Sobrien/* Structure used to hold the components of a S/390 memory 214107590Sobrien address. A legitimate address on S/390 is of the general 215107590Sobrien form 216107590Sobrien base + index + displacement 217107590Sobrien where any of the components is optional. 218107590Sobrien 219107590Sobrien base and index are registers of the class ADDR_REGS, 220107590Sobrien displacement is an unsigned 12-bit immediate constant. */ 221107590Sobrien 222107590Sobrienstruct s390_address 223107590Sobrien{ 224107590Sobrien rtx base; 225107590Sobrien rtx indx; 226107590Sobrien rtx disp; 227169689Skan bool pointer; 228169689Skan bool literal_pool; 229107590Sobrien}; 230107590Sobrien 231132718Skan/* Which cpu are we tuning for. */ 232169689Skanenum processor_type s390_tune = PROCESSOR_max; 233132718Skanenum processor_flags s390_tune_flags; 234132718Skan/* Which instruction set architecture to use. */ 235132718Skanenum processor_type s390_arch; 236132718Skanenum processor_flags s390_arch_flags; 237132718Skan 238169689SkanHOST_WIDE_INT s390_warn_framesize = 0; 239169689SkanHOST_WIDE_INT s390_stack_size = 0; 240169689SkanHOST_WIDE_INT s390_stack_guard = 0; 241132718Skan 242169689Skan/* The following structure is embedded in the machine 243169689Skan specific part of struct function. */ 244107590Sobrien 245169689Skanstruct s390_frame_layout GTY (()) 246107590Sobrien{ 247169689Skan /* Offset within stack frame. */ 248169689Skan HOST_WIDE_INT gprs_offset; 249169689Skan HOST_WIDE_INT f0_offset; 250169689Skan HOST_WIDE_INT f4_offset; 251169689Skan HOST_WIDE_INT f8_offset; 252169689Skan HOST_WIDE_INT backchain_offset; 253117395Skan 254169689Skan /* Number of first and last gpr where slots in the register 255169689Skan save area are reserved for. */ 256169689Skan int first_save_gpr_slot; 257169689Skan int last_save_gpr_slot; 258132718Skan 259117395Skan /* Number of first and last gpr to be saved, restored. */ 260107590Sobrien int first_save_gpr; 261107590Sobrien int first_restore_gpr; 262107590Sobrien int last_save_gpr; 263169689Skan int last_restore_gpr; 264107590Sobrien 265169689Skan /* Bits standing for floating point registers. Set, if the 266169689Skan respective register has to be saved. Starting with reg 16 (f0) 267169689Skan at the rightmost bit. 268169689Skan Bit 15 - 8 7 6 5 4 3 2 1 0 269169689Skan fpr 15 - 8 7 5 3 1 6 4 2 0 270169689Skan reg 31 - 24 23 22 21 20 19 18 17 16 */ 271169689Skan unsigned int fpr_bitmap; 272169689Skan 273169689Skan /* Number of floating point registers f8-f15 which must be saved. */ 274169689Skan int high_fprs; 275169689Skan 276169689Skan /* Set if return address needs to be saved. 277169689Skan This flag is set by s390_return_addr_rtx if it could not use 278169689Skan the initial value of r14 and therefore depends on r14 saved 279169689Skan to the stack. */ 280169689Skan bool save_return_addr_p; 281169689Skan 282117395Skan /* Size of stack frame. */ 283107590Sobrien HOST_WIDE_INT frame_size; 284169689Skan}; 285117395Skan 286169689Skan/* Define the structure for the machine field in struct function. */ 287169689Skan 288169689Skanstruct machine_function GTY(()) 289169689Skan{ 290169689Skan struct s390_frame_layout frame_layout; 291169689Skan 292169689Skan /* Literal pool base register. */ 293169689Skan rtx base_reg; 294169689Skan 295169689Skan /* True if we may need to perform branch splitting. */ 296169689Skan bool split_branches_pending_p; 297169689Skan 298169689Skan /* True during final stage of literal pool processing. */ 299169689Skan bool decomposed_literal_pool_addresses_ok_p; 300169689Skan 301117395Skan /* Some local-dynamic TLS symbol name. */ 302117395Skan const char *some_ld_name; 303169689Skan 304169689Skan bool has_landing_pad_p; 305107590Sobrien}; 306107590Sobrien 307169689Skan/* Few accessor macros for struct cfun->machine->s390_frame_layout. */ 308132718Skan 309169689Skan#define cfun_frame_layout (cfun->machine->frame_layout) 310169689Skan#define cfun_save_high_fprs_p (!!cfun_frame_layout.high_fprs) 311169689Skan#define cfun_gprs_save_area_size ((cfun_frame_layout.last_save_gpr_slot - \ 312169689Skan cfun_frame_layout.first_save_gpr_slot + 1) * UNITS_PER_WORD) 313169689Skan#define cfun_set_fpr_bit(BITNUM) (cfun->machine->frame_layout.fpr_bitmap |= \ 314169689Skan (1 << (BITNUM))) 315169689Skan#define cfun_fpr_bit_p(BITNUM) (!!(cfun->machine->frame_layout.fpr_bitmap & \ 316169689Skan (1 << (BITNUM)))) 317132718Skan 318169689Skan/* Number of GPRs and FPRs used for argument passing. */ 319169689Skan#define GP_ARG_NUM_REG 5 320169689Skan#define FP_ARG_NUM_REG (TARGET_64BIT? 4 : 2) 321169689Skan 322169689Skan/* A couple of shortcuts. */ 323169689Skan#define CONST_OK_FOR_J(x) \ 324169689Skan CONST_OK_FOR_CONSTRAINT_P((x), 'J', "J") 325169689Skan#define CONST_OK_FOR_K(x) \ 326169689Skan CONST_OK_FOR_CONSTRAINT_P((x), 'K', "K") 327169689Skan#define CONST_OK_FOR_Os(x) \ 328169689Skan CONST_OK_FOR_CONSTRAINT_P((x), 'O', "Os") 329169689Skan#define CONST_OK_FOR_Op(x) \ 330169689Skan CONST_OK_FOR_CONSTRAINT_P((x), 'O', "Op") 331169689Skan#define CONST_OK_FOR_On(x) \ 332169689Skan CONST_OK_FOR_CONSTRAINT_P((x), 'O', "On") 333169689Skan 334169689Skan#define REGNO_PAIR_OK(REGNO, MODE) \ 335169689Skan (HARD_REGNO_NREGS ((REGNO), (MODE)) == 1 || !((REGNO) & 1)) 336169689Skan 337169689Skan/* Return true if the back end supports mode MODE. */ 338169689Skanstatic bool 339169689Skans390_scalar_mode_supported_p (enum machine_mode mode) 340169689Skan{ 341169689Skan if (DECIMAL_FLOAT_MODE_P (mode)) 342169689Skan return true; 343169689Skan else 344169689Skan return default_scalar_mode_supported_p (mode); 345169689Skan} 346169689Skan 347169689Skan/* Set the has_landing_pad_p flag in struct machine_function to VALUE. */ 348169689Skan 349169689Skanvoid 350169689Skans390_set_has_landing_pad_p (bool value) 351169689Skan{ 352169689Skan cfun->machine->has_landing_pad_p = value; 353169689Skan} 354169689Skan 355169689Skan/* If two condition code modes are compatible, return a condition code 356169689Skan mode which is compatible with both. Otherwise, return 357169689Skan VOIDmode. */ 358169689Skan 359169689Skanstatic enum machine_mode 360169689Skans390_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2) 361169689Skan{ 362169689Skan if (m1 == m2) 363169689Skan return m1; 364169689Skan 365169689Skan switch (m1) 366169689Skan { 367169689Skan case CCZmode: 368169689Skan if (m2 == CCUmode || m2 == CCTmode || m2 == CCZ1mode 369169689Skan || m2 == CCSmode || m2 == CCSRmode || m2 == CCURmode) 370169689Skan return m2; 371169689Skan return VOIDmode; 372169689Skan 373169689Skan case CCSmode: 374169689Skan case CCUmode: 375169689Skan case CCTmode: 376169689Skan case CCSRmode: 377169689Skan case CCURmode: 378169689Skan case CCZ1mode: 379169689Skan if (m2 == CCZmode) 380169689Skan return m1; 381169689Skan 382169689Skan return VOIDmode; 383169689Skan 384169689Skan default: 385169689Skan return VOIDmode; 386169689Skan } 387169689Skan return VOIDmode; 388169689Skan} 389169689Skan 390107590Sobrien/* Return true if SET either doesn't set the CC register, or else 391132718Skan the source and destination have matching CC modes and that 392107590Sobrien CC mode is at least as constrained as REQ_MODE. */ 393132718Skan 394169689Skanstatic bool 395132718Skans390_match_ccmode_set (rtx set, enum machine_mode req_mode) 396107590Sobrien{ 397107590Sobrien enum machine_mode set_mode; 398107590Sobrien 399169689Skan gcc_assert (GET_CODE (set) == SET); 400107590Sobrien 401107590Sobrien if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set)))) 402107590Sobrien return 1; 403107590Sobrien 404107590Sobrien set_mode = GET_MODE (SET_DEST (set)); 405107590Sobrien switch (set_mode) 406107590Sobrien { 407107590Sobrien case CCSmode: 408117395Skan case CCSRmode: 409107590Sobrien case CCUmode: 410117395Skan case CCURmode: 411107590Sobrien case CCLmode: 412117395Skan case CCL1mode: 413117395Skan case CCL2mode: 414169689Skan case CCL3mode: 415117395Skan case CCT1mode: 416117395Skan case CCT2mode: 417117395Skan case CCT3mode: 418117395Skan if (req_mode != set_mode) 419107590Sobrien return 0; 420107590Sobrien break; 421117395Skan 422107590Sobrien case CCZmode: 423117395Skan if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode 424117395Skan && req_mode != CCSRmode && req_mode != CCURmode) 425107590Sobrien return 0; 426107590Sobrien break; 427117395Skan 428117395Skan case CCAPmode: 429117395Skan case CCANmode: 430117395Skan if (req_mode != CCAmode) 431117395Skan return 0; 432117395Skan break; 433132718Skan 434107590Sobrien default: 435169689Skan gcc_unreachable (); 436107590Sobrien } 437132718Skan 438107590Sobrien return (GET_MODE (SET_SRC (set)) == set_mode); 439107590Sobrien} 440107590Sobrien 441132718Skan/* Return true if every SET in INSN that sets the CC register 442132718Skan has source and destination with matching CC modes and that 443132718Skan CC mode is at least as constrained as REQ_MODE. 444117395Skan If REQ_MODE is VOIDmode, always return false. */ 445132718Skan 446169689Skanbool 447132718Skans390_match_ccmode (rtx insn, enum machine_mode req_mode) 448107590Sobrien{ 449107590Sobrien int i; 450107590Sobrien 451117395Skan /* s390_tm_ccmode returns VOIDmode to indicate failure. */ 452117395Skan if (req_mode == VOIDmode) 453169689Skan return false; 454117395Skan 455107590Sobrien if (GET_CODE (PATTERN (insn)) == SET) 456107590Sobrien return s390_match_ccmode_set (PATTERN (insn), req_mode); 457107590Sobrien 458107590Sobrien if (GET_CODE (PATTERN (insn)) == PARALLEL) 459107590Sobrien for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) 460107590Sobrien { 461107590Sobrien rtx set = XVECEXP (PATTERN (insn), 0, i); 462107590Sobrien if (GET_CODE (set) == SET) 463107590Sobrien if (!s390_match_ccmode_set (set, req_mode)) 464169689Skan return false; 465107590Sobrien } 466107590Sobrien 467169689Skan return true; 468107590Sobrien} 469107590Sobrien 470132718Skan/* If a test-under-mask instruction can be used to implement 471117395Skan (compare (and ... OP1) OP2), return the CC mode required 472132718Skan to do that. Otherwise, return VOIDmode. 473117395Skan MIXED is true if the instruction can distinguish between 474117395Skan CC1 and CC2 for mixed selected bits (TMxx), it is false 475117395Skan if the instruction cannot (TM). */ 476117395Skan 477117395Skanenum machine_mode 478169689Skans390_tm_ccmode (rtx op1, rtx op2, bool mixed) 479117395Skan{ 480117395Skan int bit0, bit1; 481117395Skan 482117395Skan /* ??? Fixme: should work on CONST_DOUBLE as well. */ 483117395Skan if (GET_CODE (op1) != CONST_INT || GET_CODE (op2) != CONST_INT) 484117395Skan return VOIDmode; 485117395Skan 486169689Skan /* Selected bits all zero: CC0. 487169689Skan e.g.: int a; if ((a & (16 + 128)) == 0) */ 488117395Skan if (INTVAL (op2) == 0) 489117395Skan return CCTmode; 490117395Skan 491169689Skan /* Selected bits all one: CC3. 492169689Skan e.g.: int a; if ((a & (16 + 128)) == 16 + 128) */ 493117395Skan if (INTVAL (op2) == INTVAL (op1)) 494117395Skan return CCT3mode; 495117395Skan 496169689Skan /* Exactly two bits selected, mixed zeroes and ones: CC1 or CC2. e.g.: 497169689Skan int a; 498169689Skan if ((a & (16 + 128)) == 16) -> CCT1 499169689Skan if ((a & (16 + 128)) == 128) -> CCT2 */ 500117395Skan if (mixed) 501117395Skan { 502117395Skan bit1 = exact_log2 (INTVAL (op2)); 503117395Skan bit0 = exact_log2 (INTVAL (op1) ^ INTVAL (op2)); 504117395Skan if (bit0 != -1 && bit1 != -1) 505117395Skan return bit0 > bit1 ? CCT1mode : CCT2mode; 506117395Skan } 507117395Skan 508117395Skan return VOIDmode; 509117395Skan} 510117395Skan 511132718Skan/* Given a comparison code OP (EQ, NE, etc.) and the operands 512132718Skan OP0 and OP1 of a COMPARE, return the mode to be used for the 513107590Sobrien comparison. */ 514107590Sobrien 515107590Sobrienenum machine_mode 516132718Skans390_select_ccmode (enum rtx_code code, rtx op0, rtx op1) 517107590Sobrien{ 518107590Sobrien switch (code) 519107590Sobrien { 520107590Sobrien case EQ: 521107590Sobrien case NE: 522169689Skan if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS) 523169689Skan && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) 524169689Skan return CCAPmode; 525117395Skan if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT 526169689Skan && CONST_OK_FOR_K (INTVAL (XEXP (op0, 1)))) 527117395Skan return CCAPmode; 528132718Skan if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS 529132718Skan || GET_CODE (op1) == NEG) 530132718Skan && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) 531107590Sobrien return CCLmode; 532107590Sobrien 533117395Skan if (GET_CODE (op0) == AND) 534117395Skan { 535117395Skan /* Check whether we can potentially do it via TM. */ 536117395Skan enum machine_mode ccmode; 537117395Skan ccmode = s390_tm_ccmode (XEXP (op0, 1), op1, 1); 538117395Skan if (ccmode != VOIDmode) 539117395Skan { 540117395Skan /* Relax CCTmode to CCZmode to allow fall-back to AND 541117395Skan if that turns out to be beneficial. */ 542117395Skan return ccmode == CCTmode ? CCZmode : ccmode; 543117395Skan } 544117395Skan } 545117395Skan 546132718Skan if (register_operand (op0, HImode) 547117395Skan && GET_CODE (op1) == CONST_INT 548117395Skan && (INTVAL (op1) == -1 || INTVAL (op1) == 65535)) 549117395Skan return CCT3mode; 550132718Skan if (register_operand (op0, QImode) 551117395Skan && GET_CODE (op1) == CONST_INT 552117395Skan && (INTVAL (op1) == -1 || INTVAL (op1) == 255)) 553117395Skan return CCT3mode; 554117395Skan 555107590Sobrien return CCZmode; 556107590Sobrien 557107590Sobrien case LE: 558107590Sobrien case LT: 559107590Sobrien case GE: 560107590Sobrien case GT: 561169689Skan /* The only overflow condition of NEG and ABS happens when 562169689Skan -INT_MAX is used as parameter, which stays negative. So 563169689Skan we have an overflow from a positive value to a negative. 564169689Skan Using CCAP mode the resulting cc can be used for comparisons. */ 565169689Skan if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS) 566169689Skan && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) 567169689Skan return CCAPmode; 568169689Skan 569169689Skan /* If constants are involved in an add instruction it is possible to use 570169689Skan the resulting cc for comparisons with zero. Knowing the sign of the 571169689Skan constant the overflow behavior gets predictable. e.g.: 572169689Skan int a, b; if ((b = a + c) > 0) 573169689Skan with c as a constant value: c < 0 -> CCAN and c >= 0 -> CCAP */ 574169689Skan if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT 575169689Skan && CONST_OK_FOR_K (INTVAL (XEXP (op0, 1)))) 576169689Skan { 577169689Skan if (INTVAL (XEXP((op0), 1)) < 0) 578169689Skan return CCANmode; 579169689Skan else 580169689Skan return CCAPmode; 581169689Skan } 582169689Skan /* Fall through. */ 583107590Sobrien case UNORDERED: 584107590Sobrien case ORDERED: 585107590Sobrien case UNEQ: 586107590Sobrien case UNLE: 587107590Sobrien case UNLT: 588107590Sobrien case UNGE: 589107590Sobrien case UNGT: 590107590Sobrien case LTGT: 591117395Skan if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND) 592117395Skan && GET_CODE (op1) != CONST_INT) 593117395Skan return CCSRmode; 594107590Sobrien return CCSmode; 595107590Sobrien 596107590Sobrien case LTU: 597107590Sobrien case GEU: 598132718Skan if (GET_CODE (op0) == PLUS 599132718Skan && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) 600117395Skan return CCL1mode; 601117395Skan 602117395Skan if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND) 603117395Skan && GET_CODE (op1) != CONST_INT) 604117395Skan return CCURmode; 605117395Skan return CCUmode; 606117395Skan 607117395Skan case LEU: 608107590Sobrien case GTU: 609132718Skan if (GET_CODE (op0) == MINUS 610132718Skan && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) 611117395Skan return CCL2mode; 612117395Skan 613117395Skan if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND) 614117395Skan && GET_CODE (op1) != CONST_INT) 615117395Skan return CCURmode; 616107590Sobrien return CCUmode; 617107590Sobrien 618107590Sobrien default: 619169689Skan gcc_unreachable (); 620107590Sobrien } 621107590Sobrien} 622107590Sobrien 623169689Skan/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one 624169689Skan that we can implement more efficiently. */ 625132718Skan 626169689Skanvoid 627169689Skans390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1) 628132718Skan{ 629169689Skan /* Convert ZERO_EXTRACT back to AND to enable TM patterns. */ 630169689Skan if ((*code == EQ || *code == NE) 631169689Skan && *op1 == const0_rtx 632169689Skan && GET_CODE (*op0) == ZERO_EXTRACT 633169689Skan && GET_CODE (XEXP (*op0, 1)) == CONST_INT 634169689Skan && GET_CODE (XEXP (*op0, 2)) == CONST_INT 635169689Skan && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0)))) 636169689Skan { 637169689Skan rtx inner = XEXP (*op0, 0); 638169689Skan HOST_WIDE_INT modesize = GET_MODE_BITSIZE (GET_MODE (inner)); 639169689Skan HOST_WIDE_INT len = INTVAL (XEXP (*op0, 1)); 640169689Skan HOST_WIDE_INT pos = INTVAL (XEXP (*op0, 2)); 641132718Skan 642169689Skan if (len > 0 && len < modesize 643169689Skan && pos >= 0 && pos + len <= modesize 644169689Skan && modesize <= HOST_BITS_PER_WIDE_INT) 645169689Skan { 646169689Skan unsigned HOST_WIDE_INT block; 647169689Skan block = ((unsigned HOST_WIDE_INT) 1 << len) - 1; 648169689Skan block <<= modesize - pos - len; 649132718Skan 650169689Skan *op0 = gen_rtx_AND (GET_MODE (inner), inner, 651169689Skan gen_int_mode (block, GET_MODE (inner))); 652169689Skan } 653169689Skan } 654132718Skan 655169689Skan /* Narrow AND of memory against immediate to enable TM. */ 656169689Skan if ((*code == EQ || *code == NE) 657169689Skan && *op1 == const0_rtx 658169689Skan && GET_CODE (*op0) == AND 659169689Skan && GET_CODE (XEXP (*op0, 1)) == CONST_INT 660169689Skan && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0)))) 661132718Skan { 662169689Skan rtx inner = XEXP (*op0, 0); 663169689Skan rtx mask = XEXP (*op0, 1); 664132718Skan 665169689Skan /* Ignore paradoxical SUBREGs if all extra bits are masked out. */ 666169689Skan if (GET_CODE (inner) == SUBREG 667169689Skan && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (inner))) 668169689Skan && (GET_MODE_SIZE (GET_MODE (inner)) 669169689Skan >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner)))) 670169689Skan && ((INTVAL (mask) 671169689Skan & GET_MODE_MASK (GET_MODE (inner)) 672169689Skan & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (inner)))) 673169689Skan == 0)) 674169689Skan inner = SUBREG_REG (inner); 675132718Skan 676169689Skan /* Do not change volatile MEMs. */ 677169689Skan if (MEM_P (inner) && !MEM_VOLATILE_P (inner)) 678169689Skan { 679169689Skan int part = s390_single_part (XEXP (*op0, 1), 680169689Skan GET_MODE (inner), QImode, 0); 681169689Skan if (part >= 0) 682169689Skan { 683169689Skan mask = gen_int_mode (s390_extract_part (mask, QImode, 0), QImode); 684169689Skan inner = adjust_address_nv (inner, QImode, part); 685169689Skan *op0 = gen_rtx_AND (QImode, inner, mask); 686169689Skan } 687169689Skan } 688169689Skan } 689132718Skan 690169689Skan /* Narrow comparisons against 0xffff to HImode if possible. */ 691169689Skan if ((*code == EQ || *code == NE) 692169689Skan && GET_CODE (*op1) == CONST_INT 693169689Skan && INTVAL (*op1) == 0xffff 694169689Skan && SCALAR_INT_MODE_P (GET_MODE (*op0)) 695169689Skan && (nonzero_bits (*op0, GET_MODE (*op0)) 696169689Skan & ~(unsigned HOST_WIDE_INT) 0xffff) == 0) 697169689Skan { 698169689Skan *op0 = gen_lowpart (HImode, *op0); 699169689Skan *op1 = constm1_rtx; 700169689Skan } 701132718Skan 702132718Skan 703169689Skan /* Remove redundant UNSPEC_CMPINT conversions if possible. */ 704169689Skan if (GET_CODE (*op0) == UNSPEC 705169689Skan && XINT (*op0, 1) == UNSPEC_CMPINT 706169689Skan && XVECLEN (*op0, 0) == 1 707169689Skan && GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode 708169689Skan && GET_CODE (XVECEXP (*op0, 0, 0)) == REG 709169689Skan && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM 710169689Skan && *op1 == const0_rtx) 711169689Skan { 712169689Skan enum rtx_code new_code = UNKNOWN; 713169689Skan switch (*code) 714169689Skan { 715169689Skan case EQ: new_code = EQ; break; 716169689Skan case NE: new_code = NE; break; 717169689Skan case LT: new_code = GTU; break; 718169689Skan case GT: new_code = LTU; break; 719169689Skan case LE: new_code = GEU; break; 720169689Skan case GE: new_code = LEU; break; 721169689Skan default: break; 722169689Skan } 723132718Skan 724169689Skan if (new_code != UNKNOWN) 725169689Skan { 726169689Skan *op0 = XVECEXP (*op0, 0, 0); 727169689Skan *code = new_code; 728169689Skan } 729132718Skan } 730169689Skan 731169689Skan /* Simplify cascaded EQ, NE with const0_rtx. */ 732169689Skan if ((*code == NE || *code == EQ) 733169689Skan && (GET_CODE (*op0) == EQ || GET_CODE (*op0) == NE) 734169689Skan && GET_MODE (*op0) == SImode 735169689Skan && GET_MODE (XEXP (*op0, 0)) == CCZ1mode 736169689Skan && REG_P (XEXP (*op0, 0)) 737169689Skan && XEXP (*op0, 1) == const0_rtx 738169689Skan && *op1 == const0_rtx) 739169689Skan { 740169689Skan if ((*code == EQ && GET_CODE (*op0) == NE) 741169689Skan || (*code == NE && GET_CODE (*op0) == EQ)) 742169689Skan *code = EQ; 743169689Skan else 744169689Skan *code = NE; 745169689Skan *op0 = XEXP (*op0, 0); 746169689Skan } 747169689Skan 748169689Skan /* Prefer register over memory as first operand. */ 749169689Skan if (MEM_P (*op0) && REG_P (*op1)) 750169689Skan { 751169689Skan rtx tem = *op0; *op0 = *op1; *op1 = tem; 752169689Skan *code = swap_condition (*code); 753169689Skan } 754132718Skan} 755132718Skan 756169689Skan/* Emit a compare instruction suitable to implement the comparison 757169689Skan OP0 CODE OP1. Return the correct condition RTL to be placed in 758169689Skan the IF_THEN_ELSE of the conditional branch testing the result. */ 759132718Skan 760169689Skanrtx 761169689Skans390_emit_compare (enum rtx_code code, rtx op0, rtx op1) 762132718Skan{ 763169689Skan enum machine_mode mode = s390_select_ccmode (code, op0, op1); 764169689Skan rtx ret = NULL_RTX; 765132718Skan 766169689Skan /* Do not output a redundant compare instruction if a compare_and_swap 767169689Skan pattern already computed the result and the machine modes are compatible. */ 768169689Skan if (s390_compare_emitted 769169689Skan && (s390_cc_modes_compatible (GET_MODE (s390_compare_emitted), mode) 770169689Skan == GET_MODE (s390_compare_emitted))) 771169689Skan ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx); 772169689Skan else 773169689Skan { 774169689Skan rtx cc = gen_rtx_REG (mode, CC_REGNUM); 775169689Skan 776169689Skan emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1))); 777169689Skan ret = gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx); 778169689Skan } 779169689Skan s390_compare_emitted = NULL_RTX; 780169689Skan return ret; 781169689Skan} 782132718Skan 783169689Skan/* Emit a SImode compare and swap instruction setting MEM to NEW if OLD 784169689Skan matches CMP. 785169689Skan Return the correct condition RTL to be placed in the IF_THEN_ELSE of the 786169689Skan conditional branch testing the result. */ 787132718Skan 788169689Skanstatic rtx 789169689Skans390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem, rtx cmp, rtx new) 790169689Skan{ 791169689Skan rtx ret; 792132718Skan 793169689Skan emit_insn (gen_sync_compare_and_swap_ccsi (old, mem, cmp, new)); 794169689Skan ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx); 795132718Skan 796169689Skan s390_compare_emitted = NULL_RTX; 797132718Skan 798169689Skan return ret; 799169689Skan} 800132718Skan 801169689Skan/* Emit a jump instruction to TARGET. If COND is NULL_RTX, emit an 802169689Skan unconditional jump, else a conditional jump under condition COND. */ 803132718Skan 804169689Skanvoid 805169689Skans390_emit_jump (rtx target, rtx cond) 806169689Skan{ 807169689Skan rtx insn; 808132718Skan 809169689Skan target = gen_rtx_LABEL_REF (VOIDmode, target); 810169689Skan if (cond) 811169689Skan target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx); 812169689Skan 813169689Skan insn = gen_rtx_SET (VOIDmode, pc_rtx, target); 814169689Skan emit_jump_insn (insn); 815132718Skan} 816132718Skan 817132718Skan/* Return branch condition mask to implement a branch 818169689Skan specified by CODE. Return -1 for invalid comparisons. */ 819107590Sobrien 820169689Skanint 821132718Skans390_branch_condition_mask (rtx code) 822132718Skan{ 823107590Sobrien const int CC0 = 1 << 3; 824107590Sobrien const int CC1 = 1 << 2; 825107590Sobrien const int CC2 = 1 << 1; 826107590Sobrien const int CC3 = 1 << 0; 827107590Sobrien 828169689Skan gcc_assert (GET_CODE (XEXP (code, 0)) == REG); 829169689Skan gcc_assert (REGNO (XEXP (code, 0)) == CC_REGNUM); 830169689Skan gcc_assert (XEXP (code, 1) == const0_rtx); 831107590Sobrien 832107590Sobrien switch (GET_MODE (XEXP (code, 0))) 833107590Sobrien { 834107590Sobrien case CCZmode: 835169689Skan case CCZ1mode: 836107590Sobrien switch (GET_CODE (code)) 837107590Sobrien { 838107590Sobrien case EQ: return CC0; 839107590Sobrien case NE: return CC1 | CC2 | CC3; 840169689Skan default: return -1; 841107590Sobrien } 842107590Sobrien break; 843107590Sobrien 844117395Skan case CCT1mode: 845117395Skan switch (GET_CODE (code)) 846117395Skan { 847117395Skan case EQ: return CC1; 848117395Skan case NE: return CC0 | CC2 | CC3; 849169689Skan default: return -1; 850117395Skan } 851117395Skan break; 852117395Skan 853117395Skan case CCT2mode: 854117395Skan switch (GET_CODE (code)) 855117395Skan { 856117395Skan case EQ: return CC2; 857117395Skan case NE: return CC0 | CC1 | CC3; 858169689Skan default: return -1; 859117395Skan } 860117395Skan break; 861117395Skan 862117395Skan case CCT3mode: 863117395Skan switch (GET_CODE (code)) 864117395Skan { 865117395Skan case EQ: return CC3; 866117395Skan case NE: return CC0 | CC1 | CC2; 867169689Skan default: return -1; 868117395Skan } 869117395Skan break; 870117395Skan 871107590Sobrien case CCLmode: 872107590Sobrien switch (GET_CODE (code)) 873107590Sobrien { 874107590Sobrien case EQ: return CC0 | CC2; 875107590Sobrien case NE: return CC1 | CC3; 876169689Skan default: return -1; 877107590Sobrien } 878107590Sobrien break; 879107590Sobrien 880117395Skan case CCL1mode: 881117395Skan switch (GET_CODE (code)) 882117395Skan { 883117395Skan case LTU: return CC2 | CC3; /* carry */ 884117395Skan case GEU: return CC0 | CC1; /* no carry */ 885169689Skan default: return -1; 886117395Skan } 887117395Skan break; 888117395Skan 889117395Skan case CCL2mode: 890117395Skan switch (GET_CODE (code)) 891117395Skan { 892117395Skan case GTU: return CC0 | CC1; /* borrow */ 893117395Skan case LEU: return CC2 | CC3; /* no borrow */ 894169689Skan default: return -1; 895117395Skan } 896117395Skan break; 897117395Skan 898169689Skan case CCL3mode: 899169689Skan switch (GET_CODE (code)) 900169689Skan { 901169689Skan case EQ: return CC0 | CC2; 902169689Skan case NE: return CC1 | CC3; 903169689Skan case LTU: return CC1; 904169689Skan case GTU: return CC3; 905169689Skan case LEU: return CC1 | CC2; 906169689Skan case GEU: return CC2 | CC3; 907169689Skan default: return -1; 908169689Skan } 909169689Skan 910107590Sobrien case CCUmode: 911107590Sobrien switch (GET_CODE (code)) 912107590Sobrien { 913107590Sobrien case EQ: return CC0; 914107590Sobrien case NE: return CC1 | CC2 | CC3; 915107590Sobrien case LTU: return CC1; 916107590Sobrien case GTU: return CC2; 917107590Sobrien case LEU: return CC0 | CC1; 918107590Sobrien case GEU: return CC0 | CC2; 919169689Skan default: return -1; 920107590Sobrien } 921107590Sobrien break; 922107590Sobrien 923117395Skan case CCURmode: 924117395Skan switch (GET_CODE (code)) 925117395Skan { 926117395Skan case EQ: return CC0; 927117395Skan case NE: return CC2 | CC1 | CC3; 928117395Skan case LTU: return CC2; 929117395Skan case GTU: return CC1; 930117395Skan case LEU: return CC0 | CC2; 931117395Skan case GEU: return CC0 | CC1; 932169689Skan default: return -1; 933117395Skan } 934117395Skan break; 935117395Skan 936117395Skan case CCAPmode: 937117395Skan switch (GET_CODE (code)) 938117395Skan { 939117395Skan case EQ: return CC0; 940117395Skan case NE: return CC1 | CC2 | CC3; 941117395Skan case LT: return CC1 | CC3; 942117395Skan case GT: return CC2; 943117395Skan case LE: return CC0 | CC1 | CC3; 944117395Skan case GE: return CC0 | CC2; 945169689Skan default: return -1; 946117395Skan } 947117395Skan break; 948117395Skan 949117395Skan case CCANmode: 950117395Skan switch (GET_CODE (code)) 951117395Skan { 952117395Skan case EQ: return CC0; 953117395Skan case NE: return CC1 | CC2 | CC3; 954117395Skan case LT: return CC1; 955117395Skan case GT: return CC2 | CC3; 956117395Skan case LE: return CC0 | CC1; 957117395Skan case GE: return CC0 | CC2 | CC3; 958169689Skan default: return -1; 959117395Skan } 960117395Skan break; 961117395Skan 962107590Sobrien case CCSmode: 963107590Sobrien switch (GET_CODE (code)) 964107590Sobrien { 965107590Sobrien case EQ: return CC0; 966107590Sobrien case NE: return CC1 | CC2 | CC3; 967107590Sobrien case LT: return CC1; 968107590Sobrien case GT: return CC2; 969107590Sobrien case LE: return CC0 | CC1; 970107590Sobrien case GE: return CC0 | CC2; 971107590Sobrien case UNORDERED: return CC3; 972107590Sobrien case ORDERED: return CC0 | CC1 | CC2; 973107590Sobrien case UNEQ: return CC0 | CC3; 974107590Sobrien case UNLT: return CC1 | CC3; 975107590Sobrien case UNGT: return CC2 | CC3; 976107590Sobrien case UNLE: return CC0 | CC1 | CC3; 977107590Sobrien case UNGE: return CC0 | CC2 | CC3; 978107590Sobrien case LTGT: return CC1 | CC2; 979169689Skan default: return -1; 980107590Sobrien } 981117395Skan break; 982107590Sobrien 983117395Skan case CCSRmode: 984117395Skan switch (GET_CODE (code)) 985117395Skan { 986117395Skan case EQ: return CC0; 987117395Skan case NE: return CC2 | CC1 | CC3; 988117395Skan case LT: return CC2; 989117395Skan case GT: return CC1; 990117395Skan case LE: return CC0 | CC2; 991117395Skan case GE: return CC0 | CC1; 992117395Skan case UNORDERED: return CC3; 993117395Skan case ORDERED: return CC0 | CC2 | CC1; 994117395Skan case UNEQ: return CC0 | CC3; 995117395Skan case UNLT: return CC2 | CC3; 996117395Skan case UNGT: return CC1 | CC3; 997117395Skan case UNLE: return CC0 | CC2 | CC3; 998117395Skan case UNGE: return CC0 | CC1 | CC3; 999117395Skan case LTGT: return CC2 | CC1; 1000169689Skan default: return -1; 1001117395Skan } 1002117395Skan break; 1003117395Skan 1004107590Sobrien default: 1005169689Skan return -1; 1006107590Sobrien } 1007107590Sobrien} 1008107590Sobrien 1009132718Skan/* If INV is false, return assembler mnemonic string to implement 1010132718Skan a branch specified by CODE. If INV is true, return mnemonic 1011107590Sobrien for the corresponding inverted branch. */ 1012107590Sobrien 1013107590Sobrienstatic const char * 1014132718Skans390_branch_condition_mnemonic (rtx code, int inv) 1015107590Sobrien{ 1016117395Skan static const char *const mnemonic[16] = 1017107590Sobrien { 1018107590Sobrien NULL, "o", "h", "nle", 1019107590Sobrien "l", "nhe", "lh", "ne", 1020107590Sobrien "e", "nlh", "he", "nl", 1021107590Sobrien "le", "nh", "no", NULL 1022107590Sobrien }; 1023107590Sobrien 1024107590Sobrien int mask = s390_branch_condition_mask (code); 1025169689Skan gcc_assert (mask >= 0); 1026107590Sobrien 1027107590Sobrien if (inv) 1028107590Sobrien mask ^= 15; 1029107590Sobrien 1030169689Skan gcc_assert (mask >= 1 && mask <= 14); 1031107590Sobrien 1032107590Sobrien return mnemonic[mask]; 1033107590Sobrien} 1034107590Sobrien 1035132718Skan/* Return the part of op which has a value different from def. 1036132718Skan The size of the part is determined by mode. 1037169689Skan Use this function only if you already know that op really 1038132718Skan contains such a part. */ 1039107590Sobrien 1040132718Skanunsigned HOST_WIDE_INT 1041132718Skans390_extract_part (rtx op, enum machine_mode mode, int def) 1042107590Sobrien{ 1043132718Skan unsigned HOST_WIDE_INT value = 0; 1044132718Skan int max_parts = HOST_BITS_PER_WIDE_INT / GET_MODE_BITSIZE (mode); 1045132718Skan int part_bits = GET_MODE_BITSIZE (mode); 1046169689Skan unsigned HOST_WIDE_INT part_mask 1047169689Skan = ((unsigned HOST_WIDE_INT)1 << part_bits) - 1; 1048132718Skan int i; 1049169689Skan 1050132718Skan for (i = 0; i < max_parts; i++) 1051107590Sobrien { 1052132718Skan if (i == 0) 1053132718Skan value = (unsigned HOST_WIDE_INT) INTVAL (op); 1054107590Sobrien else 1055132718Skan value >>= part_bits; 1056169689Skan 1057132718Skan if ((value & part_mask) != (def & part_mask)) 1058132718Skan return value & part_mask; 1059107590Sobrien } 1060169689Skan 1061169689Skan gcc_unreachable (); 1062107590Sobrien} 1063107590Sobrien 1064107590Sobrien/* If OP is an integer constant of mode MODE with exactly one 1065132718Skan part of mode PART_MODE unequal to DEF, return the number of that 1066132718Skan part. Otherwise, return -1. */ 1067107590Sobrien 1068107590Sobrienint 1069169689Skans390_single_part (rtx op, 1070169689Skan enum machine_mode mode, 1071132718Skan enum machine_mode part_mode, 1072132718Skan int def) 1073107590Sobrien{ 1074132718Skan unsigned HOST_WIDE_INT value = 0; 1075132718Skan int n_parts = GET_MODE_SIZE (mode) / GET_MODE_SIZE (part_mode); 1076169689Skan unsigned HOST_WIDE_INT part_mask 1077169689Skan = ((unsigned HOST_WIDE_INT)1 << GET_MODE_BITSIZE (part_mode)) - 1; 1078132718Skan int i, part = -1; 1079107590Sobrien 1080132718Skan if (GET_CODE (op) != CONST_INT) 1081132718Skan return -1; 1082169689Skan 1083132718Skan for (i = 0; i < n_parts; i++) 1084107590Sobrien { 1085132718Skan if (i == 0) 1086132718Skan value = (unsigned HOST_WIDE_INT) INTVAL (op); 1087107590Sobrien else 1088132718Skan value >>= GET_MODE_BITSIZE (part_mode); 1089169689Skan 1090132718Skan if ((value & part_mask) != (def & part_mask)) 1091132718Skan { 1092132718Skan if (part != -1) 1093132718Skan return -1; 1094132718Skan else 1095132718Skan part = i; 1096132718Skan } 1097107590Sobrien } 1098132718Skan return part == -1 ? -1 : n_parts - 1 - part; 1099107590Sobrien} 1100107590Sobrien 1101132718Skan/* Check whether we can (and want to) split a double-word 1102132718Skan move in mode MODE from SRC to DST into two single-word 1103117395Skan moves, moving the subword FIRST_SUBWORD first. */ 1104107590Sobrien 1105117395Skanbool 1106132718Skans390_split_ok_p (rtx dst, rtx src, enum machine_mode mode, int first_subword) 1107117395Skan{ 1108117395Skan /* Floating point registers cannot be split. */ 1109117395Skan if (FP_REG_P (src) || FP_REG_P (dst)) 1110117395Skan return false; 1111117395Skan 1112132718Skan /* We don't need to split if operands are directly accessible. */ 1113117395Skan if (s_operand (src, mode) || s_operand (dst, mode)) 1114117395Skan return false; 1115117395Skan 1116117395Skan /* Non-offsettable memory references cannot be split. */ 1117117395Skan if ((GET_CODE (src) == MEM && !offsettable_memref_p (src)) 1118117395Skan || (GET_CODE (dst) == MEM && !offsettable_memref_p (dst))) 1119117395Skan return false; 1120117395Skan 1121117395Skan /* Moving the first subword must not clobber a register 1122117395Skan needed to move the second subword. */ 1123117395Skan if (register_operand (dst, mode)) 1124117395Skan { 1125117395Skan rtx subreg = operand_subword (dst, first_subword, 0, mode); 1126117395Skan if (reg_overlap_mentioned_p (subreg, src)) 1127117395Skan return false; 1128117395Skan } 1129117395Skan 1130117395Skan return true; 1131117395Skan} 1132117395Skan 1133169689Skan/* Return true if it can be proven that [MEM1, MEM1 + SIZE] 1134169689Skan and [MEM2, MEM2 + SIZE] do overlap and false 1135169689Skan otherwise. */ 1136117395Skan 1137169689Skanbool 1138169689Skans390_overlap_p (rtx mem1, rtx mem2, HOST_WIDE_INT size) 1139169689Skan{ 1140169689Skan rtx addr1, addr2, addr_delta; 1141169689Skan HOST_WIDE_INT delta; 1142169689Skan 1143169689Skan if (GET_CODE (mem1) != MEM || GET_CODE (mem2) != MEM) 1144169689Skan return true; 1145169689Skan 1146169689Skan if (size == 0) 1147169689Skan return false; 1148169689Skan 1149169689Skan addr1 = XEXP (mem1, 0); 1150169689Skan addr2 = XEXP (mem2, 0); 1151169689Skan 1152169689Skan addr_delta = simplify_binary_operation (MINUS, Pmode, addr2, addr1); 1153169689Skan 1154169689Skan /* This overlapping check is used by peepholes merging memory block operations. 1155169689Skan Overlapping operations would otherwise be recognized by the S/390 hardware 1156169689Skan and would fall back to a slower implementation. Allowing overlapping 1157169689Skan operations would lead to slow code but not to wrong code. Therefore we are 1158169689Skan somewhat optimistic if we cannot prove that the memory blocks are 1159169689Skan overlapping. 1160169689Skan That's why we return false here although this may accept operations on 1161169689Skan overlapping memory areas. */ 1162169689Skan if (!addr_delta || GET_CODE (addr_delta) != CONST_INT) 1163169689Skan return false; 1164169689Skan 1165169689Skan delta = INTVAL (addr_delta); 1166169689Skan 1167169689Skan if (delta == 0 1168169689Skan || (delta > 0 && delta < size) 1169169689Skan || (delta < 0 && -delta < size)) 1170169689Skan return true; 1171169689Skan 1172169689Skan return false; 1173169689Skan} 1174169689Skan 1175169689Skan/* Check whether the address of memory reference MEM2 equals exactly 1176169689Skan the address of memory reference MEM1 plus DELTA. Return true if 1177169689Skan we can prove this to be the case, false otherwise. */ 1178169689Skan 1179169689Skanbool 1180169689Skans390_offset_p (rtx mem1, rtx mem2, rtx delta) 1181169689Skan{ 1182169689Skan rtx addr1, addr2, addr_delta; 1183169689Skan 1184169689Skan if (GET_CODE (mem1) != MEM || GET_CODE (mem2) != MEM) 1185169689Skan return false; 1186169689Skan 1187169689Skan addr1 = XEXP (mem1, 0); 1188169689Skan addr2 = XEXP (mem2, 0); 1189169689Skan 1190169689Skan addr_delta = simplify_binary_operation (MINUS, Pmode, addr2, addr1); 1191169689Skan if (!addr_delta || !rtx_equal_p (addr_delta, delta)) 1192169689Skan return false; 1193169689Skan 1194169689Skan return true; 1195169689Skan} 1196169689Skan 1197169689Skan/* Expand logical operator CODE in mode MODE with operands OPERANDS. */ 1198169689Skan 1199169689Skanvoid 1200169689Skans390_expand_logical_operator (enum rtx_code code, enum machine_mode mode, 1201169689Skan rtx *operands) 1202169689Skan{ 1203169689Skan enum machine_mode wmode = mode; 1204169689Skan rtx dst = operands[0]; 1205169689Skan rtx src1 = operands[1]; 1206169689Skan rtx src2 = operands[2]; 1207169689Skan rtx op, clob, tem; 1208169689Skan 1209169689Skan /* If we cannot handle the operation directly, use a temp register. */ 1210169689Skan if (!s390_logical_operator_ok_p (operands)) 1211169689Skan dst = gen_reg_rtx (mode); 1212169689Skan 1213169689Skan /* QImode and HImode patterns make sense only if we have a destination 1214169689Skan in memory. Otherwise perform the operation in SImode. */ 1215169689Skan if ((mode == QImode || mode == HImode) && GET_CODE (dst) != MEM) 1216169689Skan wmode = SImode; 1217169689Skan 1218169689Skan /* Widen operands if required. */ 1219169689Skan if (mode != wmode) 1220169689Skan { 1221169689Skan if (GET_CODE (dst) == SUBREG 1222169689Skan && (tem = simplify_subreg (wmode, dst, mode, 0)) != 0) 1223169689Skan dst = tem; 1224169689Skan else if (REG_P (dst)) 1225169689Skan dst = gen_rtx_SUBREG (wmode, dst, 0); 1226169689Skan else 1227169689Skan dst = gen_reg_rtx (wmode); 1228169689Skan 1229169689Skan if (GET_CODE (src1) == SUBREG 1230169689Skan && (tem = simplify_subreg (wmode, src1, mode, 0)) != 0) 1231169689Skan src1 = tem; 1232169689Skan else if (GET_MODE (src1) != VOIDmode) 1233169689Skan src1 = gen_rtx_SUBREG (wmode, force_reg (mode, src1), 0); 1234169689Skan 1235169689Skan if (GET_CODE (src2) == SUBREG 1236169689Skan && (tem = simplify_subreg (wmode, src2, mode, 0)) != 0) 1237169689Skan src2 = tem; 1238169689Skan else if (GET_MODE (src2) != VOIDmode) 1239169689Skan src2 = gen_rtx_SUBREG (wmode, force_reg (mode, src2), 0); 1240169689Skan } 1241169689Skan 1242169689Skan /* Emit the instruction. */ 1243169689Skan op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, wmode, src1, src2)); 1244169689Skan clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); 1245169689Skan emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob))); 1246169689Skan 1247169689Skan /* Fix up the destination if needed. */ 1248169689Skan if (dst != operands[0]) 1249169689Skan emit_move_insn (operands[0], gen_lowpart (mode, dst)); 1250169689Skan} 1251169689Skan 1252169689Skan/* Check whether OPERANDS are OK for a logical operation (AND, IOR, XOR). */ 1253169689Skan 1254169689Skanbool 1255169689Skans390_logical_operator_ok_p (rtx *operands) 1256169689Skan{ 1257169689Skan /* If the destination operand is in memory, it needs to coincide 1258169689Skan with one of the source operands. After reload, it has to be 1259169689Skan the first source operand. */ 1260169689Skan if (GET_CODE (operands[0]) == MEM) 1261169689Skan return rtx_equal_p (operands[0], operands[1]) 1262169689Skan || (!reload_completed && rtx_equal_p (operands[0], operands[2])); 1263169689Skan 1264169689Skan return true; 1265169689Skan} 1266169689Skan 1267169689Skan/* Narrow logical operation CODE of memory operand MEMOP with immediate 1268169689Skan operand IMMOP to switch from SS to SI type instructions. */ 1269169689Skan 1270169689Skanvoid 1271169689Skans390_narrow_logical_operator (enum rtx_code code, rtx *memop, rtx *immop) 1272169689Skan{ 1273169689Skan int def = code == AND ? -1 : 0; 1274169689Skan HOST_WIDE_INT mask; 1275169689Skan int part; 1276169689Skan 1277169689Skan gcc_assert (GET_CODE (*memop) == MEM); 1278169689Skan gcc_assert (!MEM_VOLATILE_P (*memop)); 1279169689Skan 1280169689Skan mask = s390_extract_part (*immop, QImode, def); 1281169689Skan part = s390_single_part (*immop, GET_MODE (*memop), QImode, def); 1282169689Skan gcc_assert (part >= 0); 1283169689Skan 1284169689Skan *memop = adjust_address (*memop, QImode, part); 1285169689Skan *immop = gen_int_mode (mask, QImode); 1286169689Skan} 1287169689Skan 1288169689Skan 1289169689Skan/* How to allocate a 'struct machine_function'. */ 1290169689Skan 1291169689Skanstatic struct machine_function * 1292169689Skans390_init_machine_status (void) 1293169689Skan{ 1294169689Skan return ggc_alloc_cleared (sizeof (struct machine_function)); 1295169689Skan} 1296169689Skan 1297132718Skan/* Change optimizations to be performed, depending on the 1298107590Sobrien optimization level. 1299107590Sobrien 1300107590Sobrien LEVEL is the optimization level specified; 2 if `-O2' is 1301107590Sobrien specified, 1 if `-O' is specified, and 0 if neither is specified. 1302107590Sobrien 1303117395Skan SIZE is nonzero if `-Os' is specified and zero otherwise. */ 1304107590Sobrien 1305107590Sobrienvoid 1306132718Skanoptimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED) 1307107590Sobrien{ 1308117395Skan /* ??? There are apparently still problems with -fcaller-saves. */ 1309117395Skan flag_caller_saves = 0; 1310117395Skan 1311117395Skan /* By default, always emit DWARF-2 unwind info. This allows debugging 1312117395Skan without maintaining a stack frame back-chain. */ 1313117395Skan flag_asynchronous_unwind_tables = 1; 1314169689Skan 1315169689Skan /* Use MVCLE instructions to decrease code size if requested. */ 1316169689Skan if (size != 0) 1317169689Skan target_flags |= MASK_MVCLE; 1318107590Sobrien} 1319107590Sobrien 1320169689Skan/* Return true if ARG is the name of a processor. Set *TYPE and *FLAGS 1321169689Skan to the associated processor_type and processor_flags if so. */ 1322169689Skan 1323169689Skanstatic bool 1324169689Skans390_handle_arch_option (const char *arg, 1325169689Skan enum processor_type *type, 1326169689Skan enum processor_flags *flags) 1327107590Sobrien{ 1328132718Skan static struct pta 1329132718Skan { 1330132718Skan const char *const name; /* processor name or nickname. */ 1331132718Skan const enum processor_type processor; 1332132718Skan const enum processor_flags flags; 1333132718Skan } 1334132718Skan const processor_alias_table[] = 1335132718Skan { 1336132718Skan {"g5", PROCESSOR_9672_G5, PF_IEEE_FLOAT}, 1337132718Skan {"g6", PROCESSOR_9672_G6, PF_IEEE_FLOAT}, 1338132718Skan {"z900", PROCESSOR_2064_Z900, PF_IEEE_FLOAT | PF_ZARCH}, 1339132718Skan {"z990", PROCESSOR_2084_Z990, PF_IEEE_FLOAT | PF_ZARCH 1340132718Skan | PF_LONG_DISPLACEMENT}, 1341169689Skan {"z9-109", PROCESSOR_2094_Z9_109, PF_IEEE_FLOAT | PF_ZARCH 1342169689Skan | PF_LONG_DISPLACEMENT | PF_EXTIMM}, 1343132718Skan }; 1344169689Skan size_t i; 1345132718Skan 1346169689Skan for (i = 0; i < ARRAY_SIZE (processor_alias_table); i++) 1347169689Skan if (strcmp (arg, processor_alias_table[i].name) == 0) 1348169689Skan { 1349169689Skan *type = processor_alias_table[i].processor; 1350169689Skan *flags = processor_alias_table[i].flags; 1351169689Skan return true; 1352169689Skan } 1353169689Skan return false; 1354169689Skan} 1355132718Skan 1356169689Skan/* Implement TARGET_HANDLE_OPTION. */ 1357117395Skan 1358169689Skanstatic bool 1359169689Skans390_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) 1360169689Skan{ 1361169689Skan switch (code) 1362169689Skan { 1363169689Skan case OPT_march_: 1364169689Skan return s390_handle_arch_option (arg, &s390_arch, &s390_arch_flags); 1365169689Skan 1366169689Skan case OPT_mstack_guard_: 1367169689Skan if (sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_stack_guard) != 1) 1368169689Skan return false; 1369169689Skan if (exact_log2 (s390_stack_guard) == -1) 1370169689Skan error ("stack guard value must be an exact power of 2"); 1371169689Skan return true; 1372169689Skan 1373169689Skan case OPT_mstack_size_: 1374169689Skan if (sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_stack_size) != 1) 1375169689Skan return false; 1376169689Skan if (exact_log2 (s390_stack_size) == -1) 1377169689Skan error ("stack size must be an exact power of 2"); 1378169689Skan return true; 1379169689Skan 1380169689Skan case OPT_mtune_: 1381169689Skan return s390_handle_arch_option (arg, &s390_tune, &s390_tune_flags); 1382169689Skan 1383169689Skan case OPT_mwarn_framesize_: 1384169689Skan return sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_warn_framesize) == 1; 1385169689Skan 1386169689Skan default: 1387169689Skan return true; 1388169689Skan } 1389169689Skan} 1390169689Skan 1391169689Skanvoid 1392169689Skanoverride_options (void) 1393169689Skan{ 1394117395Skan /* Set up function hooks. */ 1395117395Skan init_machine_status = s390_init_machine_status; 1396132718Skan 1397132718Skan /* Architecture mode defaults according to ABI. */ 1398132718Skan if (!(target_flags_explicit & MASK_ZARCH)) 1399132718Skan { 1400132718Skan if (TARGET_64BIT) 1401132718Skan target_flags |= MASK_ZARCH; 1402132718Skan else 1403132718Skan target_flags &= ~MASK_ZARCH; 1404132718Skan } 1405132718Skan 1406132718Skan /* Determine processor architectural level. */ 1407132718Skan if (!s390_arch_string) 1408169689Skan { 1409169689Skan s390_arch_string = TARGET_ZARCH? "z900" : "g5"; 1410169689Skan s390_handle_arch_option (s390_arch_string, &s390_arch, &s390_arch_flags); 1411169689Skan } 1412132718Skan 1413132718Skan /* Determine processor to tune for. */ 1414169689Skan if (s390_tune == PROCESSOR_max) 1415132718Skan { 1416132718Skan s390_tune = s390_arch; 1417132718Skan s390_tune_flags = s390_arch_flags; 1418132718Skan } 1419169689Skan 1420169689Skan /* Sanity checks. */ 1421169689Skan if (TARGET_ZARCH && !(s390_arch_flags & PF_ZARCH)) 1422169689Skan error ("z/Architecture mode not supported on %s", s390_arch_string); 1423169689Skan if (TARGET_64BIT && !TARGET_ZARCH) 1424169689Skan error ("64-bit ABI not supported in ESA/390 mode"); 1425169689Skan 1426169689Skan /* Set processor cost function. */ 1427169689Skan if (s390_tune == PROCESSOR_2094_Z9_109) 1428169689Skan s390_cost = &z9_109_cost; 1429169689Skan else if (s390_tune == PROCESSOR_2084_Z990) 1430169689Skan s390_cost = &z990_cost; 1431132718Skan else 1432169689Skan s390_cost = &z900_cost; 1433169689Skan 1434169689Skan if (TARGET_BACKCHAIN && TARGET_PACKED_STACK && TARGET_HARD_FLOAT) 1435169689Skan error ("-mbackchain -mpacked-stack -mhard-float are not supported " 1436169689Skan "in combination"); 1437169689Skan 1438169689Skan if (s390_stack_size) 1439132718Skan { 1440169689Skan if (!s390_stack_guard) 1441169689Skan error ("-mstack-size implies use of -mstack-guard"); 1442169689Skan else if (s390_stack_guard >= s390_stack_size) 1443169689Skan error ("stack size must be greater than the stack guard value"); 1444169689Skan else if (s390_stack_size > 1 << 16) 1445169689Skan error ("stack size must not be greater than 64k"); 1446132718Skan } 1447169689Skan else if (s390_stack_guard) 1448169689Skan error ("-mstack-guard implies use of -mstack-size"); 1449132718Skan 1450169689Skan#ifdef TARGET_DEFAULT_LONG_DOUBLE_128 1451169689Skan if (!(target_flags_explicit & MASK_LONG_DOUBLE_128)) 1452169689Skan target_flags |= MASK_LONG_DOUBLE_128; 1453169689Skan#endif 1454107590Sobrien} 1455107590Sobrien 1456107590Sobrien/* Map for smallest class containing reg regno. */ 1457107590Sobrien 1458117395Skanconst enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = 1459107590Sobrien{ GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, 1460107590Sobrien ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, 1461107590Sobrien ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, 1462107590Sobrien ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, 1463107590Sobrien FP_REGS, FP_REGS, FP_REGS, FP_REGS, 1464107590Sobrien FP_REGS, FP_REGS, FP_REGS, FP_REGS, 1465107590Sobrien FP_REGS, FP_REGS, FP_REGS, FP_REGS, 1466107590Sobrien FP_REGS, FP_REGS, FP_REGS, FP_REGS, 1467169689Skan ADDR_REGS, CC_REGS, ADDR_REGS, ADDR_REGS, 1468169689Skan ACCESS_REGS, ACCESS_REGS 1469107590Sobrien}; 1470107590Sobrien 1471132718Skan/* Return attribute type of insn. */ 1472107590Sobrien 1473132718Skanstatic enum attr_type 1474132718Skans390_safe_attr_type (rtx insn) 1475132718Skan{ 1476132718Skan if (recog_memoized (insn) >= 0) 1477132718Skan return get_attr_type (insn); 1478132718Skan else 1479132718Skan return TYPE_NONE; 1480132718Skan} 1481132718Skan 1482169689Skan/* Return true if DISP is a valid short displacement. */ 1483132718Skan 1484169689Skanstatic bool 1485169689Skans390_short_displacement (rtx disp) 1486107590Sobrien{ 1487169689Skan /* No displacement is OK. */ 1488169689Skan if (!disp) 1489169689Skan return true; 1490107590Sobrien 1491169689Skan /* Integer displacement in range. */ 1492169689Skan if (GET_CODE (disp) == CONST_INT) 1493169689Skan return INTVAL (disp) >= 0 && INTVAL (disp) < 4096; 1494107590Sobrien 1495169689Skan /* GOT offset is not OK, the GOT can be large. */ 1496169689Skan if (GET_CODE (disp) == CONST 1497169689Skan && GET_CODE (XEXP (disp, 0)) == UNSPEC 1498169689Skan && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT 1499169689Skan || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF)) 1500169689Skan return false; 1501169689Skan 1502169689Skan /* All other symbolic constants are literal pool references, 1503169689Skan which are OK as the literal pool must be small. */ 1504169689Skan if (GET_CODE (disp) == CONST) 1505169689Skan return true; 1506169689Skan 1507169689Skan return false; 1508107590Sobrien} 1509107590Sobrien 1510169689Skan/* Decompose a RTL expression ADDR for a memory address into 1511169689Skan its components, returned in OUT. 1512107590Sobrien 1513169689Skan Returns false if ADDR is not a valid memory address, true 1514169689Skan otherwise. If OUT is NULL, don't return the components, 1515169689Skan but check for validity only. 1516169689Skan 1517169689Skan Note: Only addresses in canonical form are recognized. 1518169689Skan LEGITIMIZE_ADDRESS should convert non-canonical forms to the 1519169689Skan canonical form so that they will be recognized. */ 1520169689Skan 1521107590Sobrienstatic int 1522169689Skans390_decompose_address (rtx addr, struct s390_address *out) 1523107590Sobrien{ 1524169689Skan HOST_WIDE_INT offset = 0; 1525169689Skan rtx base = NULL_RTX; 1526169689Skan rtx indx = NULL_RTX; 1527169689Skan rtx disp = NULL_RTX; 1528169689Skan rtx orig_disp; 1529169689Skan bool pointer = false; 1530169689Skan bool base_ptr = false; 1531169689Skan bool indx_ptr = false; 1532169689Skan bool literal_pool = false; 1533169689Skan 1534169689Skan /* We may need to substitute the literal pool base register into the address 1535169689Skan below. However, at this point we do not know which register is going to 1536169689Skan be used as base, so we substitute the arg pointer register. This is going 1537169689Skan to be treated as holding a pointer below -- it shouldn't be used for any 1538169689Skan other purpose. */ 1539169689Skan rtx fake_pool_base = gen_rtx_REG (Pmode, ARG_POINTER_REGNUM); 1540169689Skan 1541169689Skan /* Decompose address into base + index + displacement. */ 1542169689Skan 1543169689Skan if (GET_CODE (addr) == REG || GET_CODE (addr) == UNSPEC) 1544169689Skan base = addr; 1545169689Skan 1546169689Skan else if (GET_CODE (addr) == PLUS) 1547169689Skan { 1548169689Skan rtx op0 = XEXP (addr, 0); 1549169689Skan rtx op1 = XEXP (addr, 1); 1550169689Skan enum rtx_code code0 = GET_CODE (op0); 1551169689Skan enum rtx_code code1 = GET_CODE (op1); 1552169689Skan 1553169689Skan if (code0 == REG || code0 == UNSPEC) 1554169689Skan { 1555169689Skan if (code1 == REG || code1 == UNSPEC) 1556169689Skan { 1557169689Skan indx = op0; /* index + base */ 1558169689Skan base = op1; 1559169689Skan } 1560169689Skan 1561169689Skan else 1562169689Skan { 1563169689Skan base = op0; /* base + displacement */ 1564169689Skan disp = op1; 1565169689Skan } 1566169689Skan } 1567169689Skan 1568169689Skan else if (code0 == PLUS) 1569169689Skan { 1570169689Skan indx = XEXP (op0, 0); /* index + base + disp */ 1571169689Skan base = XEXP (op0, 1); 1572169689Skan disp = op1; 1573169689Skan } 1574169689Skan 1575169689Skan else 1576169689Skan { 1577169689Skan return false; 1578169689Skan } 1579169689Skan } 1580169689Skan 1581107590Sobrien else 1582169689Skan disp = addr; /* displacement */ 1583107590Sobrien 1584169689Skan /* Extract integer part of displacement. */ 1585169689Skan orig_disp = disp; 1586169689Skan if (disp) 1587169689Skan { 1588169689Skan if (GET_CODE (disp) == CONST_INT) 1589169689Skan { 1590169689Skan offset = INTVAL (disp); 1591169689Skan disp = NULL_RTX; 1592169689Skan } 1593169689Skan else if (GET_CODE (disp) == CONST 1594169689Skan && GET_CODE (XEXP (disp, 0)) == PLUS 1595169689Skan && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT) 1596169689Skan { 1597169689Skan offset = INTVAL (XEXP (XEXP (disp, 0), 1)); 1598169689Skan disp = XEXP (XEXP (disp, 0), 0); 1599169689Skan } 1600169689Skan } 1601107590Sobrien 1602169689Skan /* Strip off CONST here to avoid special case tests later. */ 1603169689Skan if (disp && GET_CODE (disp) == CONST) 1604169689Skan disp = XEXP (disp, 0); 1605107590Sobrien 1606169689Skan /* We can convert literal pool addresses to 1607169689Skan displacements by basing them off the base register. */ 1608169689Skan if (disp && GET_CODE (disp) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (disp)) 1609169689Skan { 1610169689Skan /* Either base or index must be free to hold the base register. */ 1611169689Skan if (!base) 1612169689Skan base = fake_pool_base, literal_pool = true; 1613169689Skan else if (!indx) 1614169689Skan indx = fake_pool_base, literal_pool = true; 1615169689Skan else 1616169689Skan return false; 1617107590Sobrien 1618169689Skan /* Mark up the displacement. */ 1619169689Skan disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp), 1620169689Skan UNSPEC_LTREL_OFFSET); 1621169689Skan } 1622107590Sobrien 1623169689Skan /* Validate base register. */ 1624169689Skan if (base) 1625107590Sobrien { 1626169689Skan if (GET_CODE (base) == UNSPEC) 1627169689Skan switch (XINT (base, 1)) 1628169689Skan { 1629169689Skan case UNSPEC_LTREF: 1630169689Skan if (!disp) 1631169689Skan disp = gen_rtx_UNSPEC (Pmode, 1632169689Skan gen_rtvec (1, XVECEXP (base, 0, 0)), 1633169689Skan UNSPEC_LTREL_OFFSET); 1634169689Skan else 1635169689Skan return false; 1636169689Skan 1637169689Skan base = XVECEXP (base, 0, 1); 1638169689Skan break; 1639169689Skan 1640169689Skan case UNSPEC_LTREL_BASE: 1641169689Skan if (XVECLEN (base, 0) == 1) 1642169689Skan base = fake_pool_base, literal_pool = true; 1643169689Skan else 1644169689Skan base = XVECEXP (base, 0, 1); 1645169689Skan break; 1646169689Skan 1647169689Skan default: 1648169689Skan return false; 1649169689Skan } 1650169689Skan 1651169689Skan if (!REG_P (base) 1652169689Skan || (GET_MODE (base) != SImode 1653169689Skan && GET_MODE (base) != Pmode)) 1654169689Skan return false; 1655169689Skan 1656169689Skan if (REGNO (base) == STACK_POINTER_REGNUM 1657169689Skan || REGNO (base) == FRAME_POINTER_REGNUM 1658169689Skan || ((reload_completed || reload_in_progress) 1659169689Skan && frame_pointer_needed 1660169689Skan && REGNO (base) == HARD_FRAME_POINTER_REGNUM) 1661169689Skan || REGNO (base) == ARG_POINTER_REGNUM 1662169689Skan || (flag_pic 1663169689Skan && REGNO (base) == PIC_OFFSET_TABLE_REGNUM)) 1664169689Skan pointer = base_ptr = true; 1665169689Skan 1666169689Skan if ((reload_completed || reload_in_progress) 1667169689Skan && base == cfun->machine->base_reg) 1668169689Skan pointer = base_ptr = literal_pool = true; 1669107590Sobrien } 1670107590Sobrien 1671169689Skan /* Validate index register. */ 1672169689Skan if (indx) 1673169689Skan { 1674169689Skan if (GET_CODE (indx) == UNSPEC) 1675169689Skan switch (XINT (indx, 1)) 1676169689Skan { 1677169689Skan case UNSPEC_LTREF: 1678169689Skan if (!disp) 1679169689Skan disp = gen_rtx_UNSPEC (Pmode, 1680169689Skan gen_rtvec (1, XVECEXP (indx, 0, 0)), 1681169689Skan UNSPEC_LTREL_OFFSET); 1682169689Skan else 1683169689Skan return false; 1684107590Sobrien 1685169689Skan indx = XVECEXP (indx, 0, 1); 1686169689Skan break; 1687107590Sobrien 1688169689Skan case UNSPEC_LTREL_BASE: 1689169689Skan if (XVECLEN (indx, 0) == 1) 1690169689Skan indx = fake_pool_base, literal_pool = true; 1691169689Skan else 1692169689Skan indx = XVECEXP (indx, 0, 1); 1693169689Skan break; 1694107590Sobrien 1695169689Skan default: 1696169689Skan return false; 1697169689Skan } 1698107590Sobrien 1699169689Skan if (!REG_P (indx) 1700169689Skan || (GET_MODE (indx) != SImode 1701169689Skan && GET_MODE (indx) != Pmode)) 1702169689Skan return false; 1703107590Sobrien 1704169689Skan if (REGNO (indx) == STACK_POINTER_REGNUM 1705169689Skan || REGNO (indx) == FRAME_POINTER_REGNUM 1706169689Skan || ((reload_completed || reload_in_progress) 1707169689Skan && frame_pointer_needed 1708169689Skan && REGNO (indx) == HARD_FRAME_POINTER_REGNUM) 1709169689Skan || REGNO (indx) == ARG_POINTER_REGNUM 1710169689Skan || (flag_pic 1711169689Skan && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM)) 1712169689Skan pointer = indx_ptr = true; 1713107590Sobrien 1714169689Skan if ((reload_completed || reload_in_progress) 1715169689Skan && indx == cfun->machine->base_reg) 1716169689Skan pointer = indx_ptr = literal_pool = true; 1717169689Skan } 1718107590Sobrien 1719169689Skan /* Prefer to use pointer as base, not index. */ 1720169689Skan if (base && indx && !base_ptr 1721169689Skan && (indx_ptr || (!REG_POINTER (base) && REG_POINTER (indx)))) 1722107590Sobrien { 1723169689Skan rtx tmp = base; 1724169689Skan base = indx; 1725169689Skan indx = tmp; 1726169689Skan } 1727107590Sobrien 1728169689Skan /* Validate displacement. */ 1729169689Skan if (!disp) 1730169689Skan { 1731169689Skan /* If virtual registers are involved, the displacement will change later 1732169689Skan anyway as the virtual registers get eliminated. This could make a 1733169689Skan valid displacement invalid, but it is more likely to make an invalid 1734169689Skan displacement valid, because we sometimes access the register save area 1735169689Skan via negative offsets to one of those registers. 1736169689Skan Thus we don't check the displacement for validity here. If after 1737169689Skan elimination the displacement turns out to be invalid after all, 1738169689Skan this is fixed up by reload in any case. */ 1739169689Skan if (base != arg_pointer_rtx 1740169689Skan && indx != arg_pointer_rtx 1741169689Skan && base != return_address_pointer_rtx 1742169689Skan && indx != return_address_pointer_rtx 1743169689Skan && base != frame_pointer_rtx 1744169689Skan && indx != frame_pointer_rtx 1745169689Skan && base != virtual_stack_vars_rtx 1746169689Skan && indx != virtual_stack_vars_rtx) 1747169689Skan if (!DISP_IN_RANGE (offset)) 1748169689Skan return false; 1749169689Skan } 1750169689Skan else 1751169689Skan { 1752169689Skan /* All the special cases are pointers. */ 1753169689Skan pointer = true; 1754107590Sobrien 1755169689Skan /* In the small-PIC case, the linker converts @GOT 1756169689Skan and @GOTNTPOFF offsets to possible displacements. */ 1757169689Skan if (GET_CODE (disp) == UNSPEC 1758169689Skan && (XINT (disp, 1) == UNSPEC_GOT 1759169689Skan || XINT (disp, 1) == UNSPEC_GOTNTPOFF) 1760169689Skan && flag_pic == 1) 1761169689Skan { 1762169689Skan ; 1763169689Skan } 1764169689Skan 1765169689Skan /* Accept chunkified literal pool symbol references. */ 1766169689Skan else if (cfun && cfun->machine 1767169689Skan && cfun->machine->decomposed_literal_pool_addresses_ok_p 1768169689Skan && GET_CODE (disp) == MINUS 1769169689Skan && GET_CODE (XEXP (disp, 0)) == LABEL_REF 1770169689Skan && GET_CODE (XEXP (disp, 1)) == LABEL_REF) 1771169689Skan { 1772169689Skan ; 1773169689Skan } 1774169689Skan 1775169689Skan /* Accept literal pool references. */ 1776169689Skan else if (GET_CODE (disp) == UNSPEC 1777169689Skan && XINT (disp, 1) == UNSPEC_LTREL_OFFSET) 1778169689Skan { 1779169689Skan orig_disp = gen_rtx_CONST (Pmode, disp); 1780169689Skan if (offset) 1781169689Skan { 1782169689Skan /* If we have an offset, make sure it does not 1783169689Skan exceed the size of the constant pool entry. */ 1784169689Skan rtx sym = XVECEXP (disp, 0, 0); 1785169689Skan if (offset >= GET_MODE_SIZE (get_pool_mode (sym))) 1786169689Skan return false; 1787169689Skan 1788169689Skan orig_disp = plus_constant (orig_disp, offset); 1789169689Skan } 1790169689Skan } 1791169689Skan 1792169689Skan else 1793169689Skan return false; 1794107590Sobrien } 1795107590Sobrien 1796169689Skan if (!base && !indx) 1797169689Skan pointer = true; 1798107590Sobrien 1799169689Skan if (out) 1800169689Skan { 1801169689Skan out->base = base; 1802169689Skan out->indx = indx; 1803169689Skan out->disp = orig_disp; 1804169689Skan out->pointer = pointer; 1805169689Skan out->literal_pool = literal_pool; 1806169689Skan } 1807107590Sobrien 1808169689Skan return true; 1809107590Sobrien} 1810107590Sobrien 1811169689Skan/* Decompose a RTL expression OP for a shift count into its components, 1812169689Skan and return the base register in BASE and the offset in OFFSET. 1813107590Sobrien 1814169689Skan Return true if OP is a valid shift count, false if not. */ 1815107590Sobrien 1816169689Skanbool 1817169689Skans390_decompose_shift_count (rtx op, rtx *base, HOST_WIDE_INT *offset) 1818117395Skan{ 1819169689Skan HOST_WIDE_INT off = 0; 1820117395Skan 1821132718Skan /* We can have an integer constant, an address register, 1822169689Skan or a sum of the two. */ 1823132718Skan if (GET_CODE (op) == CONST_INT) 1824132718Skan { 1825169689Skan off = INTVAL (op); 1826132718Skan op = NULL_RTX; 1827132718Skan } 1828132718Skan if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) 1829132718Skan { 1830169689Skan off = INTVAL (XEXP (op, 1)); 1831132718Skan op = XEXP (op, 0); 1832132718Skan } 1833132718Skan while (op && GET_CODE (op) == SUBREG) 1834132718Skan op = SUBREG_REG (op); 1835169689Skan 1836132718Skan if (op && GET_CODE (op) != REG) 1837169689Skan return false; 1838117395Skan 1839169689Skan if (offset) 1840169689Skan *offset = off; 1841169689Skan if (base) 1842169689Skan *base = op; 1843117395Skan 1844169689Skan return true; 1845117395Skan} 1846117395Skan 1847117395Skan 1848169689Skan/* Return true if CODE is a valid address without index. */ 1849169689Skan 1850169689Skanbool 1851169689Skans390_legitimate_address_without_index_p (rtx op) 1852132718Skan{ 1853169689Skan struct s390_address addr; 1854132718Skan 1855169689Skan if (!s390_decompose_address (XEXP (op, 0), &addr)) 1856169689Skan return false; 1857169689Skan if (addr.indx) 1858169689Skan return false; 1859132718Skan 1860169689Skan return true; 1861169689Skan} 1862132718Skan 1863132718Skan 1864169689Skan/* Evaluates constraint strings described by the regular expression 1865169689Skan ([A|B](Q|R|S|T))|U|W and returns 1 if OP is a valid operand for the 1866169689Skan constraint given in STR, or 0 else. */ 1867132718Skan 1868117395Skanint 1869169689Skans390_mem_constraint (const char *str, rtx op) 1870117395Skan{ 1871132718Skan struct s390_address addr; 1872169689Skan char c = str[0]; 1873132718Skan 1874169689Skan /* Check for offsettable variants of memory constraints. */ 1875169689Skan if (c == 'A') 1876169689Skan { 1877169689Skan /* Only accept non-volatile MEMs. */ 1878169689Skan if (!MEM_P (op) || MEM_VOLATILE_P (op)) 1879169689Skan return 0; 1880132718Skan 1881169689Skan if ((reload_completed || reload_in_progress) 1882169689Skan ? !offsettable_memref_p (op) : !offsettable_nonstrict_memref_p (op)) 1883169689Skan return 0; 1884169689Skan 1885169689Skan c = str[1]; 1886169689Skan } 1887169689Skan 1888169689Skan /* Check for non-literal-pool variants of memory constraints. */ 1889169689Skan else if (c == 'B') 1890169689Skan { 1891169689Skan if (GET_CODE (op) != MEM) 1892169689Skan return 0; 1893169689Skan if (!s390_decompose_address (XEXP (op, 0), &addr)) 1894169689Skan return 0; 1895169689Skan if (addr.literal_pool) 1896169689Skan return 0; 1897169689Skan 1898169689Skan c = str[1]; 1899169689Skan } 1900169689Skan 1901132718Skan switch (c) 1902132718Skan { 1903132718Skan case 'Q': 1904132718Skan if (GET_CODE (op) != MEM) 1905132718Skan return 0; 1906132718Skan if (!s390_decompose_address (XEXP (op, 0), &addr)) 1907132718Skan return 0; 1908132718Skan if (addr.indx) 1909132718Skan return 0; 1910132718Skan 1911132718Skan if (TARGET_LONG_DISPLACEMENT) 1912132718Skan { 1913132718Skan if (!s390_short_displacement (addr.disp)) 1914132718Skan return 0; 1915132718Skan } 1916132718Skan break; 1917132718Skan 1918132718Skan case 'R': 1919132718Skan if (GET_CODE (op) != MEM) 1920132718Skan return 0; 1921132718Skan 1922132718Skan if (TARGET_LONG_DISPLACEMENT) 1923132718Skan { 1924132718Skan if (!s390_decompose_address (XEXP (op, 0), &addr)) 1925132718Skan return 0; 1926132718Skan if (!s390_short_displacement (addr.disp)) 1927132718Skan return 0; 1928132718Skan } 1929132718Skan break; 1930132718Skan 1931132718Skan case 'S': 1932132718Skan if (!TARGET_LONG_DISPLACEMENT) 1933132718Skan return 0; 1934132718Skan if (GET_CODE (op) != MEM) 1935132718Skan return 0; 1936132718Skan if (!s390_decompose_address (XEXP (op, 0), &addr)) 1937132718Skan return 0; 1938132718Skan if (addr.indx) 1939132718Skan return 0; 1940132718Skan if (s390_short_displacement (addr.disp)) 1941132718Skan return 0; 1942132718Skan break; 1943132718Skan 1944132718Skan case 'T': 1945132718Skan if (!TARGET_LONG_DISPLACEMENT) 1946132718Skan return 0; 1947132718Skan if (GET_CODE (op) != MEM) 1948132718Skan return 0; 1949132718Skan /* Any invalid address here will be fixed up by reload, 1950132718Skan so accept it for the most generic constraint. */ 1951132718Skan if (s390_decompose_address (XEXP (op, 0), &addr) 1952132718Skan && s390_short_displacement (addr.disp)) 1953132718Skan return 0; 1954132718Skan break; 1955132718Skan 1956132718Skan case 'U': 1957132718Skan if (TARGET_LONG_DISPLACEMENT) 1958132718Skan { 1959132718Skan if (!s390_decompose_address (op, &addr)) 1960132718Skan return 0; 1961132718Skan if (!s390_short_displacement (addr.disp)) 1962132718Skan return 0; 1963132718Skan } 1964132718Skan break; 1965132718Skan 1966132718Skan case 'W': 1967132718Skan if (!TARGET_LONG_DISPLACEMENT) 1968132718Skan return 0; 1969132718Skan /* Any invalid address here will be fixed up by reload, 1970132718Skan so accept it for the most generic constraint. */ 1971132718Skan if (s390_decompose_address (op, &addr) 1972132718Skan && s390_short_displacement (addr.disp)) 1973132718Skan return 0; 1974132718Skan break; 1975132718Skan 1976132718Skan case 'Y': 1977169689Skan /* Simply check for the basic form of a shift count. Reload will 1978169689Skan take care of making sure we have a proper base register. */ 1979169689Skan if (!s390_decompose_shift_count (op, NULL, NULL)) 1980169689Skan return 0; 1981169689Skan break; 1982132718Skan 1983132718Skan default: 1984132718Skan return 0; 1985132718Skan } 1986132718Skan 1987132718Skan return 1; 1988132718Skan} 1989132718Skan 1990132718Skan 1991169689Skan 1992169689Skan/* Evaluates constraint strings starting with letter O. Input 1993169689Skan parameter C is the second letter following the "O" in the constraint 1994169689Skan string. Returns 1 if VALUE meets the respective constraint and 0 1995169689Skan otherwise. */ 1996169689Skan 1997132718Skanint 1998169689Skans390_O_constraint_str (const char c, HOST_WIDE_INT value) 1999132718Skan{ 2000169689Skan if (!TARGET_EXTIMM) 2001169689Skan return 0; 2002132718Skan 2003169689Skan switch (c) 2004132718Skan { 2005169689Skan case 's': 2006169689Skan return trunc_int_for_mode (value, SImode) == value; 2007132718Skan 2008169689Skan case 'p': 2009169689Skan return value == 0 2010169689Skan || s390_single_part (GEN_INT (value), DImode, SImode, 0) == 1; 2011132718Skan 2012169689Skan case 'n': 2013169689Skan return value == -1 2014169689Skan || s390_single_part (GEN_INT (value), DImode, SImode, -1) == 1; 2015132718Skan 2016169689Skan default: 2017169689Skan gcc_unreachable (); 2018169689Skan } 2019169689Skan} 2020132718Skan 2021132718Skan 2022169689Skan/* Evaluates constraint strings starting with letter N. Parameter STR 2023169689Skan contains the letters following letter "N" in the constraint string. 2024169689Skan Returns true if VALUE matches the constraint. */ 2025132718Skan 2026169689Skanint 2027169689Skans390_N_constraint_str (const char *str, HOST_WIDE_INT value) 2028169689Skan{ 2029169689Skan enum machine_mode mode, part_mode; 2030169689Skan int def; 2031169689Skan int part, part_goal; 2032132718Skan 2033132718Skan 2034169689Skan if (str[0] == 'x') 2035169689Skan part_goal = -1; 2036169689Skan else 2037169689Skan part_goal = str[0] - '0'; 2038132718Skan 2039169689Skan switch (str[1]) 2040169689Skan { 2041169689Skan case 'Q': 2042169689Skan part_mode = QImode; 2043132718Skan break; 2044169689Skan case 'H': 2045169689Skan part_mode = HImode; 2046169689Skan break; 2047169689Skan case 'S': 2048169689Skan part_mode = SImode; 2049169689Skan break; 2050169689Skan default: 2051169689Skan return 0; 2052169689Skan } 2053132718Skan 2054169689Skan switch (str[2]) 2055169689Skan { 2056169689Skan case 'H': 2057169689Skan mode = HImode; 2058169689Skan break; 2059169689Skan case 'S': 2060169689Skan mode = SImode; 2061169689Skan break; 2062169689Skan case 'D': 2063169689Skan mode = DImode; 2064169689Skan break; 2065132718Skan default: 2066132718Skan return 0; 2067132718Skan } 2068132718Skan 2069169689Skan switch (str[3]) 2070169689Skan { 2071169689Skan case '0': 2072169689Skan def = 0; 2073169689Skan break; 2074169689Skan case 'F': 2075169689Skan def = -1; 2076169689Skan break; 2077169689Skan default: 2078169689Skan return 0; 2079169689Skan } 2080169689Skan 2081169689Skan if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (part_mode)) 2082169689Skan return 0; 2083169689Skan 2084169689Skan part = s390_single_part (GEN_INT (value), mode, part_mode, def); 2085169689Skan if (part < 0) 2086169689Skan return 0; 2087169689Skan if (part_goal != -1 && part_goal != part) 2088169689Skan return 0; 2089169689Skan 2090132718Skan return 1; 2091132718Skan} 2092132718Skan 2093169689Skan 2094169689Skan/* Returns true if the input parameter VALUE is a float zero. */ 2095169689Skan 2096169689Skanint 2097169689Skans390_float_const_zero_p (rtx value) 2098169689Skan{ 2099169689Skan return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT 2100169689Skan && value == CONST0_RTX (GET_MODE (value))); 2101169689Skan} 2102169689Skan 2103169689Skan 2104132718Skan/* Compute a (partial) cost for rtx X. Return true if the complete 2105132718Skan cost has been computed, and false if subexpressions should be 2106169689Skan scanned. In either case, *TOTAL contains the cost result. 2107169689Skan CODE contains GET_CODE (x), OUTER_CODE contains the code 2108169689Skan of the superexpression of x. */ 2109132718Skan 2110132718Skanstatic bool 2111132718Skans390_rtx_costs (rtx x, int code, int outer_code, int *total) 2112132718Skan{ 2113132718Skan switch (code) 2114132718Skan { 2115132718Skan case CONST: 2116132718Skan case CONST_INT: 2117132718Skan case LABEL_REF: 2118132718Skan case SYMBOL_REF: 2119132718Skan case CONST_DOUBLE: 2120169689Skan case MEM: 2121132718Skan *total = 0; 2122132718Skan return true; 2123132718Skan 2124132718Skan case ASHIFT: 2125132718Skan case ASHIFTRT: 2126132718Skan case LSHIFTRT: 2127169689Skan case ROTATE: 2128169689Skan case ROTATERT: 2129132718Skan case AND: 2130132718Skan case IOR: 2131132718Skan case XOR: 2132132718Skan case NEG: 2133132718Skan case NOT: 2134132718Skan *total = COSTS_N_INSNS (1); 2135169689Skan return false; 2136132718Skan 2137169689Skan case PLUS: 2138169689Skan case MINUS: 2139169689Skan /* Check for multiply and add. */ 2140169689Skan if ((GET_MODE (x) == DFmode || GET_MODE (x) == SFmode) 2141169689Skan && GET_CODE (XEXP (x, 0)) == MULT 2142169689Skan && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD) 2143169689Skan { 2144169689Skan /* This is the multiply and add case. */ 2145169689Skan if (GET_MODE (x) == DFmode) 2146169689Skan *total = s390_cost->madbr; 2147169689Skan else 2148169689Skan *total = s390_cost->maebr; 2149169689Skan *total += rtx_cost (XEXP (XEXP (x, 0), 0), MULT) 2150169689Skan + rtx_cost (XEXP (XEXP (x, 0), 1), MULT) 2151169689Skan + rtx_cost (XEXP (x, 1), code); 2152169689Skan return true; /* Do not do an additional recursive descent. */ 2153169689Skan } 2154169689Skan *total = COSTS_N_INSNS (1); 2155169689Skan return false; 2156132718Skan 2157169689Skan case MULT: 2158169689Skan switch (GET_MODE (x)) 2159169689Skan { 2160169689Skan case SImode: 2161169689Skan { 2162169689Skan rtx left = XEXP (x, 0); 2163169689Skan rtx right = XEXP (x, 1); 2164169689Skan if (GET_CODE (right) == CONST_INT 2165169689Skan && CONST_OK_FOR_K (INTVAL (right))) 2166169689Skan *total = s390_cost->mhi; 2167169689Skan else if (GET_CODE (left) == SIGN_EXTEND) 2168169689Skan *total = s390_cost->mh; 2169169689Skan else 2170169689Skan *total = s390_cost->ms; /* msr, ms, msy */ 2171169689Skan break; 2172169689Skan } 2173169689Skan case DImode: 2174169689Skan { 2175169689Skan rtx left = XEXP (x, 0); 2176169689Skan rtx right = XEXP (x, 1); 2177169689Skan if (TARGET_64BIT) 2178169689Skan { 2179169689Skan if (GET_CODE (right) == CONST_INT 2180169689Skan && CONST_OK_FOR_K (INTVAL (right))) 2181169689Skan *total = s390_cost->mghi; 2182169689Skan else if (GET_CODE (left) == SIGN_EXTEND) 2183169689Skan *total = s390_cost->msgf; 2184169689Skan else 2185169689Skan *total = s390_cost->msg; /* msgr, msg */ 2186169689Skan } 2187169689Skan else /* TARGET_31BIT */ 2188169689Skan { 2189169689Skan if (GET_CODE (left) == SIGN_EXTEND 2190169689Skan && GET_CODE (right) == SIGN_EXTEND) 2191169689Skan /* mulsidi case: mr, m */ 2192169689Skan *total = s390_cost->m; 2193169689Skan else if (GET_CODE (left) == ZERO_EXTEND 2194169689Skan && GET_CODE (right) == ZERO_EXTEND 2195169689Skan && TARGET_CPU_ZARCH) 2196169689Skan /* umulsidi case: ml, mlr */ 2197169689Skan *total = s390_cost->ml; 2198169689Skan else 2199169689Skan /* Complex calculation is required. */ 2200169689Skan *total = COSTS_N_INSNS (40); 2201169689Skan } 2202169689Skan break; 2203169689Skan } 2204169689Skan case SFmode: 2205169689Skan case DFmode: 2206169689Skan *total = s390_cost->mult_df; 2207169689Skan break; 2208169689Skan case TFmode: 2209169689Skan *total = s390_cost->mxbr; 2210169689Skan break; 2211169689Skan default: 2212169689Skan return false; 2213169689Skan } 2214169689Skan return false; 2215169689Skan 2216132718Skan case UDIV: 2217132718Skan case UMOD: 2218169689Skan if (GET_MODE (x) == TImode) /* 128 bit division */ 2219169689Skan *total = s390_cost->dlgr; 2220169689Skan else if (GET_MODE (x) == DImode) 2221169689Skan { 2222169689Skan rtx right = XEXP (x, 1); 2223169689Skan if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */ 2224169689Skan *total = s390_cost->dlr; 2225169689Skan else /* 64 by 64 bit division */ 2226169689Skan *total = s390_cost->dlgr; 2227169689Skan } 2228169689Skan else if (GET_MODE (x) == SImode) /* 32 bit division */ 2229169689Skan *total = s390_cost->dlr; 2230169689Skan return false; 2231132718Skan 2232169689Skan case DIV: 2233169689Skan case MOD: 2234169689Skan if (GET_MODE (x) == DImode) 2235169689Skan { 2236169689Skan rtx right = XEXP (x, 1); 2237169689Skan if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */ 2238169689Skan if (TARGET_64BIT) 2239169689Skan *total = s390_cost->dsgfr; 2240169689Skan else 2241169689Skan *total = s390_cost->dr; 2242169689Skan else /* 64 by 64 bit division */ 2243169689Skan *total = s390_cost->dsgr; 2244169689Skan } 2245169689Skan else if (GET_MODE (x) == SImode) /* 32 bit division */ 2246169689Skan *total = s390_cost->dlr; 2247169689Skan else if (GET_MODE (x) == SFmode) 2248169689Skan { 2249169689Skan if (TARGET_IEEE_FLOAT) 2250169689Skan *total = s390_cost->debr; 2251169689Skan else /* TARGET_IBM_FLOAT */ 2252169689Skan *total = s390_cost->der; 2253169689Skan } 2254169689Skan else if (GET_MODE (x) == DFmode) 2255169689Skan { 2256169689Skan if (TARGET_IEEE_FLOAT) 2257169689Skan *total = s390_cost->ddbr; 2258169689Skan else /* TARGET_IBM_FLOAT */ 2259169689Skan *total = s390_cost->ddr; 2260169689Skan } 2261169689Skan else if (GET_MODE (x) == TFmode) 2262169689Skan { 2263169689Skan if (TARGET_IEEE_FLOAT) 2264169689Skan *total = s390_cost->dxbr; 2265169689Skan else /* TARGET_IBM_FLOAT */ 2266169689Skan *total = s390_cost->dxr; 2267169689Skan } 2268169689Skan return false; 2269169689Skan 2270169689Skan case SQRT: 2271169689Skan if (GET_MODE (x) == SFmode) 2272169689Skan *total = s390_cost->sqebr; 2273169689Skan else if (GET_MODE (x) == DFmode) 2274169689Skan *total = s390_cost->sqdbr; 2275169689Skan else /* TFmode */ 2276169689Skan *total = s390_cost->sqxbr; 2277169689Skan return false; 2278169689Skan 2279169689Skan case SIGN_EXTEND: 2280169689Skan case ZERO_EXTEND: 2281169689Skan if (outer_code == MULT || outer_code == DIV || outer_code == MOD 2282169689Skan || outer_code == PLUS || outer_code == MINUS 2283169689Skan || outer_code == COMPARE) 2284169689Skan *total = 0; 2285169689Skan return false; 2286169689Skan 2287169689Skan case COMPARE: 2288169689Skan *total = COSTS_N_INSNS (1); 2289169689Skan if (GET_CODE (XEXP (x, 0)) == AND 2290169689Skan && GET_CODE (XEXP (x, 1)) == CONST_INT 2291169689Skan && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) 2292169689Skan { 2293169689Skan rtx op0 = XEXP (XEXP (x, 0), 0); 2294169689Skan rtx op1 = XEXP (XEXP (x, 0), 1); 2295169689Skan rtx op2 = XEXP (x, 1); 2296169689Skan 2297169689Skan if (memory_operand (op0, GET_MODE (op0)) 2298169689Skan && s390_tm_ccmode (op1, op2, 0) != VOIDmode) 2299169689Skan return true; 2300169689Skan if (register_operand (op0, GET_MODE (op0)) 2301169689Skan && s390_tm_ccmode (op1, op2, 1) != VOIDmode) 2302169689Skan return true; 2303169689Skan } 2304169689Skan return false; 2305169689Skan 2306132718Skan default: 2307132718Skan return false; 2308132718Skan } 2309132718Skan} 2310132718Skan 2311132718Skan/* Return the cost of an address rtx ADDR. */ 2312132718Skan 2313132718Skanstatic int 2314132718Skans390_address_cost (rtx addr) 2315132718Skan{ 2316117395Skan struct s390_address ad; 2317117395Skan if (!s390_decompose_address (addr, &ad)) 2318117395Skan return 1000; 2319117395Skan 2320117395Skan return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1); 2321117395Skan} 2322117395Skan 2323117395Skan/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode, 2324117395Skan otherwise return 0. */ 2325117395Skan 2326117395Skanint 2327169689Skantls_symbolic_operand (rtx op) 2328117395Skan{ 2329117395Skan if (GET_CODE (op) != SYMBOL_REF) 2330117395Skan return 0; 2331132718Skan return SYMBOL_REF_TLS_MODEL (op); 2332117395Skan} 2333107590Sobrien 2334169689Skan/* Split DImode access register reference REG (on 64-bit) into its constituent 2335169689Skan low and high parts, and store them into LO and HI. Note that gen_lowpart/ 2336169689Skan gen_highpart cannot be used as they assume all registers are word-sized, 2337169689Skan while our access registers have only half that size. */ 2338107590Sobrien 2339169689Skanvoid 2340169689Skans390_split_access_reg (rtx reg, rtx *lo, rtx *hi) 2341107590Sobrien{ 2342169689Skan gcc_assert (TARGET_64BIT); 2343169689Skan gcc_assert (ACCESS_REG_P (reg)); 2344169689Skan gcc_assert (GET_MODE (reg) == DImode); 2345169689Skan gcc_assert (!(REGNO (reg) & 1)); 2346107590Sobrien 2347169689Skan *lo = gen_rtx_REG (SImode, REGNO (reg) + 1); 2348169689Skan *hi = gen_rtx_REG (SImode, REGNO (reg)); 2349107590Sobrien} 2350107590Sobrien 2351107590Sobrien/* Return true if OP contains a symbol reference */ 2352107590Sobrien 2353169689Skanbool 2354132718Skansymbolic_reference_mentioned_p (rtx op) 2355107590Sobrien{ 2356169689Skan const char *fmt; 2357169689Skan int i; 2358107590Sobrien 2359107590Sobrien if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) 2360107590Sobrien return 1; 2361107590Sobrien 2362107590Sobrien fmt = GET_RTX_FORMAT (GET_CODE (op)); 2363107590Sobrien for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) 2364107590Sobrien { 2365107590Sobrien if (fmt[i] == 'E') 2366107590Sobrien { 2367169689Skan int j; 2368107590Sobrien 2369107590Sobrien for (j = XVECLEN (op, i) - 1; j >= 0; j--) 2370107590Sobrien if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) 2371107590Sobrien return 1; 2372107590Sobrien } 2373107590Sobrien 2374107590Sobrien else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) 2375107590Sobrien return 1; 2376107590Sobrien } 2377107590Sobrien 2378107590Sobrien return 0; 2379107590Sobrien} 2380107590Sobrien 2381117395Skan/* Return true if OP contains a reference to a thread-local symbol. */ 2382107590Sobrien 2383169689Skanbool 2384132718Skantls_symbolic_reference_mentioned_p (rtx op) 2385117395Skan{ 2386169689Skan const char *fmt; 2387169689Skan int i; 2388117395Skan 2389117395Skan if (GET_CODE (op) == SYMBOL_REF) 2390117395Skan return tls_symbolic_operand (op); 2391117395Skan 2392117395Skan fmt = GET_RTX_FORMAT (GET_CODE (op)); 2393117395Skan for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) 2394117395Skan { 2395117395Skan if (fmt[i] == 'E') 2396117395Skan { 2397169689Skan int j; 2398117395Skan 2399117395Skan for (j = XVECLEN (op, i) - 1; j >= 0; j--) 2400117395Skan if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j))) 2401169689Skan return true; 2402117395Skan } 2403117395Skan 2404117395Skan else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i))) 2405169689Skan return true; 2406117395Skan } 2407117395Skan 2408169689Skan return false; 2409117395Skan} 2410117395Skan 2411117395Skan 2412132718Skan/* Return true if OP is a legitimate general operand when 2413132718Skan generating PIC code. It is given that flag_pic is on 2414107590Sobrien and that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */ 2415107590Sobrien 2416107590Sobrienint 2417169689Skanlegitimate_pic_operand_p (rtx op) 2418107590Sobrien{ 2419107590Sobrien /* Accept all non-symbolic constants. */ 2420107590Sobrien if (!SYMBOLIC_CONST (op)) 2421107590Sobrien return 1; 2422107590Sobrien 2423132718Skan /* Reject everything else; must be handled 2424117395Skan via emit_symbolic_move. */ 2425107590Sobrien return 0; 2426107590Sobrien} 2427107590Sobrien 2428107590Sobrien/* Returns true if the constant value OP is a legitimate general operand. 2429107590Sobrien It is given that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */ 2430107590Sobrien 2431107590Sobrienint 2432169689Skanlegitimate_constant_p (rtx op) 2433107590Sobrien{ 2434107590Sobrien /* Accept all non-symbolic constants. */ 2435107590Sobrien if (!SYMBOLIC_CONST (op)) 2436107590Sobrien return 1; 2437107590Sobrien 2438117395Skan /* Accept immediate LARL operands. */ 2439132718Skan if (TARGET_CPU_ZARCH && larl_operand (op, VOIDmode)) 2440117395Skan return 1; 2441117395Skan 2442117395Skan /* Thread-local symbols are never legal constants. This is 2443117395Skan so that emit_call knows that computing such addresses 2444117395Skan might require a function call. */ 2445117395Skan if (TLS_SYMBOLIC_CONST (op)) 2446117395Skan return 0; 2447117395Skan 2448107590Sobrien /* In the PIC case, symbolic constants must *not* be 2449107590Sobrien forced into the literal pool. We accept them here, 2450117395Skan so that they will be handled by emit_symbolic_move. */ 2451107590Sobrien if (flag_pic) 2452107590Sobrien return 1; 2453107590Sobrien 2454107590Sobrien /* All remaining non-PIC symbolic constants are 2455107590Sobrien forced into the literal pool. */ 2456107590Sobrien return 0; 2457107590Sobrien} 2458107590Sobrien 2459117395Skan/* Determine if it's legal to put X into the constant pool. This 2460117395Skan is not possible if X contains the address of a symbol that is 2461117395Skan not constant (TLS) or not known at final link time (PIC). */ 2462117395Skan 2463117395Skanstatic bool 2464132718Skans390_cannot_force_const_mem (rtx x) 2465117395Skan{ 2466117395Skan switch (GET_CODE (x)) 2467117395Skan { 2468117395Skan case CONST_INT: 2469117395Skan case CONST_DOUBLE: 2470117395Skan /* Accept all non-symbolic constants. */ 2471117395Skan return false; 2472117395Skan 2473117395Skan case LABEL_REF: 2474117395Skan /* Labels are OK iff we are non-PIC. */ 2475117395Skan return flag_pic != 0; 2476117395Skan 2477117395Skan case SYMBOL_REF: 2478117395Skan /* 'Naked' TLS symbol references are never OK, 2479117395Skan non-TLS symbols are OK iff we are non-PIC. */ 2480117395Skan if (tls_symbolic_operand (x)) 2481117395Skan return true; 2482117395Skan else 2483117395Skan return flag_pic != 0; 2484117395Skan 2485117395Skan case CONST: 2486117395Skan return s390_cannot_force_const_mem (XEXP (x, 0)); 2487117395Skan case PLUS: 2488117395Skan case MINUS: 2489117395Skan return s390_cannot_force_const_mem (XEXP (x, 0)) 2490117395Skan || s390_cannot_force_const_mem (XEXP (x, 1)); 2491117395Skan 2492117395Skan case UNSPEC: 2493117395Skan switch (XINT (x, 1)) 2494117395Skan { 2495117395Skan /* Only lt-relative or GOT-relative UNSPECs are OK. */ 2496132718Skan case UNSPEC_LTREL_OFFSET: 2497132718Skan case UNSPEC_GOT: 2498132718Skan case UNSPEC_GOTOFF: 2499132718Skan case UNSPEC_PLTOFF: 2500117395Skan case UNSPEC_TLSGD: 2501117395Skan case UNSPEC_TLSLDM: 2502117395Skan case UNSPEC_NTPOFF: 2503117395Skan case UNSPEC_DTPOFF: 2504117395Skan case UNSPEC_GOTNTPOFF: 2505117395Skan case UNSPEC_INDNTPOFF: 2506117395Skan return false; 2507117395Skan 2508169689Skan /* If the literal pool shares the code section, be put 2509169689Skan execute template placeholders into the pool as well. */ 2510169689Skan case UNSPEC_INSN: 2511169689Skan return TARGET_CPU_ZARCH; 2512169689Skan 2513117395Skan default: 2514117395Skan return true; 2515117395Skan } 2516117395Skan break; 2517117395Skan 2518117395Skan default: 2519169689Skan gcc_unreachable (); 2520117395Skan } 2521117395Skan} 2522117395Skan 2523107590Sobrien/* Returns true if the constant value OP is a legitimate general 2524132718Skan operand during and after reload. The difference to 2525107590Sobrien legitimate_constant_p is that this function will not accept 2526107590Sobrien a constant that would need to be forced to the literal pool 2527107590Sobrien before it can be used as operand. */ 2528107590Sobrien 2529169689Skanbool 2530169689Skanlegitimate_reload_constant_p (rtx op) 2531107590Sobrien{ 2532132718Skan /* Accept la(y) operands. */ 2533132718Skan if (GET_CODE (op) == CONST_INT 2534132718Skan && DISP_IN_RANGE (INTVAL (op))) 2535169689Skan return true; 2536132718Skan 2537169689Skan /* Accept l(g)hi/l(g)fi operands. */ 2538107590Sobrien if (GET_CODE (op) == CONST_INT 2539169689Skan && (CONST_OK_FOR_K (INTVAL (op)) || CONST_OK_FOR_Os (INTVAL (op)))) 2540169689Skan return true; 2541107590Sobrien 2542107590Sobrien /* Accept lliXX operands. */ 2543132718Skan if (TARGET_ZARCH 2544169689Skan && GET_CODE (op) == CONST_INT 2545169689Skan && trunc_int_for_mode (INTVAL (op), word_mode) == INTVAL (op) 2546169689Skan && s390_single_part (op, word_mode, HImode, 0) >= 0) 2547169689Skan return true; 2548107590Sobrien 2549169689Skan if (TARGET_EXTIMM 2550169689Skan && GET_CODE (op) == CONST_INT 2551169689Skan && trunc_int_for_mode (INTVAL (op), word_mode) == INTVAL (op) 2552169689Skan && s390_single_part (op, word_mode, SImode, 0) >= 0) 2553169689Skan return true; 2554169689Skan 2555107590Sobrien /* Accept larl operands. */ 2556132718Skan if (TARGET_CPU_ZARCH 2557107590Sobrien && larl_operand (op, VOIDmode)) 2558169689Skan return true; 2559107590Sobrien 2560169689Skan /* Accept lzXX operands. */ 2561169689Skan if (GET_CODE (op) == CONST_DOUBLE 2562169689Skan && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', "G")) 2563169689Skan return true; 2564169689Skan 2565169689Skan /* Accept double-word operands that can be split. */ 2566169689Skan if (GET_CODE (op) == CONST_INT 2567169689Skan && trunc_int_for_mode (INTVAL (op), word_mode) != INTVAL (op)) 2568169689Skan { 2569169689Skan enum machine_mode dword_mode = word_mode == SImode ? DImode : TImode; 2570169689Skan rtx hi = operand_subword (op, 0, 0, dword_mode); 2571169689Skan rtx lo = operand_subword (op, 1, 0, dword_mode); 2572169689Skan return legitimate_reload_constant_p (hi) 2573169689Skan && legitimate_reload_constant_p (lo); 2574169689Skan } 2575169689Skan 2576107590Sobrien /* Everything else cannot be handled without reload. */ 2577169689Skan return false; 2578107590Sobrien} 2579107590Sobrien 2580107590Sobrien/* Given an rtx OP being reloaded into a reg required to be in class CLASS, 2581107590Sobrien return the class of reg to actually use. */ 2582107590Sobrien 2583107590Sobrienenum reg_class 2584132718Skans390_preferred_reload_class (rtx op, enum reg_class class) 2585107590Sobrien{ 2586107590Sobrien switch (GET_CODE (op)) 2587107590Sobrien { 2588107590Sobrien /* Constants we cannot reload must be forced into the 2589117395Skan literal pool. */ 2590107590Sobrien 2591107590Sobrien case CONST_DOUBLE: 2592107590Sobrien case CONST_INT: 2593117395Skan if (legitimate_reload_constant_p (op)) 2594117395Skan return class; 2595117395Skan else 2596107590Sobrien return NO_REGS; 2597107590Sobrien 2598107590Sobrien /* If a symbolic constant or a PLUS is reloaded, 2599107590Sobrien it is most likely being used as an address, so 2600107590Sobrien prefer ADDR_REGS. If 'class' is not a superset 2601107590Sobrien of ADDR_REGS, e.g. FP_REGS, reject this reload. */ 2602107590Sobrien case PLUS: 2603107590Sobrien case LABEL_REF: 2604107590Sobrien case SYMBOL_REF: 2605107590Sobrien case CONST: 2606107590Sobrien if (reg_class_subset_p (ADDR_REGS, class)) 2607107590Sobrien return ADDR_REGS; 2608107590Sobrien else 2609107590Sobrien return NO_REGS; 2610107590Sobrien 2611107590Sobrien default: 2612107590Sobrien break; 2613107590Sobrien } 2614107590Sobrien 2615107590Sobrien return class; 2616107590Sobrien} 2617107590Sobrien 2618107590Sobrien/* Return the register class of a scratch register needed to 2619107590Sobrien load IN into a register of class CLASS in MODE. 2620107590Sobrien 2621107590Sobrien We need a temporary when loading a PLUS expression which 2622107590Sobrien is not a legitimate operand of the LOAD ADDRESS instruction. */ 2623107590Sobrien 2624107590Sobrienenum reg_class 2625169689Skans390_secondary_input_reload_class (enum reg_class class, 2626132718Skan enum machine_mode mode, rtx in) 2627107590Sobrien{ 2628107590Sobrien if (s390_plus_operand (in, mode)) 2629107590Sobrien return ADDR_REGS; 2630107590Sobrien 2631169689Skan if (reg_classes_intersect_p (FP_REGS, class) 2632169689Skan && mode == TFmode 2633169689Skan && GET_CODE (in) == MEM 2634169689Skan && GET_CODE (XEXP (in, 0)) == PLUS 2635169689Skan && GET_CODE (XEXP (XEXP (in, 0), 1)) == CONST_INT 2636169689Skan && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (in, 0), 1)) 2637169689Skan + GET_MODE_SIZE (mode) - 1)) 2638169689Skan return ADDR_REGS; 2639169689Skan 2640169689Skan if (reg_classes_intersect_p (CC_REGS, class)) 2641169689Skan return GENERAL_REGS; 2642169689Skan 2643107590Sobrien return NO_REGS; 2644107590Sobrien} 2645107590Sobrien 2646117395Skan/* Return the register class of a scratch register needed to 2647117395Skan store a register of class CLASS in MODE into OUT: 2648117395Skan 2649132718Skan We need a temporary when storing a double-word to a 2650117395Skan non-offsettable memory address. */ 2651117395Skan 2652117395Skanenum reg_class 2653132718Skans390_secondary_output_reload_class (enum reg_class class, 2654132718Skan enum machine_mode mode, rtx out) 2655117395Skan{ 2656169689Skan if ((TARGET_64BIT ? (mode == TImode || mode == TFmode) 2657117395Skan : (mode == DImode || mode == DFmode)) 2658117395Skan && reg_classes_intersect_p (GENERAL_REGS, class) 2659117395Skan && GET_CODE (out) == MEM 2660169689Skan && GET_CODE (XEXP (out, 0)) == PLUS 2661169689Skan && GET_CODE (XEXP (XEXP (out, 0), 0)) == PLUS 2662169689Skan && GET_CODE (XEXP (XEXP (out, 0), 1)) == CONST_INT 2663169689Skan && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (out, 0), 1)) 2664169689Skan + GET_MODE_SIZE (mode) - 1)) 2665117395Skan return ADDR_REGS; 2666117395Skan 2667169689Skan if (reg_classes_intersect_p (FP_REGS, class) 2668169689Skan && mode == TFmode 2669169689Skan && GET_CODE (out) == MEM 2670169689Skan && GET_CODE (XEXP (out, 0)) == PLUS 2671169689Skan && GET_CODE (XEXP (XEXP (out, 0), 1)) == CONST_INT 2672169689Skan && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (out, 0), 1)) 2673169689Skan + GET_MODE_SIZE (mode) - 1)) 2674169689Skan return ADDR_REGS; 2675117395Skan 2676169689Skan if (reg_classes_intersect_p (CC_REGS, class)) 2677169689Skan return GENERAL_REGS; 2678107590Sobrien 2679169689Skan return NO_REGS; 2680107590Sobrien} 2681107590Sobrien 2682107590Sobrien/* Generate code to load SRC, which is PLUS that is not a 2683107590Sobrien legitimate operand for the LA instruction, into TARGET. 2684107590Sobrien SCRATCH may be used as scratch register. */ 2685107590Sobrien 2686107590Sobrienvoid 2687169689Skans390_expand_plus_operand (rtx target, rtx src, 2688169689Skan rtx scratch) 2689107590Sobrien{ 2690117395Skan rtx sum1, sum2; 2691117395Skan struct s390_address ad; 2692107590Sobrien 2693107590Sobrien /* src must be a PLUS; get its two operands. */ 2694169689Skan gcc_assert (GET_CODE (src) == PLUS); 2695169689Skan gcc_assert (GET_MODE (src) == Pmode); 2696107590Sobrien 2697107590Sobrien /* Check if any of the two operands is already scheduled 2698107590Sobrien for replacement by reload. This can happen e.g. when 2699107590Sobrien float registers occur in an address. */ 2700107590Sobrien sum1 = find_replacement (&XEXP (src, 0)); 2701107590Sobrien sum2 = find_replacement (&XEXP (src, 1)); 2702117395Skan src = gen_rtx_PLUS (Pmode, sum1, sum2); 2703107590Sobrien 2704117395Skan /* If the address is already strictly valid, there's nothing to do. */ 2705117395Skan if (!s390_decompose_address (src, &ad) 2706169689Skan || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) 2707169689Skan || (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx)))) 2708107590Sobrien { 2709117395Skan /* Otherwise, one of the operands cannot be an address register; 2710117395Skan we reload its value into the scratch register. */ 2711117395Skan if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15) 2712117395Skan { 2713117395Skan emit_move_insn (scratch, sum1); 2714117395Skan sum1 = scratch; 2715117395Skan } 2716117395Skan if (true_regnum (sum2) < 1 || true_regnum (sum2) > 15) 2717117395Skan { 2718117395Skan emit_move_insn (scratch, sum2); 2719117395Skan sum2 = scratch; 2720117395Skan } 2721107590Sobrien 2722117395Skan /* According to the way these invalid addresses are generated 2723117395Skan in reload.c, it should never happen (at least on s390) that 2724117395Skan *neither* of the PLUS components, after find_replacements 2725117395Skan was applied, is an address register. */ 2726117395Skan if (sum1 == scratch && sum2 == scratch) 2727117395Skan { 2728117395Skan debug_rtx (src); 2729169689Skan gcc_unreachable (); 2730117395Skan } 2731107590Sobrien 2732117395Skan src = gen_rtx_PLUS (Pmode, sum1, sum2); 2733107590Sobrien } 2734107590Sobrien 2735107590Sobrien /* Emit the LOAD ADDRESS pattern. Note that reload of PLUS 2736107590Sobrien is only ever performed on addresses, so we can mark the 2737107590Sobrien sum as legitimate for LA in any case. */ 2738117395Skan s390_load_address (target, src); 2739107590Sobrien} 2740107590Sobrien 2741107590Sobrien 2742169689Skan/* Return true if ADDR is a valid memory address. 2743107590Sobrien STRICT specifies whether strict register checking applies. */ 2744107590Sobrien 2745169689Skanbool 2746132718Skanlegitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, 2747169689Skan rtx addr, int strict) 2748107590Sobrien{ 2749117395Skan struct s390_address ad; 2750117395Skan if (!s390_decompose_address (addr, &ad)) 2751169689Skan return false; 2752117395Skan 2753117395Skan if (strict) 2754117395Skan { 2755169689Skan if (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) 2756169689Skan return false; 2757169689Skan 2758169689Skan if (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx))) 2759169689Skan return false; 2760117395Skan } 2761117395Skan else 2762117395Skan { 2763169689Skan if (ad.base 2764169689Skan && !(REGNO (ad.base) >= FIRST_PSEUDO_REGISTER 2765169689Skan || REGNO_REG_CLASS (REGNO (ad.base)) == ADDR_REGS)) 2766169689Skan return false; 2767169689Skan 2768169689Skan if (ad.indx 2769169689Skan && !(REGNO (ad.indx) >= FIRST_PSEUDO_REGISTER 2770169689Skan || REGNO_REG_CLASS (REGNO (ad.indx)) == ADDR_REGS)) 2771169689Skan return false; 2772117395Skan } 2773169689Skan return true; 2774107590Sobrien} 2775107590Sobrien 2776169689Skan/* Return true if OP is a valid operand for the LA instruction. 2777107590Sobrien In 31-bit, we need to prove that the result is used as an 2778107590Sobrien address, as LA performs only a 31-bit addition. */ 2779107590Sobrien 2780169689Skanbool 2781169689Skanlegitimate_la_operand_p (rtx op) 2782107590Sobrien{ 2783107590Sobrien struct s390_address addr; 2784117395Skan if (!s390_decompose_address (op, &addr)) 2785169689Skan return false; 2786107590Sobrien 2787169689Skan return (TARGET_64BIT || addr.pointer); 2788107590Sobrien} 2789107590Sobrien 2790169689Skan/* Return true if it is valid *and* preferable to use LA to 2791169689Skan compute the sum of OP1 and OP2. */ 2792132718Skan 2793169689Skanbool 2794169689Skanpreferred_la_operand_p (rtx op1, rtx op2) 2795107590Sobrien{ 2796107590Sobrien struct s390_address addr; 2797107590Sobrien 2798169689Skan if (op2 != const0_rtx) 2799169689Skan op1 = gen_rtx_PLUS (Pmode, op1, op2); 2800169689Skan 2801169689Skan if (!s390_decompose_address (op1, &addr)) 2802169689Skan return false; 2803169689Skan if (addr.base && !REGNO_OK_FOR_BASE_P (REGNO (addr.base))) 2804169689Skan return false; 2805169689Skan if (addr.indx && !REGNO_OK_FOR_INDEX_P (REGNO (addr.indx))) 2806169689Skan return false; 2807169689Skan 2808117395Skan if (!TARGET_64BIT && !addr.pointer) 2809169689Skan return false; 2810107590Sobrien 2811117395Skan if (addr.pointer) 2812169689Skan return true; 2813107590Sobrien 2814117395Skan if ((addr.base && REG_P (addr.base) && REG_POINTER (addr.base)) 2815117395Skan || (addr.indx && REG_P (addr.indx) && REG_POINTER (addr.indx))) 2816169689Skan return true; 2817107590Sobrien 2818169689Skan return false; 2819107590Sobrien} 2820107590Sobrien 2821117395Skan/* Emit a forced load-address operation to load SRC into DST. 2822117395Skan This will use the LOAD ADDRESS instruction even in situations 2823117395Skan where legitimate_la_operand_p (SRC) returns false. */ 2824117395Skan 2825117395Skanvoid 2826132718Skans390_load_address (rtx dst, rtx src) 2827117395Skan{ 2828117395Skan if (TARGET_64BIT) 2829117395Skan emit_move_insn (dst, src); 2830117395Skan else 2831117395Skan emit_insn (gen_force_la_31 (dst, src)); 2832117395Skan} 2833117395Skan 2834107590Sobrien/* Return a legitimate reference for ORIG (an address) using the 2835107590Sobrien register REG. If REG is 0, a new pseudo is generated. 2836107590Sobrien 2837107590Sobrien There are two types of references that must be handled: 2838107590Sobrien 2839107590Sobrien 1. Global data references must load the address from the GOT, via 2840107590Sobrien the PIC reg. An insn is emitted to do this load, and the reg is 2841107590Sobrien returned. 2842107590Sobrien 2843107590Sobrien 2. Static data references, constant pool addresses, and code labels 2844107590Sobrien compute the address as an offset from the GOT, whose base is in 2845132718Skan the PIC reg. Static data objects have SYMBOL_FLAG_LOCAL set to 2846107590Sobrien differentiate them from global data objects. The returned 2847107590Sobrien address is the PIC reg + an unspec constant. 2848107590Sobrien 2849107590Sobrien GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC 2850107590Sobrien reg also appears in the address. */ 2851107590Sobrien 2852107590Sobrienrtx 2853132718Skanlegitimize_pic_address (rtx orig, rtx reg) 2854107590Sobrien{ 2855107590Sobrien rtx addr = orig; 2856107590Sobrien rtx new = orig; 2857107590Sobrien rtx base; 2858107590Sobrien 2859169689Skan gcc_assert (!TLS_SYMBOLIC_CONST (addr)); 2860169689Skan 2861107590Sobrien if (GET_CODE (addr) == LABEL_REF 2862132718Skan || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr))) 2863107590Sobrien { 2864107590Sobrien /* This is a local symbol. */ 2865132718Skan if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode)) 2866107590Sobrien { 2867132718Skan /* Access local symbols PC-relative via LARL. 2868132718Skan This is the same as in the non-PIC case, so it is 2869107590Sobrien handled automatically ... */ 2870107590Sobrien } 2871107590Sobrien else 2872107590Sobrien { 2873132718Skan /* Access local symbols relative to the GOT. */ 2874107590Sobrien 2875107590Sobrien rtx temp = reg? reg : gen_reg_rtx (Pmode); 2876107590Sobrien 2877132718Skan if (reload_in_progress || reload_completed) 2878132718Skan regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; 2879132718Skan 2880132718Skan addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF); 2881117395Skan addr = gen_rtx_CONST (Pmode, addr); 2882117395Skan addr = force_const_mem (Pmode, addr); 2883107590Sobrien emit_move_insn (temp, addr); 2884107590Sobrien 2885132718Skan new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); 2886107590Sobrien if (reg != 0) 2887107590Sobrien { 2888169689Skan s390_load_address (reg, new); 2889107590Sobrien new = reg; 2890107590Sobrien } 2891107590Sobrien } 2892107590Sobrien } 2893107590Sobrien else if (GET_CODE (addr) == SYMBOL_REF) 2894107590Sobrien { 2895107590Sobrien if (reg == 0) 2896107590Sobrien reg = gen_reg_rtx (Pmode); 2897107590Sobrien 2898107590Sobrien if (flag_pic == 1) 2899107590Sobrien { 2900107590Sobrien /* Assume GOT offset < 4k. This is handled the same way 2901132718Skan in both 31- and 64-bit code (@GOT). */ 2902107590Sobrien 2903117395Skan if (reload_in_progress || reload_completed) 2904117395Skan regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; 2905107590Sobrien 2906132718Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT); 2907107590Sobrien new = gen_rtx_CONST (Pmode, new); 2908107590Sobrien new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); 2909169689Skan new = gen_const_mem (Pmode, new); 2910107590Sobrien emit_move_insn (reg, new); 2911107590Sobrien new = reg; 2912107590Sobrien } 2913132718Skan else if (TARGET_CPU_ZARCH) 2914107590Sobrien { 2915107590Sobrien /* If the GOT offset might be >= 4k, we determine the position 2916107590Sobrien of the GOT entry via a PC-relative LARL (@GOTENT). */ 2917107590Sobrien 2918107590Sobrien rtx temp = gen_reg_rtx (Pmode); 2919107590Sobrien 2920132718Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT); 2921107590Sobrien new = gen_rtx_CONST (Pmode, new); 2922107590Sobrien emit_move_insn (temp, new); 2923107590Sobrien 2924169689Skan new = gen_const_mem (Pmode, temp); 2925107590Sobrien emit_move_insn (reg, new); 2926107590Sobrien new = reg; 2927107590Sobrien } 2928107590Sobrien else 2929107590Sobrien { 2930132718Skan /* If the GOT offset might be >= 4k, we have to load it 2931107590Sobrien from the literal pool (@GOT). */ 2932107590Sobrien 2933107590Sobrien rtx temp = gen_reg_rtx (Pmode); 2934107590Sobrien 2935117395Skan if (reload_in_progress || reload_completed) 2936117395Skan regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; 2937107590Sobrien 2938132718Skan addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT); 2939117395Skan addr = gen_rtx_CONST (Pmode, addr); 2940117395Skan addr = force_const_mem (Pmode, addr); 2941107590Sobrien emit_move_insn (temp, addr); 2942107590Sobrien 2943107590Sobrien new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); 2944169689Skan new = gen_const_mem (Pmode, new); 2945107590Sobrien emit_move_insn (reg, new); 2946107590Sobrien new = reg; 2947107590Sobrien } 2948132718Skan } 2949107590Sobrien else 2950107590Sobrien { 2951107590Sobrien if (GET_CODE (addr) == CONST) 2952107590Sobrien { 2953107590Sobrien addr = XEXP (addr, 0); 2954107590Sobrien if (GET_CODE (addr) == UNSPEC) 2955107590Sobrien { 2956169689Skan gcc_assert (XVECLEN (addr, 0) == 1); 2957107590Sobrien switch (XINT (addr, 1)) 2958107590Sobrien { 2959132718Skan /* If someone moved a GOT-relative UNSPEC 2960107590Sobrien out of the literal pool, force them back in. */ 2961132718Skan case UNSPEC_GOTOFF: 2962132718Skan case UNSPEC_PLTOFF: 2963117395Skan new = force_const_mem (Pmode, orig); 2964107590Sobrien break; 2965107590Sobrien 2966132718Skan /* @GOT is OK as is if small. */ 2967132718Skan case UNSPEC_GOT: 2968132718Skan if (flag_pic == 2) 2969132718Skan new = force_const_mem (Pmode, orig); 2970132718Skan break; 2971132718Skan 2972107590Sobrien /* @GOTENT is OK as is. */ 2973132718Skan case UNSPEC_GOTENT: 2974107590Sobrien break; 2975107590Sobrien 2976107590Sobrien /* @PLT is OK as is on 64-bit, must be converted to 2977132718Skan GOT-relative @PLTOFF on 31-bit. */ 2978132718Skan case UNSPEC_PLT: 2979132718Skan if (!TARGET_CPU_ZARCH) 2980107590Sobrien { 2981107590Sobrien rtx temp = reg? reg : gen_reg_rtx (Pmode); 2982107590Sobrien 2983132718Skan if (reload_in_progress || reload_completed) 2984132718Skan regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; 2985132718Skan 2986107590Sobrien addr = XVECEXP (addr, 0, 0); 2987132718Skan addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 2988132718Skan UNSPEC_PLTOFF); 2989117395Skan addr = gen_rtx_CONST (Pmode, addr); 2990117395Skan addr = force_const_mem (Pmode, addr); 2991107590Sobrien emit_move_insn (temp, addr); 2992107590Sobrien 2993132718Skan new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); 2994107590Sobrien if (reg != 0) 2995107590Sobrien { 2996169689Skan s390_load_address (reg, new); 2997107590Sobrien new = reg; 2998107590Sobrien } 2999107590Sobrien } 3000107590Sobrien break; 3001107590Sobrien 3002107590Sobrien /* Everything else cannot happen. */ 3003107590Sobrien default: 3004169689Skan gcc_unreachable (); 3005107590Sobrien } 3006107590Sobrien } 3007169689Skan else 3008169689Skan gcc_assert (GET_CODE (addr) == PLUS); 3009107590Sobrien } 3010107590Sobrien if (GET_CODE (addr) == PLUS) 3011107590Sobrien { 3012107590Sobrien rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); 3013169689Skan 3014169689Skan gcc_assert (!TLS_SYMBOLIC_CONST (op0)); 3015169689Skan gcc_assert (!TLS_SYMBOLIC_CONST (op1)); 3016169689Skan 3017132718Skan /* Check first to see if this is a constant offset 3018107590Sobrien from a local symbol reference. */ 3019107590Sobrien if ((GET_CODE (op0) == LABEL_REF 3020132718Skan || (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0))) 3021107590Sobrien && GET_CODE (op1) == CONST_INT) 3022107590Sobrien { 3023169689Skan if (TARGET_CPU_ZARCH 3024169689Skan && larl_operand (op0, VOIDmode) 3025169689Skan && INTVAL (op1) < (HOST_WIDE_INT)1 << 31 3026169689Skan && INTVAL (op1) >= -((HOST_WIDE_INT)1 << 31)) 3027107590Sobrien { 3028107590Sobrien if (INTVAL (op1) & 1) 3029107590Sobrien { 3030132718Skan /* LARL can't handle odd offsets, so emit a 3031107590Sobrien pair of LARL and LA. */ 3032107590Sobrien rtx temp = reg? reg : gen_reg_rtx (Pmode); 3033107590Sobrien 3034132718Skan if (!DISP_IN_RANGE (INTVAL (op1))) 3035107590Sobrien { 3036169689Skan HOST_WIDE_INT even = INTVAL (op1) - 1; 3037107590Sobrien op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even)); 3038107590Sobrien op0 = gen_rtx_CONST (Pmode, op0); 3039169689Skan op1 = const1_rtx; 3040107590Sobrien } 3041107590Sobrien 3042107590Sobrien emit_move_insn (temp, op0); 3043107590Sobrien new = gen_rtx_PLUS (Pmode, temp, op1); 3044107590Sobrien 3045107590Sobrien if (reg != 0) 3046107590Sobrien { 3047169689Skan s390_load_address (reg, new); 3048107590Sobrien new = reg; 3049107590Sobrien } 3050107590Sobrien } 3051107590Sobrien else 3052107590Sobrien { 3053107590Sobrien /* If the offset is even, we can just use LARL. 3054107590Sobrien This will happen automatically. */ 3055107590Sobrien } 3056107590Sobrien } 3057107590Sobrien else 3058107590Sobrien { 3059132718Skan /* Access local symbols relative to the GOT. */ 3060107590Sobrien 3061107590Sobrien rtx temp = reg? reg : gen_reg_rtx (Pmode); 3062107590Sobrien 3063132718Skan if (reload_in_progress || reload_completed) 3064132718Skan regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; 3065132718Skan 3066132718Skan addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 3067132718Skan UNSPEC_GOTOFF); 3068117395Skan addr = gen_rtx_PLUS (Pmode, addr, op1); 3069117395Skan addr = gen_rtx_CONST (Pmode, addr); 3070117395Skan addr = force_const_mem (Pmode, addr); 3071132718Skan emit_move_insn (temp, addr); 3072107590Sobrien 3073132718Skan new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); 3074107590Sobrien if (reg != 0) 3075107590Sobrien { 3076169689Skan s390_load_address (reg, new); 3077107590Sobrien new = reg; 3078107590Sobrien } 3079107590Sobrien } 3080107590Sobrien } 3081107590Sobrien 3082132718Skan /* Now, check whether it is a GOT relative symbol plus offset 3083107590Sobrien that was pulled out of the literal pool. Force it back in. */ 3084107590Sobrien 3085107590Sobrien else if (GET_CODE (op0) == UNSPEC 3086132718Skan && GET_CODE (op1) == CONST_INT 3087132718Skan && XINT (op0, 1) == UNSPEC_GOTOFF) 3088107590Sobrien { 3089169689Skan gcc_assert (XVECLEN (op0, 0) == 1); 3090107590Sobrien 3091117395Skan new = force_const_mem (Pmode, orig); 3092107590Sobrien } 3093107590Sobrien 3094107590Sobrien /* Otherwise, compute the sum. */ 3095107590Sobrien else 3096107590Sobrien { 3097107590Sobrien base = legitimize_pic_address (XEXP (addr, 0), reg); 3098107590Sobrien new = legitimize_pic_address (XEXP (addr, 1), 3099107590Sobrien base == reg ? NULL_RTX : reg); 3100107590Sobrien if (GET_CODE (new) == CONST_INT) 3101107590Sobrien new = plus_constant (base, INTVAL (new)); 3102107590Sobrien else 3103107590Sobrien { 3104107590Sobrien if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1))) 3105107590Sobrien { 3106107590Sobrien base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0)); 3107107590Sobrien new = XEXP (new, 1); 3108107590Sobrien } 3109107590Sobrien new = gen_rtx_PLUS (Pmode, base, new); 3110107590Sobrien } 3111107590Sobrien 3112107590Sobrien if (GET_CODE (new) == CONST) 3113107590Sobrien new = XEXP (new, 0); 3114107590Sobrien new = force_operand (new, 0); 3115107590Sobrien } 3116107590Sobrien } 3117107590Sobrien } 3118107590Sobrien return new; 3119107590Sobrien} 3120107590Sobrien 3121117395Skan/* Load the thread pointer into a register. */ 3122117395Skan 3123169689Skanrtx 3124169689Skans390_get_thread_pointer (void) 3125117395Skan{ 3126169689Skan rtx tp = gen_reg_rtx (Pmode); 3127117395Skan 3128169689Skan emit_move_insn (tp, gen_rtx_REG (Pmode, TP_REGNUM)); 3129117395Skan mark_reg_pointer (tp, BITS_PER_WORD); 3130117395Skan 3131117395Skan return tp; 3132117395Skan} 3133117395Skan 3134169689Skan/* Emit a tls call insn. The call target is the SYMBOL_REF stored 3135169689Skan in s390_tls_symbol which always refers to __tls_get_offset. 3136169689Skan The returned offset is written to RESULT_REG and an USE rtx is 3137169689Skan generated for TLS_CALL. */ 3138117395Skan 3139117395Skanstatic GTY(()) rtx s390_tls_symbol; 3140169689Skan 3141169689Skanstatic void 3142169689Skans390_emit_tls_call_insn (rtx result_reg, rtx tls_call) 3143117395Skan{ 3144169689Skan rtx insn; 3145169689Skan 3146169689Skan gcc_assert (flag_pic); 3147169689Skan 3148117395Skan if (!s390_tls_symbol) 3149117395Skan s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset"); 3150117395Skan 3151169689Skan insn = s390_emit_call (s390_tls_symbol, tls_call, result_reg, 3152169689Skan gen_rtx_REG (Pmode, RETURN_REGNUM)); 3153169689Skan 3154169689Skan use_reg (&CALL_INSN_FUNCTION_USAGE (insn), result_reg); 3155169689Skan CONST_OR_PURE_CALL_P (insn) = 1; 3156117395Skan} 3157117395Skan 3158117395Skan/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute 3159117395Skan this (thread-local) address. REG may be used as temporary. */ 3160117395Skan 3161117395Skanstatic rtx 3162132718Skanlegitimize_tls_address (rtx addr, rtx reg) 3163117395Skan{ 3164117395Skan rtx new, tls_call, temp, base, r2, insn; 3165117395Skan 3166117395Skan if (GET_CODE (addr) == SYMBOL_REF) 3167117395Skan switch (tls_symbolic_operand (addr)) 3168117395Skan { 3169117395Skan case TLS_MODEL_GLOBAL_DYNAMIC: 3170117395Skan start_sequence (); 3171117395Skan r2 = gen_rtx_REG (Pmode, 2); 3172117395Skan tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_TLSGD); 3173117395Skan new = gen_rtx_CONST (Pmode, tls_call); 3174117395Skan new = force_const_mem (Pmode, new); 3175117395Skan emit_move_insn (r2, new); 3176169689Skan s390_emit_tls_call_insn (r2, tls_call); 3177117395Skan insn = get_insns (); 3178117395Skan end_sequence (); 3179117395Skan 3180117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF); 3181117395Skan temp = gen_reg_rtx (Pmode); 3182117395Skan emit_libcall_block (insn, temp, r2, new); 3183117395Skan 3184169689Skan new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); 3185117395Skan if (reg != 0) 3186117395Skan { 3187117395Skan s390_load_address (reg, new); 3188117395Skan new = reg; 3189117395Skan } 3190117395Skan break; 3191117395Skan 3192117395Skan case TLS_MODEL_LOCAL_DYNAMIC: 3193117395Skan start_sequence (); 3194117395Skan r2 = gen_rtx_REG (Pmode, 2); 3195117395Skan tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM); 3196117395Skan new = gen_rtx_CONST (Pmode, tls_call); 3197117395Skan new = force_const_mem (Pmode, new); 3198117395Skan emit_move_insn (r2, new); 3199169689Skan s390_emit_tls_call_insn (r2, tls_call); 3200117395Skan insn = get_insns (); 3201117395Skan end_sequence (); 3202117395Skan 3203117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM_NTPOFF); 3204117395Skan temp = gen_reg_rtx (Pmode); 3205117395Skan emit_libcall_block (insn, temp, r2, new); 3206117395Skan 3207169689Skan new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); 3208117395Skan base = gen_reg_rtx (Pmode); 3209117395Skan s390_load_address (base, new); 3210117395Skan 3211117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_DTPOFF); 3212117395Skan new = gen_rtx_CONST (Pmode, new); 3213117395Skan new = force_const_mem (Pmode, new); 3214117395Skan temp = gen_reg_rtx (Pmode); 3215117395Skan emit_move_insn (temp, new); 3216117395Skan 3217117395Skan new = gen_rtx_PLUS (Pmode, base, temp); 3218117395Skan if (reg != 0) 3219117395Skan { 3220117395Skan s390_load_address (reg, new); 3221117395Skan new = reg; 3222117395Skan } 3223117395Skan break; 3224117395Skan 3225117395Skan case TLS_MODEL_INITIAL_EXEC: 3226117395Skan if (flag_pic == 1) 3227117395Skan { 3228117395Skan /* Assume GOT offset < 4k. This is handled the same way 3229117395Skan in both 31- and 64-bit code. */ 3230117395Skan 3231117395Skan if (reload_in_progress || reload_completed) 3232117395Skan regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; 3233117395Skan 3234117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF); 3235117395Skan new = gen_rtx_CONST (Pmode, new); 3236117395Skan new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); 3237169689Skan new = gen_const_mem (Pmode, new); 3238117395Skan temp = gen_reg_rtx (Pmode); 3239117395Skan emit_move_insn (temp, new); 3240117395Skan } 3241132718Skan else if (TARGET_CPU_ZARCH) 3242117395Skan { 3243117395Skan /* If the GOT offset might be >= 4k, we determine the position 3244117395Skan of the GOT entry via a PC-relative LARL. */ 3245117395Skan 3246117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF); 3247117395Skan new = gen_rtx_CONST (Pmode, new); 3248117395Skan temp = gen_reg_rtx (Pmode); 3249117395Skan emit_move_insn (temp, new); 3250117395Skan 3251169689Skan new = gen_const_mem (Pmode, temp); 3252117395Skan temp = gen_reg_rtx (Pmode); 3253117395Skan emit_move_insn (temp, new); 3254117395Skan } 3255117395Skan else if (flag_pic) 3256117395Skan { 3257132718Skan /* If the GOT offset might be >= 4k, we have to load it 3258117395Skan from the literal pool. */ 3259117395Skan 3260117395Skan if (reload_in_progress || reload_completed) 3261117395Skan regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; 3262117395Skan 3263117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF); 3264117395Skan new = gen_rtx_CONST (Pmode, new); 3265117395Skan new = force_const_mem (Pmode, new); 3266117395Skan temp = gen_reg_rtx (Pmode); 3267117395Skan emit_move_insn (temp, new); 3268117395Skan 3269117395Skan new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); 3270169689Skan new = gen_const_mem (Pmode, new); 3271117395Skan 3272117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD); 3273117395Skan temp = gen_reg_rtx (Pmode); 3274117395Skan emit_insn (gen_rtx_SET (Pmode, temp, new)); 3275117395Skan } 3276117395Skan else 3277117395Skan { 3278117395Skan /* In position-dependent code, load the absolute address of 3279117395Skan the GOT entry from the literal pool. */ 3280117395Skan 3281117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF); 3282117395Skan new = gen_rtx_CONST (Pmode, new); 3283117395Skan new = force_const_mem (Pmode, new); 3284117395Skan temp = gen_reg_rtx (Pmode); 3285117395Skan emit_move_insn (temp, new); 3286117395Skan 3287117395Skan new = temp; 3288169689Skan new = gen_const_mem (Pmode, new); 3289117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD); 3290117395Skan temp = gen_reg_rtx (Pmode); 3291117395Skan emit_insn (gen_rtx_SET (Pmode, temp, new)); 3292117395Skan } 3293117395Skan 3294169689Skan new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); 3295117395Skan if (reg != 0) 3296117395Skan { 3297117395Skan s390_load_address (reg, new); 3298117395Skan new = reg; 3299117395Skan } 3300117395Skan break; 3301117395Skan 3302117395Skan case TLS_MODEL_LOCAL_EXEC: 3303117395Skan new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF); 3304117395Skan new = gen_rtx_CONST (Pmode, new); 3305117395Skan new = force_const_mem (Pmode, new); 3306117395Skan temp = gen_reg_rtx (Pmode); 3307117395Skan emit_move_insn (temp, new); 3308117395Skan 3309169689Skan new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); 3310117395Skan if (reg != 0) 3311117395Skan { 3312117395Skan s390_load_address (reg, new); 3313117395Skan new = reg; 3314117395Skan } 3315117395Skan break; 3316117395Skan 3317117395Skan default: 3318169689Skan gcc_unreachable (); 3319117395Skan } 3320117395Skan 3321117395Skan else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == UNSPEC) 3322117395Skan { 3323117395Skan switch (XINT (XEXP (addr, 0), 1)) 3324117395Skan { 3325117395Skan case UNSPEC_INDNTPOFF: 3326169689Skan gcc_assert (TARGET_CPU_ZARCH); 3327169689Skan new = addr; 3328117395Skan break; 3329117395Skan 3330117395Skan default: 3331169689Skan gcc_unreachable (); 3332117395Skan } 3333117395Skan } 3334117395Skan 3335169689Skan else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS 3336169689Skan && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT) 3337169689Skan { 3338169689Skan new = XEXP (XEXP (addr, 0), 0); 3339169689Skan if (GET_CODE (new) != SYMBOL_REF) 3340169689Skan new = gen_rtx_CONST (Pmode, new); 3341169689Skan 3342169689Skan new = legitimize_tls_address (new, reg); 3343169689Skan new = plus_constant (new, INTVAL (XEXP (XEXP (addr, 0), 1))); 3344169689Skan new = force_operand (new, 0); 3345169689Skan } 3346169689Skan 3347117395Skan else 3348169689Skan gcc_unreachable (); /* for now ... */ 3349117395Skan 3350117395Skan return new; 3351117395Skan} 3352117395Skan 3353107590Sobrien/* Emit insns to move operands[1] into operands[0]. */ 3354107590Sobrien 3355107590Sobrienvoid 3356132718Skanemit_symbolic_move (rtx *operands) 3357107590Sobrien{ 3358107590Sobrien rtx temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); 3359107590Sobrien 3360117395Skan if (GET_CODE (operands[0]) == MEM) 3361107590Sobrien operands[1] = force_reg (Pmode, operands[1]); 3362117395Skan else if (TLS_SYMBOLIC_CONST (operands[1])) 3363117395Skan operands[1] = legitimize_tls_address (operands[1], temp); 3364117395Skan else if (flag_pic) 3365107590Sobrien operands[1] = legitimize_pic_address (operands[1], temp); 3366107590Sobrien} 3367107590Sobrien 3368107590Sobrien/* Try machine-dependent ways of modifying an illegitimate address X 3369107590Sobrien to be legitimate. If we find one, return the new, valid address. 3370107590Sobrien 3371107590Sobrien OLDX is the address as it was before break_out_memory_refs was called. 3372107590Sobrien In some cases it is useful to look at this to decide what needs to be done. 3373107590Sobrien 3374107590Sobrien MODE is the mode of the operand pointed to by X. 3375107590Sobrien 3376107590Sobrien When -fpic is used, special handling is needed for symbolic references. 3377107590Sobrien See comments by legitimize_pic_address for details. */ 3378107590Sobrien 3379107590Sobrienrtx 3380169689Skanlegitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, 3381132718Skan enum machine_mode mode ATTRIBUTE_UNUSED) 3382107590Sobrien{ 3383107590Sobrien rtx constant_term = const0_rtx; 3384107590Sobrien 3385117395Skan if (TLS_SYMBOLIC_CONST (x)) 3386107590Sobrien { 3387117395Skan x = legitimize_tls_address (x, 0); 3388117395Skan 3389117395Skan if (legitimate_address_p (mode, x, FALSE)) 3390117395Skan return x; 3391117395Skan } 3392169689Skan else if (GET_CODE (x) == PLUS 3393169689Skan && (TLS_SYMBOLIC_CONST (XEXP (x, 0)) 3394169689Skan || TLS_SYMBOLIC_CONST (XEXP (x, 1)))) 3395169689Skan { 3396169689Skan return x; 3397169689Skan } 3398117395Skan else if (flag_pic) 3399117395Skan { 3400107590Sobrien if (SYMBOLIC_CONST (x) 3401132718Skan || (GET_CODE (x) == PLUS 3402132718Skan && (SYMBOLIC_CONST (XEXP (x, 0)) 3403107590Sobrien || SYMBOLIC_CONST (XEXP (x, 1))))) 3404107590Sobrien x = legitimize_pic_address (x, 0); 3405107590Sobrien 3406107590Sobrien if (legitimate_address_p (mode, x, FALSE)) 3407107590Sobrien return x; 3408107590Sobrien } 3409107590Sobrien 3410107590Sobrien x = eliminate_constant_term (x, &constant_term); 3411107590Sobrien 3412117395Skan /* Optimize loading of large displacements by splitting them 3413117395Skan into the multiple of 4K and the rest; this allows the 3414132718Skan former to be CSE'd if possible. 3415117395Skan 3416117395Skan Don't do this if the displacement is added to a register 3417117395Skan pointing into the stack frame, as the offsets will 3418117395Skan change later anyway. */ 3419117395Skan 3420117395Skan if (GET_CODE (constant_term) == CONST_INT 3421132718Skan && !TARGET_LONG_DISPLACEMENT 3422132718Skan && !DISP_IN_RANGE (INTVAL (constant_term)) 3423117395Skan && !(REG_P (x) && REGNO_PTR_FRAME_P (REGNO (x)))) 3424117395Skan { 3425117395Skan HOST_WIDE_INT lower = INTVAL (constant_term) & 0xfff; 3426117395Skan HOST_WIDE_INT upper = INTVAL (constant_term) ^ lower; 3427117395Skan 3428117395Skan rtx temp = gen_reg_rtx (Pmode); 3429117395Skan rtx val = force_operand (GEN_INT (upper), temp); 3430117395Skan if (val != temp) 3431117395Skan emit_move_insn (temp, val); 3432117395Skan 3433117395Skan x = gen_rtx_PLUS (Pmode, x, temp); 3434117395Skan constant_term = GEN_INT (lower); 3435117395Skan } 3436117395Skan 3437107590Sobrien if (GET_CODE (x) == PLUS) 3438107590Sobrien { 3439107590Sobrien if (GET_CODE (XEXP (x, 0)) == REG) 3440107590Sobrien { 3441169689Skan rtx temp = gen_reg_rtx (Pmode); 3442169689Skan rtx val = force_operand (XEXP (x, 1), temp); 3443107590Sobrien if (val != temp) 3444107590Sobrien emit_move_insn (temp, val); 3445107590Sobrien 3446107590Sobrien x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp); 3447107590Sobrien } 3448107590Sobrien 3449107590Sobrien else if (GET_CODE (XEXP (x, 1)) == REG) 3450107590Sobrien { 3451169689Skan rtx temp = gen_reg_rtx (Pmode); 3452169689Skan rtx val = force_operand (XEXP (x, 0), temp); 3453107590Sobrien if (val != temp) 3454107590Sobrien emit_move_insn (temp, val); 3455107590Sobrien 3456107590Sobrien x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1)); 3457107590Sobrien } 3458107590Sobrien } 3459107590Sobrien 3460107590Sobrien if (constant_term != const0_rtx) 3461107590Sobrien x = gen_rtx_PLUS (Pmode, x, constant_term); 3462107590Sobrien 3463107590Sobrien return x; 3464107590Sobrien} 3465107590Sobrien 3466169689Skan/* Try a machine-dependent way of reloading an illegitimate address AD 3467169689Skan operand. If we find one, push the reload and and return the new address. 3468169689Skan 3469169689Skan MODE is the mode of the enclosing MEM. OPNUM is the operand number 3470169689Skan and TYPE is the reload type of the current reload. */ 3471169689Skan 3472169689Skanrtx 3473169689Skanlegitimize_reload_address (rtx ad, enum machine_mode mode ATTRIBUTE_UNUSED, 3474169689Skan int opnum, int type) 3475169689Skan{ 3476169689Skan if (!optimize || TARGET_LONG_DISPLACEMENT) 3477169689Skan return NULL_RTX; 3478169689Skan 3479169689Skan if (GET_CODE (ad) == PLUS) 3480169689Skan { 3481169689Skan rtx tem = simplify_binary_operation (PLUS, Pmode, 3482169689Skan XEXP (ad, 0), XEXP (ad, 1)); 3483169689Skan if (tem) 3484169689Skan ad = tem; 3485169689Skan } 3486169689Skan 3487169689Skan if (GET_CODE (ad) == PLUS 3488169689Skan && GET_CODE (XEXP (ad, 0)) == REG 3489169689Skan && GET_CODE (XEXP (ad, 1)) == CONST_INT 3490169689Skan && !DISP_IN_RANGE (INTVAL (XEXP (ad, 1)))) 3491169689Skan { 3492169689Skan HOST_WIDE_INT lower = INTVAL (XEXP (ad, 1)) & 0xfff; 3493169689Skan HOST_WIDE_INT upper = INTVAL (XEXP (ad, 1)) ^ lower; 3494169689Skan rtx cst, tem, new; 3495169689Skan 3496169689Skan cst = GEN_INT (upper); 3497169689Skan if (!legitimate_reload_constant_p (cst)) 3498169689Skan cst = force_const_mem (Pmode, cst); 3499169689Skan 3500169689Skan tem = gen_rtx_PLUS (Pmode, XEXP (ad, 0), cst); 3501169689Skan new = gen_rtx_PLUS (Pmode, tem, GEN_INT (lower)); 3502169689Skan 3503169689Skan push_reload (XEXP (tem, 1), 0, &XEXP (tem, 1), 0, 3504169689Skan BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, 3505169689Skan opnum, (enum reload_type) type); 3506169689Skan return new; 3507169689Skan } 3508169689Skan 3509169689Skan return NULL_RTX; 3510169689Skan} 3511169689Skan 3512117395Skan/* Emit code to move LEN bytes from DST to SRC. */ 3513117395Skan 3514117395Skanvoid 3515169689Skans390_expand_movmem (rtx dst, rtx src, rtx len) 3516117395Skan{ 3517117395Skan if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256) 3518117395Skan { 3519117395Skan if (INTVAL (len) > 0) 3520169689Skan emit_insn (gen_movmem_short (dst, src, GEN_INT (INTVAL (len) - 1))); 3521117395Skan } 3522117395Skan 3523117395Skan else if (TARGET_MVCLE) 3524117395Skan { 3525169689Skan emit_insn (gen_movmem_long (dst, src, convert_to_mode (Pmode, len, 1))); 3526117395Skan } 3527117395Skan 3528117395Skan else 3529117395Skan { 3530117395Skan rtx dst_addr, src_addr, count, blocks, temp; 3531169689Skan rtx loop_start_label = gen_label_rtx (); 3532169689Skan rtx loop_end_label = gen_label_rtx (); 3533117395Skan rtx end_label = gen_label_rtx (); 3534117395Skan enum machine_mode mode; 3535117395Skan 3536117395Skan mode = GET_MODE (len); 3537117395Skan if (mode == VOIDmode) 3538132718Skan mode = Pmode; 3539117395Skan 3540117395Skan dst_addr = gen_reg_rtx (Pmode); 3541117395Skan src_addr = gen_reg_rtx (Pmode); 3542117395Skan count = gen_reg_rtx (mode); 3543117395Skan blocks = gen_reg_rtx (mode); 3544117395Skan 3545117395Skan convert_move (count, len, 1); 3546132718Skan emit_cmp_and_jump_insns (count, const0_rtx, 3547117395Skan EQ, NULL_RTX, mode, 1, end_label); 3548117395Skan 3549117395Skan emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX)); 3550117395Skan emit_move_insn (src_addr, force_operand (XEXP (src, 0), NULL_RTX)); 3551117395Skan dst = change_address (dst, VOIDmode, dst_addr); 3552117395Skan src = change_address (src, VOIDmode, src_addr); 3553132718Skan 3554117395Skan temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0); 3555117395Skan if (temp != count) 3556117395Skan emit_move_insn (count, temp); 3557117395Skan 3558169689Skan temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, 0); 3559117395Skan if (temp != blocks) 3560117395Skan emit_move_insn (blocks, temp); 3561117395Skan 3562169689Skan emit_cmp_and_jump_insns (blocks, const0_rtx, 3563169689Skan EQ, NULL_RTX, mode, 1, loop_end_label); 3564117395Skan 3565169689Skan emit_label (loop_start_label); 3566169689Skan 3567169689Skan emit_insn (gen_movmem_short (dst, src, GEN_INT (255))); 3568132718Skan s390_load_address (dst_addr, 3569117395Skan gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256))); 3570132718Skan s390_load_address (src_addr, 3571117395Skan gen_rtx_PLUS (Pmode, src_addr, GEN_INT (256))); 3572132718Skan 3573117395Skan temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0); 3574117395Skan if (temp != blocks) 3575117395Skan emit_move_insn (blocks, temp); 3576117395Skan 3577169689Skan emit_cmp_and_jump_insns (blocks, const0_rtx, 3578169689Skan EQ, NULL_RTX, mode, 1, loop_end_label); 3579117395Skan 3580169689Skan emit_jump (loop_start_label); 3581169689Skan emit_label (loop_end_label); 3582169689Skan 3583169689Skan emit_insn (gen_movmem_short (dst, src, 3584132718Skan convert_to_mode (Pmode, count, 1))); 3585117395Skan emit_label (end_label); 3586117395Skan } 3587117395Skan} 3588117395Skan 3589169689Skan/* Emit code to set LEN bytes at DST to VAL. 3590169689Skan Make use of clrmem if VAL is zero. */ 3591117395Skan 3592117395Skanvoid 3593169689Skans390_expand_setmem (rtx dst, rtx len, rtx val) 3594117395Skan{ 3595169689Skan if (GET_CODE (len) == CONST_INT && INTVAL (len) == 0) 3596169689Skan return; 3597169689Skan 3598169689Skan gcc_assert (GET_CODE (val) == CONST_INT || GET_MODE (val) == QImode); 3599169689Skan 3600169689Skan if (GET_CODE (len) == CONST_INT && INTVAL (len) > 0 && INTVAL (len) <= 257) 3601117395Skan { 3602169689Skan if (val == const0_rtx && INTVAL (len) <= 256) 3603169689Skan emit_insn (gen_clrmem_short (dst, GEN_INT (INTVAL (len) - 1))); 3604169689Skan else 3605169689Skan { 3606169689Skan /* Initialize memory by storing the first byte. */ 3607169689Skan emit_move_insn (adjust_address (dst, QImode, 0), val); 3608169689Skan 3609169689Skan if (INTVAL (len) > 1) 3610169689Skan { 3611169689Skan /* Initiate 1 byte overlap move. 3612169689Skan The first byte of DST is propagated through DSTP1. 3613169689Skan Prepare a movmem for: DST+1 = DST (length = LEN - 1). 3614169689Skan DST is set to size 1 so the rest of the memory location 3615169689Skan does not count as source operand. */ 3616169689Skan rtx dstp1 = adjust_address (dst, VOIDmode, 1); 3617169689Skan set_mem_size (dst, const1_rtx); 3618169689Skan 3619169689Skan emit_insn (gen_movmem_short (dstp1, dst, 3620169689Skan GEN_INT (INTVAL (len) - 2))); 3621169689Skan } 3622169689Skan } 3623117395Skan } 3624117395Skan 3625117395Skan else if (TARGET_MVCLE) 3626117395Skan { 3627169689Skan val = force_not_mem (convert_modes (Pmode, QImode, val, 1)); 3628169689Skan emit_insn (gen_setmem_long (dst, convert_to_mode (Pmode, len, 1), val)); 3629117395Skan } 3630117395Skan 3631117395Skan else 3632117395Skan { 3633169689Skan rtx dst_addr, src_addr, count, blocks, temp, dstp1 = NULL_RTX; 3634169689Skan rtx loop_start_label = gen_label_rtx (); 3635169689Skan rtx loop_end_label = gen_label_rtx (); 3636117395Skan rtx end_label = gen_label_rtx (); 3637117395Skan enum machine_mode mode; 3638117395Skan 3639117395Skan mode = GET_MODE (len); 3640117395Skan if (mode == VOIDmode) 3641132718Skan mode = Pmode; 3642117395Skan 3643117395Skan dst_addr = gen_reg_rtx (Pmode); 3644117395Skan src_addr = gen_reg_rtx (Pmode); 3645117395Skan count = gen_reg_rtx (mode); 3646117395Skan blocks = gen_reg_rtx (mode); 3647117395Skan 3648117395Skan convert_move (count, len, 1); 3649132718Skan emit_cmp_and_jump_insns (count, const0_rtx, 3650117395Skan EQ, NULL_RTX, mode, 1, end_label); 3651117395Skan 3652117395Skan emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX)); 3653117395Skan dst = change_address (dst, VOIDmode, dst_addr); 3654132718Skan 3655169689Skan if (val == const0_rtx) 3656169689Skan temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0); 3657169689Skan else 3658169689Skan { 3659169689Skan dstp1 = adjust_address (dst, VOIDmode, 1); 3660169689Skan set_mem_size (dst, const1_rtx); 3661169689Skan 3662169689Skan /* Initialize memory by storing the first byte. */ 3663169689Skan emit_move_insn (adjust_address (dst, QImode, 0), val); 3664169689Skan 3665169689Skan /* If count is 1 we are done. */ 3666169689Skan emit_cmp_and_jump_insns (count, const1_rtx, 3667169689Skan EQ, NULL_RTX, mode, 1, end_label); 3668169689Skan 3669169689Skan temp = expand_binop (mode, add_optab, count, GEN_INT (-2), count, 1, 0); 3670169689Skan } 3671117395Skan if (temp != count) 3672117395Skan emit_move_insn (count, temp); 3673117395Skan 3674169689Skan temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, 0); 3675117395Skan if (temp != blocks) 3676117395Skan emit_move_insn (blocks, temp); 3677117395Skan 3678169689Skan emit_cmp_and_jump_insns (blocks, const0_rtx, 3679169689Skan EQ, NULL_RTX, mode, 1, loop_end_label); 3680117395Skan 3681169689Skan emit_label (loop_start_label); 3682169689Skan 3683169689Skan if (val == const0_rtx) 3684169689Skan emit_insn (gen_clrmem_short (dst, GEN_INT (255))); 3685169689Skan else 3686169689Skan emit_insn (gen_movmem_short (dstp1, dst, GEN_INT (255))); 3687132718Skan s390_load_address (dst_addr, 3688117395Skan gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256))); 3689132718Skan 3690117395Skan temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0); 3691117395Skan if (temp != blocks) 3692117395Skan emit_move_insn (blocks, temp); 3693117395Skan 3694169689Skan emit_cmp_and_jump_insns (blocks, const0_rtx, 3695169689Skan EQ, NULL_RTX, mode, 1, loop_end_label); 3696117395Skan 3697169689Skan emit_jump (loop_start_label); 3698169689Skan emit_label (loop_end_label); 3699169689Skan 3700169689Skan if (val == const0_rtx) 3701169689Skan emit_insn (gen_clrmem_short (dst, convert_to_mode (Pmode, count, 1))); 3702169689Skan else 3703169689Skan emit_insn (gen_movmem_short (dstp1, dst, convert_to_mode (Pmode, count, 1))); 3704117395Skan emit_label (end_label); 3705117395Skan } 3706117395Skan} 3707117395Skan 3708117395Skan/* Emit code to compare LEN bytes at OP0 with those at OP1, 3709117395Skan and return the result in TARGET. */ 3710117395Skan 3711117395Skanvoid 3712132718Skans390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len) 3713117395Skan{ 3714169689Skan rtx ccreg = gen_rtx_REG (CCUmode, CC_REGNUM); 3715169689Skan rtx tmp; 3716117395Skan 3717169689Skan /* As the result of CMPINT is inverted compared to what we need, 3718169689Skan we have to swap the operands. */ 3719169689Skan tmp = op0; op0 = op1; op1 = tmp; 3720117395Skan 3721117395Skan if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256) 3722117395Skan { 3723117395Skan if (INTVAL (len) > 0) 3724117395Skan { 3725132718Skan emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (INTVAL (len) - 1))); 3726169689Skan emit_insn (gen_cmpint (target, ccreg)); 3727117395Skan } 3728117395Skan else 3729117395Skan emit_move_insn (target, const0_rtx); 3730117395Skan } 3731169689Skan else if (TARGET_MVCLE) 3732117395Skan { 3733132718Skan emit_insn (gen_cmpmem_long (op0, op1, convert_to_mode (Pmode, len, 1))); 3734169689Skan emit_insn (gen_cmpint (target, ccreg)); 3735117395Skan } 3736117395Skan else 3737117395Skan { 3738117395Skan rtx addr0, addr1, count, blocks, temp; 3739169689Skan rtx loop_start_label = gen_label_rtx (); 3740169689Skan rtx loop_end_label = gen_label_rtx (); 3741117395Skan rtx end_label = gen_label_rtx (); 3742117395Skan enum machine_mode mode; 3743117395Skan 3744117395Skan mode = GET_MODE (len); 3745117395Skan if (mode == VOIDmode) 3746132718Skan mode = Pmode; 3747117395Skan 3748117395Skan addr0 = gen_reg_rtx (Pmode); 3749117395Skan addr1 = gen_reg_rtx (Pmode); 3750117395Skan count = gen_reg_rtx (mode); 3751117395Skan blocks = gen_reg_rtx (mode); 3752117395Skan 3753117395Skan convert_move (count, len, 1); 3754132718Skan emit_cmp_and_jump_insns (count, const0_rtx, 3755117395Skan EQ, NULL_RTX, mode, 1, end_label); 3756117395Skan 3757117395Skan emit_move_insn (addr0, force_operand (XEXP (op0, 0), NULL_RTX)); 3758117395Skan emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX)); 3759117395Skan op0 = change_address (op0, VOIDmode, addr0); 3760117395Skan op1 = change_address (op1, VOIDmode, addr1); 3761132718Skan 3762117395Skan temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0); 3763117395Skan if (temp != count) 3764117395Skan emit_move_insn (count, temp); 3765117395Skan 3766169689Skan temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, 0); 3767117395Skan if (temp != blocks) 3768117395Skan emit_move_insn (blocks, temp); 3769117395Skan 3770169689Skan emit_cmp_and_jump_insns (blocks, const0_rtx, 3771169689Skan EQ, NULL_RTX, mode, 1, loop_end_label); 3772117395Skan 3773169689Skan emit_label (loop_start_label); 3774169689Skan 3775132718Skan emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255))); 3776169689Skan temp = gen_rtx_NE (VOIDmode, ccreg, const0_rtx); 3777132718Skan temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp, 3778117395Skan gen_rtx_LABEL_REF (VOIDmode, end_label), pc_rtx); 3779117395Skan temp = gen_rtx_SET (VOIDmode, pc_rtx, temp); 3780117395Skan emit_jump_insn (temp); 3781117395Skan 3782132718Skan s390_load_address (addr0, 3783117395Skan gen_rtx_PLUS (Pmode, addr0, GEN_INT (256))); 3784132718Skan s390_load_address (addr1, 3785117395Skan gen_rtx_PLUS (Pmode, addr1, GEN_INT (256))); 3786132718Skan 3787117395Skan temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0); 3788117395Skan if (temp != blocks) 3789117395Skan emit_move_insn (blocks, temp); 3790117395Skan 3791169689Skan emit_cmp_and_jump_insns (blocks, const0_rtx, 3792169689Skan EQ, NULL_RTX, mode, 1, loop_end_label); 3793117395Skan 3794169689Skan emit_jump (loop_start_label); 3795169689Skan emit_label (loop_end_label); 3796169689Skan 3797169689Skan emit_insn (gen_cmpmem_short (op0, op1, 3798132718Skan convert_to_mode (Pmode, count, 1))); 3799117395Skan emit_label (end_label); 3800117395Skan 3801169689Skan emit_insn (gen_cmpint (target, ccreg)); 3802117395Skan } 3803117395Skan} 3804117395Skan 3805169689Skan 3806169689Skan/* Expand conditional increment or decrement using alc/slb instructions. 3807169689Skan Should generate code setting DST to either SRC or SRC + INCREMENT, 3808169689Skan depending on the result of the comparison CMP_OP0 CMP_CODE CMP_OP1. 3809169689Skan Returns true if successful, false otherwise. 3810169689Skan 3811169689Skan That makes it possible to implement some if-constructs without jumps e.g.: 3812169689Skan (borrow = CC0 | CC1 and carry = CC2 | CC3) 3813169689Skan unsigned int a, b, c; 3814169689Skan if (a < b) c++; -> CCU b > a -> CC2; c += carry; 3815169689Skan if (a < b) c--; -> CCL3 a - b -> borrow; c -= borrow; 3816169689Skan if (a <= b) c++; -> CCL3 b - a -> borrow; c += carry; 3817169689Skan if (a <= b) c--; -> CCU a <= b -> borrow; c -= borrow; 3818169689Skan 3819169689Skan Checks for EQ and NE with a nonzero value need an additional xor e.g.: 3820169689Skan if (a == b) c++; -> CCL3 a ^= b; 0 - a -> borrow; c += carry; 3821169689Skan if (a == b) c--; -> CCU a ^= b; a <= 0 -> CC0 | CC1; c -= borrow; 3822169689Skan if (a != b) c++; -> CCU a ^= b; a > 0 -> CC2; c += carry; 3823169689Skan if (a != b) c--; -> CCL3 a ^= b; 0 - a -> borrow; c -= borrow; */ 3824169689Skan 3825169689Skanbool 3826169689Skans390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1, 3827169689Skan rtx dst, rtx src, rtx increment) 3828169689Skan{ 3829169689Skan enum machine_mode cmp_mode; 3830169689Skan enum machine_mode cc_mode; 3831169689Skan rtx op_res; 3832169689Skan rtx insn; 3833169689Skan rtvec p; 3834169689Skan int ret; 3835169689Skan 3836169689Skan if ((GET_MODE (cmp_op0) == SImode || GET_MODE (cmp_op0) == VOIDmode) 3837169689Skan && (GET_MODE (cmp_op1) == SImode || GET_MODE (cmp_op1) == VOIDmode)) 3838169689Skan cmp_mode = SImode; 3839169689Skan else if ((GET_MODE (cmp_op0) == DImode || GET_MODE (cmp_op0) == VOIDmode) 3840169689Skan && (GET_MODE (cmp_op1) == DImode || GET_MODE (cmp_op1) == VOIDmode)) 3841169689Skan cmp_mode = DImode; 3842169689Skan else 3843169689Skan return false; 3844169689Skan 3845169689Skan /* Try ADD LOGICAL WITH CARRY. */ 3846169689Skan if (increment == const1_rtx) 3847169689Skan { 3848169689Skan /* Determine CC mode to use. */ 3849169689Skan if (cmp_code == EQ || cmp_code == NE) 3850169689Skan { 3851169689Skan if (cmp_op1 != const0_rtx) 3852169689Skan { 3853169689Skan cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1, 3854169689Skan NULL_RTX, 0, OPTAB_WIDEN); 3855169689Skan cmp_op1 = const0_rtx; 3856169689Skan } 3857169689Skan 3858169689Skan cmp_code = cmp_code == EQ ? LEU : GTU; 3859169689Skan } 3860169689Skan 3861169689Skan if (cmp_code == LTU || cmp_code == LEU) 3862169689Skan { 3863169689Skan rtx tem = cmp_op0; 3864169689Skan cmp_op0 = cmp_op1; 3865169689Skan cmp_op1 = tem; 3866169689Skan cmp_code = swap_condition (cmp_code); 3867169689Skan } 3868169689Skan 3869169689Skan switch (cmp_code) 3870169689Skan { 3871169689Skan case GTU: 3872169689Skan cc_mode = CCUmode; 3873169689Skan break; 3874169689Skan 3875169689Skan case GEU: 3876169689Skan cc_mode = CCL3mode; 3877169689Skan break; 3878169689Skan 3879169689Skan default: 3880169689Skan return false; 3881169689Skan } 3882169689Skan 3883169689Skan /* Emit comparison instruction pattern. */ 3884169689Skan if (!register_operand (cmp_op0, cmp_mode)) 3885169689Skan cmp_op0 = force_reg (cmp_mode, cmp_op0); 3886169689Skan 3887169689Skan insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), 3888169689Skan gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); 3889169689Skan /* We use insn_invalid_p here to add clobbers if required. */ 3890169689Skan ret = insn_invalid_p (emit_insn (insn)); 3891169689Skan gcc_assert (!ret); 3892169689Skan 3893169689Skan /* Emit ALC instruction pattern. */ 3894169689Skan op_res = gen_rtx_fmt_ee (cmp_code, GET_MODE (dst), 3895169689Skan gen_rtx_REG (cc_mode, CC_REGNUM), 3896169689Skan const0_rtx); 3897169689Skan 3898169689Skan if (src != const0_rtx) 3899169689Skan { 3900169689Skan if (!register_operand (src, GET_MODE (dst))) 3901169689Skan src = force_reg (GET_MODE (dst), src); 3902169689Skan 3903169689Skan src = gen_rtx_PLUS (GET_MODE (dst), src, const0_rtx); 3904169689Skan op_res = gen_rtx_PLUS (GET_MODE (dst), src, op_res); 3905169689Skan } 3906169689Skan 3907169689Skan p = rtvec_alloc (2); 3908169689Skan RTVEC_ELT (p, 0) = 3909169689Skan gen_rtx_SET (VOIDmode, dst, op_res); 3910169689Skan RTVEC_ELT (p, 1) = 3911169689Skan gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); 3912169689Skan emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); 3913169689Skan 3914169689Skan return true; 3915169689Skan } 3916169689Skan 3917169689Skan /* Try SUBTRACT LOGICAL WITH BORROW. */ 3918169689Skan if (increment == constm1_rtx) 3919169689Skan { 3920169689Skan /* Determine CC mode to use. */ 3921169689Skan if (cmp_code == EQ || cmp_code == NE) 3922169689Skan { 3923169689Skan if (cmp_op1 != const0_rtx) 3924169689Skan { 3925169689Skan cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1, 3926169689Skan NULL_RTX, 0, OPTAB_WIDEN); 3927169689Skan cmp_op1 = const0_rtx; 3928169689Skan } 3929169689Skan 3930169689Skan cmp_code = cmp_code == EQ ? LEU : GTU; 3931169689Skan } 3932169689Skan 3933169689Skan if (cmp_code == GTU || cmp_code == GEU) 3934169689Skan { 3935169689Skan rtx tem = cmp_op0; 3936169689Skan cmp_op0 = cmp_op1; 3937169689Skan cmp_op1 = tem; 3938169689Skan cmp_code = swap_condition (cmp_code); 3939169689Skan } 3940169689Skan 3941169689Skan switch (cmp_code) 3942169689Skan { 3943169689Skan case LEU: 3944169689Skan cc_mode = CCUmode; 3945169689Skan break; 3946169689Skan 3947169689Skan case LTU: 3948169689Skan cc_mode = CCL3mode; 3949169689Skan break; 3950169689Skan 3951169689Skan default: 3952169689Skan return false; 3953169689Skan } 3954169689Skan 3955169689Skan /* Emit comparison instruction pattern. */ 3956169689Skan if (!register_operand (cmp_op0, cmp_mode)) 3957169689Skan cmp_op0 = force_reg (cmp_mode, cmp_op0); 3958169689Skan 3959169689Skan insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), 3960169689Skan gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); 3961169689Skan /* We use insn_invalid_p here to add clobbers if required. */ 3962169689Skan ret = insn_invalid_p (emit_insn (insn)); 3963169689Skan gcc_assert (!ret); 3964169689Skan 3965169689Skan /* Emit SLB instruction pattern. */ 3966169689Skan if (!register_operand (src, GET_MODE (dst))) 3967169689Skan src = force_reg (GET_MODE (dst), src); 3968169689Skan 3969169689Skan op_res = gen_rtx_MINUS (GET_MODE (dst), 3970169689Skan gen_rtx_MINUS (GET_MODE (dst), src, const0_rtx), 3971169689Skan gen_rtx_fmt_ee (cmp_code, GET_MODE (dst), 3972169689Skan gen_rtx_REG (cc_mode, CC_REGNUM), 3973169689Skan const0_rtx)); 3974169689Skan p = rtvec_alloc (2); 3975169689Skan RTVEC_ELT (p, 0) = 3976169689Skan gen_rtx_SET (VOIDmode, dst, op_res); 3977169689Skan RTVEC_ELT (p, 1) = 3978169689Skan gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); 3979169689Skan emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); 3980169689Skan 3981169689Skan return true; 3982169689Skan } 3983169689Skan 3984169689Skan return false; 3985169689Skan} 3986169689Skan 3987169689Skan/* Expand code for the insv template. Return true if successful, false else. */ 3988169689Skan 3989169689Skanbool 3990169689Skans390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src) 3991169689Skan{ 3992169689Skan int bitsize = INTVAL (op1); 3993169689Skan int bitpos = INTVAL (op2); 3994169689Skan 3995169689Skan /* We need byte alignment. */ 3996169689Skan if (bitsize % BITS_PER_UNIT) 3997169689Skan return false; 3998169689Skan 3999169689Skan if (bitpos == 0 4000169689Skan && memory_operand (dest, VOIDmode) 4001169689Skan && (register_operand (src, word_mode) 4002169689Skan || const_int_operand (src, VOIDmode))) 4003169689Skan { 4004169689Skan /* Emit standard pattern if possible. */ 4005169689Skan enum machine_mode mode = smallest_mode_for_size (bitsize, MODE_INT); 4006169689Skan if (GET_MODE_BITSIZE (mode) == bitsize) 4007169689Skan emit_move_insn (adjust_address (dest, mode, 0), gen_lowpart (mode, src)); 4008169689Skan 4009169689Skan /* (set (ze (mem)) (const_int)). */ 4010169689Skan else if (const_int_operand (src, VOIDmode)) 4011169689Skan { 4012169689Skan int size = bitsize / BITS_PER_UNIT; 4013169689Skan rtx src_mem = adjust_address (force_const_mem (word_mode, src), BLKmode, 4014169689Skan GET_MODE_SIZE (word_mode) - size); 4015169689Skan 4016169689Skan dest = adjust_address (dest, BLKmode, 0); 4017169689Skan set_mem_size (dest, GEN_INT (size)); 4018169689Skan s390_expand_movmem (dest, src_mem, GEN_INT (size)); 4019169689Skan } 4020169689Skan 4021169689Skan /* (set (ze (mem)) (reg)). */ 4022169689Skan else if (register_operand (src, word_mode)) 4023169689Skan { 4024169689Skan if (bitsize <= GET_MODE_BITSIZE (SImode)) 4025169689Skan emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, op1, 4026169689Skan const0_rtx), src); 4027169689Skan else 4028169689Skan { 4029169689Skan /* Emit st,stcmh sequence. */ 4030169689Skan int stcmh_width = bitsize - GET_MODE_BITSIZE (SImode); 4031169689Skan int size = stcmh_width / BITS_PER_UNIT; 4032169689Skan 4033169689Skan emit_move_insn (adjust_address (dest, SImode, size), 4034169689Skan gen_lowpart (SImode, src)); 4035169689Skan set_mem_size (dest, GEN_INT (size)); 4036169689Skan emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, GEN_INT 4037169689Skan (stcmh_width), const0_rtx), 4038169689Skan gen_rtx_LSHIFTRT (word_mode, src, GEN_INT 4039169689Skan (GET_MODE_BITSIZE (SImode)))); 4040169689Skan } 4041169689Skan } 4042169689Skan else 4043169689Skan return false; 4044169689Skan 4045169689Skan return true; 4046169689Skan } 4047169689Skan 4048169689Skan /* (set (ze (reg)) (const_int)). */ 4049169689Skan if (TARGET_ZARCH 4050169689Skan && register_operand (dest, word_mode) 4051169689Skan && (bitpos % 16) == 0 4052169689Skan && (bitsize % 16) == 0 4053169689Skan && const_int_operand (src, VOIDmode)) 4054169689Skan { 4055169689Skan HOST_WIDE_INT val = INTVAL (src); 4056169689Skan int regpos = bitpos + bitsize; 4057169689Skan 4058169689Skan while (regpos > bitpos) 4059169689Skan { 4060169689Skan enum machine_mode putmode; 4061169689Skan int putsize; 4062169689Skan 4063169689Skan if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32)) 4064169689Skan putmode = SImode; 4065169689Skan else 4066169689Skan putmode = HImode; 4067169689Skan 4068169689Skan putsize = GET_MODE_BITSIZE (putmode); 4069169689Skan regpos -= putsize; 4070169689Skan emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, 4071169689Skan GEN_INT (putsize), 4072169689Skan GEN_INT (regpos)), 4073169689Skan gen_int_mode (val, putmode)); 4074169689Skan val >>= putsize; 4075169689Skan } 4076169689Skan gcc_assert (regpos == bitpos); 4077169689Skan return true; 4078169689Skan } 4079169689Skan 4080169689Skan return false; 4081169689Skan} 4082169689Skan 4083169689Skan/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic which returns a 4084169689Skan register that holds VAL of mode MODE shifted by COUNT bits. */ 4085169689Skan 4086169689Skanstatic inline rtx 4087169689Skans390_expand_mask_and_shift (rtx val, enum machine_mode mode, rtx count) 4088169689Skan{ 4089169689Skan val = expand_simple_binop (SImode, AND, val, GEN_INT (GET_MODE_MASK (mode)), 4090169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4091169689Skan return expand_simple_binop (SImode, ASHIFT, val, count, 4092169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4093169689Skan} 4094169689Skan 4095169689Skan/* Structure to hold the initial parameters for a compare_and_swap operation 4096169689Skan in HImode and QImode. */ 4097169689Skan 4098169689Skanstruct alignment_context 4099169689Skan{ 4100169689Skan rtx memsi; /* SI aligned memory location. */ 4101169689Skan rtx shift; /* Bit offset with regard to lsb. */ 4102169689Skan rtx modemask; /* Mask of the HQImode shifted by SHIFT bits. */ 4103169689Skan rtx modemaski; /* ~modemask */ 4104169689Skan bool aligned; /* True if memory is aligned, false else. */ 4105169689Skan}; 4106169689Skan 4107169689Skan/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic to initialize 4108169689Skan structure AC for transparent simplifying, if the memory alignment is known 4109169689Skan to be at least 32bit. MEM is the memory location for the actual operation 4110169689Skan and MODE its mode. */ 4111169689Skan 4112169689Skanstatic void 4113169689Skaninit_alignment_context (struct alignment_context *ac, rtx mem, 4114169689Skan enum machine_mode mode) 4115169689Skan{ 4116169689Skan ac->shift = GEN_INT (GET_MODE_SIZE (SImode) - GET_MODE_SIZE (mode)); 4117169689Skan ac->aligned = (MEM_ALIGN (mem) >= GET_MODE_BITSIZE (SImode)); 4118169689Skan 4119169689Skan if (ac->aligned) 4120169689Skan ac->memsi = adjust_address (mem, SImode, 0); /* Memory is aligned. */ 4121169689Skan else 4122169689Skan { 4123169689Skan /* Alignment is unknown. */ 4124169689Skan rtx byteoffset, addr, align; 4125169689Skan 4126169689Skan /* Force the address into a register. */ 4127169689Skan addr = force_reg (Pmode, XEXP (mem, 0)); 4128169689Skan 4129169689Skan /* Align it to SImode. */ 4130169689Skan align = expand_simple_binop (Pmode, AND, addr, 4131169689Skan GEN_INT (-GET_MODE_SIZE (SImode)), 4132169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4133169689Skan /* Generate MEM. */ 4134169689Skan ac->memsi = gen_rtx_MEM (SImode, align); 4135169689Skan MEM_VOLATILE_P (ac->memsi) = MEM_VOLATILE_P (mem); 4136169689Skan set_mem_alias_set (ac->memsi, ALIAS_SET_MEMORY_BARRIER); 4137169689Skan set_mem_align (ac->memsi, GET_MODE_BITSIZE (SImode)); 4138169689Skan 4139169689Skan /* Calculate shiftcount. */ 4140169689Skan byteoffset = expand_simple_binop (Pmode, AND, addr, 4141169689Skan GEN_INT (GET_MODE_SIZE (SImode) - 1), 4142169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4143169689Skan /* As we already have some offset, evaluate the remaining distance. */ 4144169689Skan ac->shift = expand_simple_binop (SImode, MINUS, ac->shift, byteoffset, 4145169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4146169689Skan 4147169689Skan } 4148169689Skan /* Shift is the byte count, but we need the bitcount. */ 4149169689Skan ac->shift = expand_simple_binop (SImode, MULT, ac->shift, GEN_INT (BITS_PER_UNIT), 4150169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4151169689Skan /* Calculate masks. */ 4152169689Skan ac->modemask = expand_simple_binop (SImode, ASHIFT, 4153169689Skan GEN_INT (GET_MODE_MASK (mode)), ac->shift, 4154169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4155169689Skan ac->modemaski = expand_simple_unop (SImode, NOT, ac->modemask, NULL_RTX, 1); 4156169689Skan} 4157169689Skan 4158169689Skan/* Expand an atomic compare and swap operation for HImode and QImode. MEM is 4159169689Skan the memory location, CMP the old value to compare MEM with and NEW the value 4160169689Skan to set if CMP == MEM. 4161169689Skan CMP is never in memory for compare_and_swap_cc because 4162169689Skan expand_bool_compare_and_swap puts it into a register for later compare. */ 4163169689Skan 4164169689Skanvoid 4165169689Skans390_expand_cs_hqi (enum machine_mode mode, rtx target, rtx mem, rtx cmp, rtx new) 4166169689Skan{ 4167169689Skan struct alignment_context ac; 4168169689Skan rtx cmpv, newv, val, resv, cc; 4169169689Skan rtx res = gen_reg_rtx (SImode); 4170169689Skan rtx csloop = gen_label_rtx (); 4171169689Skan rtx csend = gen_label_rtx (); 4172169689Skan 4173169689Skan gcc_assert (register_operand (target, VOIDmode)); 4174169689Skan gcc_assert (MEM_P (mem)); 4175169689Skan 4176169689Skan init_alignment_context (&ac, mem, mode); 4177169689Skan 4178169689Skan /* Shift the values to the correct bit positions. */ 4179169689Skan if (!(ac.aligned && MEM_P (cmp))) 4180169689Skan cmp = s390_expand_mask_and_shift (cmp, mode, ac.shift); 4181169689Skan if (!(ac.aligned && MEM_P (new))) 4182169689Skan new = s390_expand_mask_and_shift (new, mode, ac.shift); 4183169689Skan 4184169689Skan /* Load full word. Subsequent loads are performed by CS. */ 4185169689Skan val = expand_simple_binop (SImode, AND, ac.memsi, ac.modemaski, 4186169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4187169689Skan 4188169689Skan /* Start CS loop. */ 4189169689Skan emit_label (csloop); 4190169689Skan /* val = "<mem>00..0<mem>" 4191169689Skan * cmp = "00..0<cmp>00..0" 4192169689Skan * new = "00..0<new>00..0" 4193169689Skan */ 4194169689Skan 4195169689Skan /* Patch cmp and new with val at correct position. */ 4196169689Skan if (ac.aligned && MEM_P (cmp)) 4197169689Skan { 4198169689Skan cmpv = force_reg (SImode, val); 4199169689Skan store_bit_field (cmpv, GET_MODE_BITSIZE (mode), 0, SImode, cmp); 4200169689Skan } 4201169689Skan else 4202169689Skan cmpv = force_reg (SImode, expand_simple_binop (SImode, IOR, cmp, val, 4203169689Skan NULL_RTX, 1, OPTAB_DIRECT)); 4204169689Skan if (ac.aligned && MEM_P (new)) 4205169689Skan { 4206169689Skan newv = force_reg (SImode, val); 4207169689Skan store_bit_field (newv, GET_MODE_BITSIZE (mode), 0, SImode, new); 4208169689Skan } 4209169689Skan else 4210169689Skan newv = force_reg (SImode, expand_simple_binop (SImode, IOR, new, val, 4211169689Skan NULL_RTX, 1, OPTAB_DIRECT)); 4212169689Skan 4213169689Skan /* Jump to end if we're done (likely?). */ 4214169689Skan s390_emit_jump (csend, s390_emit_compare_and_swap (EQ, res, ac.memsi, 4215169689Skan cmpv, newv)); 4216169689Skan 4217169689Skan /* Check for changes outside mode. */ 4218169689Skan resv = expand_simple_binop (SImode, AND, res, ac.modemaski, 4219169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4220169689Skan cc = s390_emit_compare (NE, resv, val); 4221169689Skan emit_move_insn (val, resv); 4222169689Skan /* Loop internal if so. */ 4223169689Skan s390_emit_jump (csloop, cc); 4224169689Skan 4225169689Skan emit_label (csend); 4226169689Skan 4227169689Skan /* Return the correct part of the bitfield. */ 4228169689Skan convert_move (target, expand_simple_binop (SImode, LSHIFTRT, res, ac.shift, 4229169689Skan NULL_RTX, 1, OPTAB_DIRECT), 1); 4230169689Skan} 4231169689Skan 4232169689Skan/* Expand an atomic operation CODE of mode MODE. MEM is the memory location 4233169689Skan and VAL the value to play with. If AFTER is true then store the the value 4234169689Skan MEM holds after the operation, if AFTER is false then store the value MEM 4235169689Skan holds before the operation. If TARGET is zero then discard that value, else 4236169689Skan store it to TARGET. */ 4237169689Skan 4238169689Skanvoid 4239169689Skans390_expand_atomic (enum machine_mode mode, enum rtx_code code, 4240169689Skan rtx target, rtx mem, rtx val, bool after) 4241169689Skan{ 4242169689Skan struct alignment_context ac; 4243169689Skan rtx cmp; 4244169689Skan rtx new = gen_reg_rtx (SImode); 4245169689Skan rtx orig = gen_reg_rtx (SImode); 4246169689Skan rtx csloop = gen_label_rtx (); 4247169689Skan 4248169689Skan gcc_assert (!target || register_operand (target, VOIDmode)); 4249169689Skan gcc_assert (MEM_P (mem)); 4250169689Skan 4251169689Skan init_alignment_context (&ac, mem, mode); 4252169689Skan 4253169689Skan /* Shift val to the correct bit positions. 4254169689Skan Preserve "icm", but prevent "ex icm". */ 4255169689Skan if (!(ac.aligned && code == SET && MEM_P (val))) 4256169689Skan val = s390_expand_mask_and_shift (val, mode, ac.shift); 4257169689Skan 4258169689Skan /* Further preparation insns. */ 4259169689Skan if (code == PLUS || code == MINUS) 4260169689Skan emit_move_insn (orig, val); 4261169689Skan else if (code == MULT || code == AND) /* val = "11..1<val>11..1" */ 4262169689Skan val = expand_simple_binop (SImode, XOR, val, ac.modemaski, 4263169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4264169689Skan 4265169689Skan /* Load full word. Subsequent loads are performed by CS. */ 4266169689Skan cmp = force_reg (SImode, ac.memsi); 4267169689Skan 4268169689Skan /* Start CS loop. */ 4269169689Skan emit_label (csloop); 4270169689Skan emit_move_insn (new, cmp); 4271169689Skan 4272169689Skan /* Patch new with val at correct position. */ 4273169689Skan switch (code) 4274169689Skan { 4275169689Skan case PLUS: 4276169689Skan case MINUS: 4277169689Skan val = expand_simple_binop (SImode, code, new, orig, 4278169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4279169689Skan val = expand_simple_binop (SImode, AND, val, ac.modemask, 4280169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4281169689Skan /* FALLTHRU */ 4282169689Skan case SET: 4283169689Skan if (ac.aligned && MEM_P (val)) 4284169689Skan store_bit_field (new, GET_MODE_BITSIZE (mode), 0, SImode, val); 4285169689Skan else 4286169689Skan { 4287169689Skan new = expand_simple_binop (SImode, AND, new, ac.modemaski, 4288169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4289169689Skan new = expand_simple_binop (SImode, IOR, new, val, 4290169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4291169689Skan } 4292169689Skan break; 4293169689Skan case AND: 4294169689Skan case IOR: 4295169689Skan case XOR: 4296169689Skan new = expand_simple_binop (SImode, code, new, val, 4297169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4298169689Skan break; 4299169689Skan case MULT: /* NAND */ 4300169689Skan new = expand_simple_binop (SImode, XOR, new, ac.modemask, 4301169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4302169689Skan new = expand_simple_binop (SImode, AND, new, val, 4303169689Skan NULL_RTX, 1, OPTAB_DIRECT); 4304169689Skan break; 4305169689Skan default: 4306169689Skan gcc_unreachable (); 4307169689Skan } 4308169689Skan 4309169689Skan s390_emit_jump (csloop, s390_emit_compare_and_swap (NE, cmp, 4310169689Skan ac.memsi, cmp, new)); 4311169689Skan 4312169689Skan /* Return the correct part of the bitfield. */ 4313169689Skan if (target) 4314169689Skan convert_move (target, expand_simple_binop (SImode, LSHIFTRT, 4315169689Skan after ? new : cmp, ac.shift, 4316169689Skan NULL_RTX, 1, OPTAB_DIRECT), 1); 4317169689Skan} 4318169689Skan 4319169689Skan/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. 4320132718Skan We need to emit DTP-relative relocations. */ 4321132718Skan 4322169689Skanstatic void s390_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; 4323169689Skan 4324169689Skanstatic void 4325132718Skans390_output_dwarf_dtprel (FILE *file, int size, rtx x) 4326132718Skan{ 4327132718Skan switch (size) 4328132718Skan { 4329132718Skan case 4: 4330132718Skan fputs ("\t.long\t", file); 4331132718Skan break; 4332132718Skan case 8: 4333132718Skan fputs ("\t.quad\t", file); 4334132718Skan break; 4335132718Skan default: 4336169689Skan gcc_unreachable (); 4337132718Skan } 4338132718Skan output_addr_const (file, x); 4339132718Skan fputs ("@DTPOFF", file); 4340132718Skan} 4341132718Skan 4342169689Skan#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING 4343169689Skan/* Implement TARGET_MANGLE_FUNDAMENTAL_TYPE. */ 4344169689Skan 4345169689Skanstatic const char * 4346169689Skans390_mangle_fundamental_type (tree type) 4347169689Skan{ 4348169689Skan if (TYPE_MAIN_VARIANT (type) == long_double_type_node 4349169689Skan && TARGET_LONG_DOUBLE_128) 4350169689Skan return "g"; 4351169689Skan 4352169689Skan /* For all other types, use normal C++ mangling. */ 4353169689Skan return NULL; 4354169689Skan} 4355169689Skan#endif 4356169689Skan 4357107590Sobrien/* In the name of slightly smaller debug output, and to cater to 4358169689Skan general assembler lossage, recognize various UNSPEC sequences 4359107590Sobrien and turn them back into a direct symbol reference. */ 4360107590Sobrien 4361132718Skanstatic rtx 4362132718Skans390_delegitimize_address (rtx orig_x) 4363107590Sobrien{ 4364107590Sobrien rtx x = orig_x, y; 4365107590Sobrien 4366107590Sobrien if (GET_CODE (x) != MEM) 4367107590Sobrien return orig_x; 4368107590Sobrien 4369107590Sobrien x = XEXP (x, 0); 4370107590Sobrien if (GET_CODE (x) == PLUS 4371107590Sobrien && GET_CODE (XEXP (x, 1)) == CONST 4372107590Sobrien && GET_CODE (XEXP (x, 0)) == REG 4373107590Sobrien && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM) 4374107590Sobrien { 4375107590Sobrien y = XEXP (XEXP (x, 1), 0); 4376107590Sobrien if (GET_CODE (y) == UNSPEC 4377132718Skan && XINT (y, 1) == UNSPEC_GOT) 4378107590Sobrien return XVECEXP (y, 0, 0); 4379107590Sobrien return orig_x; 4380107590Sobrien } 4381107590Sobrien 4382107590Sobrien if (GET_CODE (x) == CONST) 4383107590Sobrien { 4384107590Sobrien y = XEXP (x, 0); 4385107590Sobrien if (GET_CODE (y) == UNSPEC 4386132718Skan && XINT (y, 1) == UNSPEC_GOTENT) 4387107590Sobrien return XVECEXP (y, 0, 0); 4388107590Sobrien return orig_x; 4389107590Sobrien } 4390107590Sobrien 4391132718Skan return orig_x; 4392107590Sobrien} 4393107590Sobrien 4394169689Skan/* Output operand OP to stdio stream FILE. 4395169689Skan OP is an address (register + offset) which is not used to address data; 4396169689Skan instead the rightmost bits are interpreted as the value. */ 4397132718Skan 4398132718Skanstatic void 4399132718Skanprint_shift_count_operand (FILE *file, rtx op) 4400132718Skan{ 4401169689Skan HOST_WIDE_INT offset; 4402169689Skan rtx base; 4403132718Skan 4404169689Skan /* Extract base register and offset. */ 4405169689Skan if (!s390_decompose_shift_count (op, &base, &offset)) 4406169689Skan gcc_unreachable (); 4407169689Skan 4408169689Skan /* Sanity check. */ 4409169689Skan if (base) 4410132718Skan { 4411169689Skan gcc_assert (GET_CODE (base) == REG); 4412169689Skan gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER); 4413169689Skan gcc_assert (REGNO_REG_CLASS (REGNO (base)) == ADDR_REGS); 4414132718Skan } 4415132718Skan 4416169689Skan /* Offsets are constricted to twelve bits. */ 4417169689Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & ((1 << 12) - 1)); 4418169689Skan if (base) 4419169689Skan fprintf (file, "(%s)", reg_names[REGNO (base)]); 4420132718Skan} 4421132718Skan 4422169689Skan/* See 'get_some_local_dynamic_name'. */ 4423117395Skan 4424117395Skanstatic int 4425132718Skanget_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) 4426117395Skan{ 4427117395Skan rtx x = *px; 4428117395Skan 4429117395Skan if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x)) 4430117395Skan { 4431117395Skan x = get_pool_constant (x); 4432117395Skan return for_each_rtx (&x, get_some_local_dynamic_name_1, 0); 4433117395Skan } 4434117395Skan 4435117395Skan if (GET_CODE (x) == SYMBOL_REF 4436117395Skan && tls_symbolic_operand (x) == TLS_MODEL_LOCAL_DYNAMIC) 4437117395Skan { 4438117395Skan cfun->machine->some_ld_name = XSTR (x, 0); 4439117395Skan return 1; 4440117395Skan } 4441117395Skan 4442117395Skan return 0; 4443117395Skan} 4444117395Skan 4445169689Skan/* Locate some local-dynamic symbol still in use by this function 4446169689Skan so that we can print its name in local-dynamic base patterns. */ 4447107590Sobrien 4448169689Skanstatic const char * 4449169689Skanget_some_local_dynamic_name (void) 4450107590Sobrien{ 4451169689Skan rtx insn; 4452107590Sobrien 4453169689Skan if (cfun->machine->some_ld_name) 4454169689Skan return cfun->machine->some_ld_name; 4455107590Sobrien 4456169689Skan for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 4457169689Skan if (INSN_P (insn) 4458169689Skan && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0)) 4459169689Skan return cfun->machine->some_ld_name; 4460107590Sobrien 4461169689Skan gcc_unreachable (); 4462169689Skan} 4463107590Sobrien 4464169689Skan/* Output machine-dependent UNSPECs occurring in address constant X 4465169689Skan in assembler syntax to stdio stream FILE. Returns true if the 4466169689Skan constant X could be recognized, false otherwise. */ 4467107590Sobrien 4468169689Skanbool 4469169689Skans390_output_addr_const_extra (FILE *file, rtx x) 4470169689Skan{ 4471169689Skan if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 1) 4472169689Skan switch (XINT (x, 1)) 4473169689Skan { 4474169689Skan case UNSPEC_GOTENT: 4475169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4476169689Skan fprintf (file, "@GOTENT"); 4477169689Skan return true; 4478169689Skan case UNSPEC_GOT: 4479169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4480169689Skan fprintf (file, "@GOT"); 4481169689Skan return true; 4482169689Skan case UNSPEC_GOTOFF: 4483169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4484169689Skan fprintf (file, "@GOTOFF"); 4485169689Skan return true; 4486169689Skan case UNSPEC_PLT: 4487169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4488169689Skan fprintf (file, "@PLT"); 4489169689Skan return true; 4490169689Skan case UNSPEC_PLTOFF: 4491169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4492169689Skan fprintf (file, "@PLTOFF"); 4493169689Skan return true; 4494169689Skan case UNSPEC_TLSGD: 4495169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4496169689Skan fprintf (file, "@TLSGD"); 4497169689Skan return true; 4498169689Skan case UNSPEC_TLSLDM: 4499169689Skan assemble_name (file, get_some_local_dynamic_name ()); 4500169689Skan fprintf (file, "@TLSLDM"); 4501169689Skan return true; 4502169689Skan case UNSPEC_DTPOFF: 4503169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4504169689Skan fprintf (file, "@DTPOFF"); 4505169689Skan return true; 4506169689Skan case UNSPEC_NTPOFF: 4507169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4508169689Skan fprintf (file, "@NTPOFF"); 4509169689Skan return true; 4510169689Skan case UNSPEC_GOTNTPOFF: 4511169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4512169689Skan fprintf (file, "@GOTNTPOFF"); 4513169689Skan return true; 4514169689Skan case UNSPEC_INDNTPOFF: 4515169689Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4516169689Skan fprintf (file, "@INDNTPOFF"); 4517169689Skan return true; 4518169689Skan } 4519169689Skan 4520169689Skan return false; 4521107590Sobrien} 4522107590Sobrien 4523132718Skan/* Output address operand ADDR in assembler syntax to 4524107590Sobrien stdio stream FILE. */ 4525107590Sobrien 4526107590Sobrienvoid 4527132718Skanprint_operand_address (FILE *file, rtx addr) 4528107590Sobrien{ 4529107590Sobrien struct s390_address ad; 4530107590Sobrien 4531117395Skan if (!s390_decompose_address (addr, &ad) 4532169689Skan || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) 4533169689Skan || (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx)))) 4534169689Skan output_operand_lossage ("cannot decompose address"); 4535132718Skan 4536107590Sobrien if (ad.disp) 4537169689Skan output_addr_const (file, ad.disp); 4538107590Sobrien else 4539107590Sobrien fprintf (file, "0"); 4540107590Sobrien 4541107590Sobrien if (ad.base && ad.indx) 4542107590Sobrien fprintf (file, "(%s,%s)", reg_names[REGNO (ad.indx)], 4543107590Sobrien reg_names[REGNO (ad.base)]); 4544107590Sobrien else if (ad.base) 4545107590Sobrien fprintf (file, "(%s)", reg_names[REGNO (ad.base)]); 4546107590Sobrien} 4547107590Sobrien 4548132718Skan/* Output operand X in assembler syntax to stdio stream FILE. 4549132718Skan CODE specified the format flag. The following format flags 4550107590Sobrien are recognized: 4551107590Sobrien 4552107590Sobrien 'C': print opcode suffix for branch condition. 4553107590Sobrien 'D': print opcode suffix for inverse branch condition. 4554117395Skan 'J': print tls_load/tls_gdcall/tls_ldcall suffix 4555169689Skan 'G': print the size of the operand in bytes. 4556107590Sobrien 'O': print only the displacement of a memory reference. 4557107590Sobrien 'R': print only the base register of a memory reference. 4558169689Skan 'S': print S-type memory reference (base+displacement). 4559107590Sobrien 'N': print the second word of a DImode operand. 4560107590Sobrien 'M': print the second word of a TImode operand. 4561132718Skan 'Y': print shift count operand. 4562107590Sobrien 4563107590Sobrien 'b': print integer X as if it's an unsigned byte. 4564169689Skan 'x': print integer X as if it's an unsigned halfword. 4565169689Skan 'h': print integer X as if it's a signed halfword. 4566132718Skan 'i': print the first nonzero HImode part of X. 4567169689Skan 'j': print the first HImode part unequal to -1 of X. 4568169689Skan 'k': print the first nonzero SImode part of X. 4569169689Skan 'm': print the first SImode part unequal to -1 of X. 4570169689Skan 'o': print integer X as if it's an unsigned 32bit word. */ 4571107590Sobrien 4572107590Sobrienvoid 4573132718Skanprint_operand (FILE *file, rtx x, int code) 4574107590Sobrien{ 4575107590Sobrien switch (code) 4576107590Sobrien { 4577107590Sobrien case 'C': 4578107590Sobrien fprintf (file, s390_branch_condition_mnemonic (x, FALSE)); 4579107590Sobrien return; 4580107590Sobrien 4581107590Sobrien case 'D': 4582107590Sobrien fprintf (file, s390_branch_condition_mnemonic (x, TRUE)); 4583107590Sobrien return; 4584107590Sobrien 4585117395Skan case 'J': 4586117395Skan if (GET_CODE (x) == SYMBOL_REF) 4587117395Skan { 4588117395Skan fprintf (file, "%s", ":tls_load:"); 4589117395Skan output_addr_const (file, x); 4590117395Skan } 4591117395Skan else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD) 4592117395Skan { 4593117395Skan fprintf (file, "%s", ":tls_gdcall:"); 4594117395Skan output_addr_const (file, XVECEXP (x, 0, 0)); 4595117395Skan } 4596117395Skan else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM) 4597117395Skan { 4598117395Skan fprintf (file, "%s", ":tls_ldcall:"); 4599117395Skan assemble_name (file, get_some_local_dynamic_name ()); 4600117395Skan } 4601117395Skan else 4602169689Skan gcc_unreachable (); 4603117395Skan return; 4604117395Skan 4605169689Skan case 'G': 4606169689Skan fprintf (file, "%u", GET_MODE_SIZE (GET_MODE (x))); 4607169689Skan return; 4608169689Skan 4609107590Sobrien case 'O': 4610107590Sobrien { 4611107590Sobrien struct s390_address ad; 4612169689Skan int ret; 4613107590Sobrien 4614169689Skan gcc_assert (GET_CODE (x) == MEM); 4615169689Skan ret = s390_decompose_address (XEXP (x, 0), &ad); 4616169689Skan gcc_assert (ret); 4617169689Skan gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base))); 4618169689Skan gcc_assert (!ad.indx); 4619107590Sobrien 4620107590Sobrien if (ad.disp) 4621169689Skan output_addr_const (file, ad.disp); 4622107590Sobrien else 4623107590Sobrien fprintf (file, "0"); 4624107590Sobrien } 4625107590Sobrien return; 4626107590Sobrien 4627107590Sobrien case 'R': 4628107590Sobrien { 4629107590Sobrien struct s390_address ad; 4630169689Skan int ret; 4631107590Sobrien 4632169689Skan gcc_assert (GET_CODE (x) == MEM); 4633169689Skan ret = s390_decompose_address (XEXP (x, 0), &ad); 4634169689Skan gcc_assert (ret); 4635169689Skan gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base))); 4636169689Skan gcc_assert (!ad.indx); 4637107590Sobrien 4638107590Sobrien if (ad.base) 4639107590Sobrien fprintf (file, "%s", reg_names[REGNO (ad.base)]); 4640107590Sobrien else 4641107590Sobrien fprintf (file, "0"); 4642107590Sobrien } 4643107590Sobrien return; 4644107590Sobrien 4645169689Skan case 'S': 4646169689Skan { 4647169689Skan struct s390_address ad; 4648169689Skan int ret; 4649169689Skan 4650169689Skan gcc_assert (GET_CODE (x) == MEM); 4651169689Skan ret = s390_decompose_address (XEXP (x, 0), &ad); 4652169689Skan gcc_assert (ret); 4653169689Skan gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base))); 4654169689Skan gcc_assert (!ad.indx); 4655169689Skan 4656169689Skan if (ad.disp) 4657169689Skan output_addr_const (file, ad.disp); 4658169689Skan else 4659169689Skan fprintf (file, "0"); 4660169689Skan 4661169689Skan if (ad.base) 4662169689Skan fprintf (file, "(%s)", reg_names[REGNO (ad.base)]); 4663169689Skan } 4664169689Skan return; 4665169689Skan 4666107590Sobrien case 'N': 4667107590Sobrien if (GET_CODE (x) == REG) 4668107590Sobrien x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1); 4669107590Sobrien else if (GET_CODE (x) == MEM) 4670107590Sobrien x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 4)); 4671107590Sobrien else 4672169689Skan gcc_unreachable (); 4673107590Sobrien break; 4674107590Sobrien 4675107590Sobrien case 'M': 4676107590Sobrien if (GET_CODE (x) == REG) 4677107590Sobrien x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1); 4678107590Sobrien else if (GET_CODE (x) == MEM) 4679107590Sobrien x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 8)); 4680107590Sobrien else 4681169689Skan gcc_unreachable (); 4682107590Sobrien break; 4683132718Skan 4684132718Skan case 'Y': 4685132718Skan print_shift_count_operand (file, x); 4686132718Skan return; 4687107590Sobrien } 4688107590Sobrien 4689107590Sobrien switch (GET_CODE (x)) 4690107590Sobrien { 4691107590Sobrien case REG: 4692107590Sobrien fprintf (file, "%s", reg_names[REGNO (x)]); 4693107590Sobrien break; 4694107590Sobrien 4695107590Sobrien case MEM: 4696107590Sobrien output_address (XEXP (x, 0)); 4697107590Sobrien break; 4698107590Sobrien 4699107590Sobrien case CONST: 4700107590Sobrien case CODE_LABEL: 4701107590Sobrien case LABEL_REF: 4702107590Sobrien case SYMBOL_REF: 4703169689Skan output_addr_const (file, x); 4704107590Sobrien break; 4705107590Sobrien 4706107590Sobrien case CONST_INT: 4707107590Sobrien if (code == 'b') 4708107590Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff); 4709107590Sobrien else if (code == 'x') 4710107590Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff); 4711107590Sobrien else if (code == 'h') 4712107590Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000); 4713132718Skan else if (code == 'i') 4714169689Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, 4715132718Skan s390_extract_part (x, HImode, 0)); 4716132718Skan else if (code == 'j') 4717169689Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, 4718169689Skan s390_extract_part (x, HImode, -1)); 4719169689Skan else if (code == 'k') 4720169689Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, 4721169689Skan s390_extract_part (x, SImode, 0)); 4722169689Skan else if (code == 'm') 4723169689Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, 4724169689Skan s390_extract_part (x, SImode, -1)); 4725169689Skan else if (code == 'o') 4726169689Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffffffff); 4727107590Sobrien else 4728107590Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 4729107590Sobrien break; 4730107590Sobrien 4731107590Sobrien case CONST_DOUBLE: 4732169689Skan gcc_assert (GET_MODE (x) == VOIDmode); 4733107590Sobrien if (code == 'b') 4734107590Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xff); 4735107590Sobrien else if (code == 'x') 4736107590Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xffff); 4737107590Sobrien else if (code == 'h') 4738107590Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000); 4739107590Sobrien else 4740169689Skan gcc_unreachable (); 4741107590Sobrien break; 4742107590Sobrien 4743107590Sobrien default: 4744107590Sobrien fatal_insn ("UNKNOWN in print_operand !?", x); 4745107590Sobrien break; 4746107590Sobrien } 4747107590Sobrien} 4748107590Sobrien 4749107590Sobrien/* Target hook for assembling integer objects. We need to define it 4750107590Sobrien here to work a round a bug in some versions of GAS, which couldn't 4751107590Sobrien handle values smaller than INT_MIN when printed in decimal. */ 4752107590Sobrien 4753107590Sobrienstatic bool 4754132718Skans390_assemble_integer (rtx x, unsigned int size, int aligned_p) 4755107590Sobrien{ 4756107590Sobrien if (size == 8 && aligned_p 4757107590Sobrien && GET_CODE (x) == CONST_INT && INTVAL (x) < INT_MIN) 4758107590Sobrien { 4759132718Skan fprintf (asm_out_file, "\t.quad\t" HOST_WIDE_INT_PRINT_HEX "\n", 4760132718Skan INTVAL (x)); 4761107590Sobrien return true; 4762107590Sobrien } 4763107590Sobrien return default_assemble_integer (x, size, aligned_p); 4764107590Sobrien} 4765107590Sobrien 4766132718Skan/* Returns true if register REGNO is used for forming 4767107590Sobrien a memory address in expression X. */ 4768107590Sobrien 4769169689Skanstatic bool 4770132718Skanreg_used_in_mem_p (int regno, rtx x) 4771107590Sobrien{ 4772107590Sobrien enum rtx_code code = GET_CODE (x); 4773107590Sobrien int i, j; 4774107590Sobrien const char *fmt; 4775132718Skan 4776107590Sobrien if (code == MEM) 4777107590Sobrien { 4778107590Sobrien if (refers_to_regno_p (regno, regno+1, 4779107590Sobrien XEXP (x, 0), 0)) 4780169689Skan return true; 4781107590Sobrien } 4782132718Skan else if (code == SET 4783107590Sobrien && GET_CODE (SET_DEST (x)) == PC) 4784107590Sobrien { 4785107590Sobrien if (refers_to_regno_p (regno, regno+1, 4786107590Sobrien SET_SRC (x), 0)) 4787169689Skan return true; 4788107590Sobrien } 4789107590Sobrien 4790107590Sobrien fmt = GET_RTX_FORMAT (code); 4791107590Sobrien for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 4792107590Sobrien { 4793107590Sobrien if (fmt[i] == 'e' 4794107590Sobrien && reg_used_in_mem_p (regno, XEXP (x, i))) 4795169689Skan return true; 4796132718Skan 4797107590Sobrien else if (fmt[i] == 'E') 4798107590Sobrien for (j = 0; j < XVECLEN (x, i); j++) 4799107590Sobrien if (reg_used_in_mem_p (regno, XVECEXP (x, i, j))) 4800169689Skan return true; 4801107590Sobrien } 4802169689Skan return false; 4803107590Sobrien} 4804107590Sobrien 4805107590Sobrien/* Returns true if expression DEP_RTX sets an address register 4806107590Sobrien used by instruction INSN to address memory. */ 4807107590Sobrien 4808169689Skanstatic bool 4809132718Skanaddr_generation_dependency_p (rtx dep_rtx, rtx insn) 4810107590Sobrien{ 4811107590Sobrien rtx target, pat; 4812107590Sobrien 4813132718Skan if (GET_CODE (dep_rtx) == INSN) 4814132718Skan dep_rtx = PATTERN (dep_rtx); 4815132718Skan 4816107590Sobrien if (GET_CODE (dep_rtx) == SET) 4817107590Sobrien { 4818107590Sobrien target = SET_DEST (dep_rtx); 4819117395Skan if (GET_CODE (target) == STRICT_LOW_PART) 4820117395Skan target = XEXP (target, 0); 4821117395Skan while (GET_CODE (target) == SUBREG) 4822117395Skan target = SUBREG_REG (target); 4823117395Skan 4824107590Sobrien if (GET_CODE (target) == REG) 4825107590Sobrien { 4826107590Sobrien int regno = REGNO (target); 4827107590Sobrien 4828132718Skan if (s390_safe_attr_type (insn) == TYPE_LA) 4829107590Sobrien { 4830107590Sobrien pat = PATTERN (insn); 4831107590Sobrien if (GET_CODE (pat) == PARALLEL) 4832107590Sobrien { 4833169689Skan gcc_assert (XVECLEN (pat, 0) == 2); 4834107590Sobrien pat = XVECEXP (pat, 0, 0); 4835107590Sobrien } 4836169689Skan gcc_assert (GET_CODE (pat) == SET); 4837169689Skan return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0); 4838107590Sobrien } 4839132718Skan else if (get_attr_atype (insn) == ATYPE_AGEN) 4840107590Sobrien return reg_used_in_mem_p (regno, PATTERN (insn)); 4841107590Sobrien } 4842107590Sobrien } 4843169689Skan return false; 4844107590Sobrien} 4845107590Sobrien 4846132718Skan/* Return 1, if dep_insn sets register used in insn in the agen unit. */ 4847107590Sobrien 4848132718Skanint 4849132718Skans390_agen_dep_p (rtx dep_insn, rtx insn) 4850132718Skan{ 4851132718Skan rtx dep_rtx = PATTERN (dep_insn); 4852132718Skan int i; 4853132718Skan 4854132718Skan if (GET_CODE (dep_rtx) == SET 4855132718Skan && addr_generation_dependency_p (dep_rtx, insn)) 4856132718Skan return 1; 4857132718Skan else if (GET_CODE (dep_rtx) == PARALLEL) 4858132718Skan { 4859132718Skan for (i = 0; i < XVECLEN (dep_rtx, 0); i++) 4860132718Skan { 4861132718Skan if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), insn)) 4862132718Skan return 1; 4863132718Skan } 4864132718Skan } 4865132718Skan return 0; 4866132718Skan} 4867132718Skan 4868107590Sobrien/* A C statement (sans semicolon) to update the integer scheduling priority 4869132718Skan INSN_PRIORITY (INSN). Increase the priority to execute the INSN earlier, 4870132718Skan reduce the priority to execute INSN later. Do not define this macro if 4871132718Skan you do not need to adjust the scheduling priorities of insns. 4872107590Sobrien 4873132718Skan A STD instruction should be scheduled earlier, 4874132718Skan in order to use the bypass. */ 4875107590Sobrien 4876107590Sobrienstatic int 4877132718Skans390_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority) 4878107590Sobrien{ 4879107590Sobrien if (! INSN_P (insn)) 4880107590Sobrien return priority; 4881107590Sobrien 4882169689Skan if (s390_tune != PROCESSOR_2084_Z990 4883169689Skan && s390_tune != PROCESSOR_2094_Z9_109) 4884107590Sobrien return priority; 4885132718Skan 4886132718Skan switch (s390_safe_attr_type (insn)) 4887107590Sobrien { 4888169689Skan case TYPE_FSTOREDF: 4889169689Skan case TYPE_FSTORESF: 4890132718Skan priority = priority << 3; 4891132718Skan break; 4892132718Skan case TYPE_STORE: 4893169689Skan case TYPE_STM: 4894132718Skan priority = priority << 1; 4895132718Skan break; 4896132718Skan default: 4897132718Skan break; 4898107590Sobrien } 4899107590Sobrien return priority; 4900107590Sobrien} 4901107590Sobrien 4902132718Skan/* The number of instructions that can be issued per cycle. */ 4903107590Sobrien 4904132718Skanstatic int 4905132718Skans390_issue_rate (void) 4906132718Skan{ 4907169689Skan if (s390_tune == PROCESSOR_2084_Z990 4908169689Skan || s390_tune == PROCESSOR_2094_Z9_109) 4909132718Skan return 3; 4910132718Skan return 1; 4911132718Skan} 4912107590Sobrien 4913132718Skanstatic int 4914169689Skans390_first_cycle_multipass_dfa_lookahead (void) 4915107590Sobrien{ 4916169689Skan return 4; 4917132718Skan} 4918132718Skan 4919169689Skan 4920169689Skan/* Annotate every literal pool reference in X by an UNSPEC_LTREF expression. 4921169689Skan Fix up MEMs as required. */ 4922169689Skan 4923169689Skanstatic void 4924169689Skanannotate_constant_pool_refs (rtx *x) 4925132718Skan{ 4926169689Skan int i, j; 4927169689Skan const char *fmt; 4928132718Skan 4929169689Skan gcc_assert (GET_CODE (*x) != SYMBOL_REF 4930169689Skan || !CONSTANT_POOL_ADDRESS_P (*x)); 4931132718Skan 4932169689Skan /* Literal pool references can only occur inside a MEM ... */ 4933169689Skan if (GET_CODE (*x) == MEM) 4934169689Skan { 4935169689Skan rtx memref = XEXP (*x, 0); 4936169689Skan 4937169689Skan if (GET_CODE (memref) == SYMBOL_REF 4938169689Skan && CONSTANT_POOL_ADDRESS_P (memref)) 4939169689Skan { 4940169689Skan rtx base = cfun->machine->base_reg; 4941169689Skan rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, memref, base), 4942169689Skan UNSPEC_LTREF); 4943169689Skan 4944169689Skan *x = replace_equiv_address (*x, addr); 4945169689Skan return; 4946169689Skan } 4947169689Skan 4948169689Skan if (GET_CODE (memref) == CONST 4949169689Skan && GET_CODE (XEXP (memref, 0)) == PLUS 4950169689Skan && GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT 4951169689Skan && GET_CODE (XEXP (XEXP (memref, 0), 0)) == SYMBOL_REF 4952169689Skan && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (memref, 0), 0))) 4953169689Skan { 4954169689Skan HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1)); 4955169689Skan rtx sym = XEXP (XEXP (memref, 0), 0); 4956169689Skan rtx base = cfun->machine->base_reg; 4957169689Skan rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base), 4958169689Skan UNSPEC_LTREF); 4959169689Skan 4960169689Skan *x = replace_equiv_address (*x, plus_constant (addr, off)); 4961169689Skan return; 4962169689Skan } 4963169689Skan } 4964169689Skan 4965169689Skan /* ... or a load-address type pattern. */ 4966169689Skan if (GET_CODE (*x) == SET) 4967169689Skan { 4968169689Skan rtx addrref = SET_SRC (*x); 4969169689Skan 4970169689Skan if (GET_CODE (addrref) == SYMBOL_REF 4971169689Skan && CONSTANT_POOL_ADDRESS_P (addrref)) 4972169689Skan { 4973169689Skan rtx base = cfun->machine->base_reg; 4974169689Skan rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addrref, base), 4975169689Skan UNSPEC_LTREF); 4976169689Skan 4977169689Skan SET_SRC (*x) = addr; 4978169689Skan return; 4979169689Skan } 4980169689Skan 4981169689Skan if (GET_CODE (addrref) == CONST 4982169689Skan && GET_CODE (XEXP (addrref, 0)) == PLUS 4983169689Skan && GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT 4984169689Skan && GET_CODE (XEXP (XEXP (addrref, 0), 0)) == SYMBOL_REF 4985169689Skan && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (addrref, 0), 0))) 4986169689Skan { 4987169689Skan HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1)); 4988169689Skan rtx sym = XEXP (XEXP (addrref, 0), 0); 4989169689Skan rtx base = cfun->machine->base_reg; 4990169689Skan rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base), 4991169689Skan UNSPEC_LTREF); 4992169689Skan 4993169689Skan SET_SRC (*x) = plus_constant (addr, off); 4994169689Skan return; 4995169689Skan } 4996169689Skan } 4997169689Skan 4998169689Skan /* Annotate LTREL_BASE as well. */ 4999169689Skan if (GET_CODE (*x) == UNSPEC 5000169689Skan && XINT (*x, 1) == UNSPEC_LTREL_BASE) 5001169689Skan { 5002169689Skan rtx base = cfun->machine->base_reg; 5003169689Skan *x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XVECEXP (*x, 0, 0), base), 5004169689Skan UNSPEC_LTREL_BASE); 5005169689Skan return; 5006169689Skan } 5007169689Skan 5008169689Skan fmt = GET_RTX_FORMAT (GET_CODE (*x)); 5009169689Skan for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--) 5010169689Skan { 5011169689Skan if (fmt[i] == 'e') 5012169689Skan { 5013169689Skan annotate_constant_pool_refs (&XEXP (*x, i)); 5014169689Skan } 5015169689Skan else if (fmt[i] == 'E') 5016169689Skan { 5017169689Skan for (j = 0; j < XVECLEN (*x, i); j++) 5018169689Skan annotate_constant_pool_refs (&XVECEXP (*x, i, j)); 5019169689Skan } 5020169689Skan } 5021132718Skan} 5022132718Skan 5023132718Skan/* Split all branches that exceed the maximum distance. 5024132718Skan Returns true if this created a new literal pool entry. */ 5025132718Skan 5026132718Skanstatic int 5027132718Skans390_split_branches (void) 5028132718Skan{ 5029132718Skan rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); 5030169689Skan int new_literal = 0, ret; 5031117395Skan rtx insn, pat, tmp, target; 5032117395Skan rtx *label; 5033107590Sobrien 5034117395Skan /* We need correct insn addresses. */ 5035107590Sobrien 5036117395Skan shorten_branches (get_insns ()); 5037107590Sobrien 5038107590Sobrien /* Find all branches that exceed 64KB, and split them. */ 5039107590Sobrien 5040107590Sobrien for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 5041107590Sobrien { 5042107590Sobrien if (GET_CODE (insn) != JUMP_INSN) 5043107590Sobrien continue; 5044107590Sobrien 5045107590Sobrien pat = PATTERN (insn); 5046117395Skan if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2) 5047117395Skan pat = XVECEXP (pat, 0, 0); 5048117395Skan if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx) 5049107590Sobrien continue; 5050107590Sobrien 5051132718Skan if (GET_CODE (SET_SRC (pat)) == LABEL_REF) 5052107590Sobrien { 5053117395Skan label = &SET_SRC (pat); 5054132718Skan } 5055132718Skan else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE) 5056107590Sobrien { 5057132718Skan if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF) 5058117395Skan label = &XEXP (SET_SRC (pat), 1); 5059132718Skan else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF) 5060117395Skan label = &XEXP (SET_SRC (pat), 2); 5061107590Sobrien else 5062107590Sobrien continue; 5063107590Sobrien } 5064107590Sobrien else 5065107590Sobrien continue; 5066107590Sobrien 5067132718Skan if (get_attr_length (insn) <= 4) 5068107590Sobrien continue; 5069107590Sobrien 5070132718Skan /* We are going to use the return register as scratch register, 5071132718Skan make sure it will be saved/restored by the prologue/epilogue. */ 5072169689Skan cfun_frame_layout.save_return_addr_p = 1; 5073117395Skan 5074132718Skan if (!flag_pic) 5075107590Sobrien { 5076117395Skan new_literal = 1; 5077117395Skan tmp = force_const_mem (Pmode, *label); 5078117395Skan tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn); 5079117395Skan INSN_ADDRESSES_NEW (tmp, -1); 5080169689Skan annotate_constant_pool_refs (&PATTERN (tmp)); 5081117395Skan 5082117395Skan target = temp_reg; 5083117395Skan } 5084107590Sobrien else 5085107590Sobrien { 5086117395Skan new_literal = 1; 5087132718Skan target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, *label), 5088132718Skan UNSPEC_LTREL_OFFSET); 5089132718Skan target = gen_rtx_CONST (Pmode, target); 5090132718Skan target = force_const_mem (Pmode, target); 5091132718Skan tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn); 5092117395Skan INSN_ADDRESSES_NEW (tmp, -1); 5093169689Skan annotate_constant_pool_refs (&PATTERN (tmp)); 5094107590Sobrien 5095169689Skan target = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XEXP (target, 0), 5096169689Skan cfun->machine->base_reg), 5097132718Skan UNSPEC_LTREL_BASE); 5098132718Skan target = gen_rtx_PLUS (Pmode, temp_reg, target); 5099107590Sobrien } 5100107590Sobrien 5101169689Skan ret = validate_change (insn, label, target, 0); 5102169689Skan gcc_assert (ret); 5103117395Skan } 5104107590Sobrien 5105117395Skan return new_literal; 5106107590Sobrien} 5107107590Sobrien 5108107590Sobrien 5109169689Skan/* Find an annotated literal pool symbol referenced in RTX X, 5110169689Skan and store it at REF. Will abort if X contains references to 5111169689Skan more than one such pool symbol; multiple references to the same 5112169689Skan symbol are allowed, however. 5113107590Sobrien 5114132718Skan The rtx pointed to by REF must be initialized to NULL_RTX 5115107590Sobrien by the caller before calling this routine. */ 5116107590Sobrien 5117107590Sobrienstatic void 5118132718Skanfind_constant_pool_ref (rtx x, rtx *ref) 5119107590Sobrien{ 5120107590Sobrien int i, j; 5121107590Sobrien const char *fmt; 5122107590Sobrien 5123132718Skan /* Ignore LTREL_BASE references. */ 5124132718Skan if (GET_CODE (x) == UNSPEC 5125132718Skan && XINT (x, 1) == UNSPEC_LTREL_BASE) 5126132718Skan return; 5127132718Skan /* Likewise POOL_ENTRY insns. */ 5128132718Skan if (GET_CODE (x) == UNSPEC_VOLATILE 5129132718Skan && XINT (x, 1) == UNSPECV_POOL_ENTRY) 5130132718Skan return; 5131132718Skan 5132169689Skan gcc_assert (GET_CODE (x) != SYMBOL_REF 5133169689Skan || !CONSTANT_POOL_ADDRESS_P (x)); 5134169689Skan 5135169689Skan if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_LTREF) 5136107590Sobrien { 5137169689Skan rtx sym = XVECEXP (x, 0, 0); 5138169689Skan gcc_assert (GET_CODE (sym) == SYMBOL_REF 5139169689Skan && CONSTANT_POOL_ADDRESS_P (sym)); 5140169689Skan 5141107590Sobrien if (*ref == NULL_RTX) 5142169689Skan *ref = sym; 5143169689Skan else 5144169689Skan gcc_assert (*ref == sym); 5145169689Skan 5146169689Skan return; 5147107590Sobrien } 5148107590Sobrien 5149107590Sobrien fmt = GET_RTX_FORMAT (GET_CODE (x)); 5150107590Sobrien for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) 5151107590Sobrien { 5152107590Sobrien if (fmt[i] == 'e') 5153107590Sobrien { 5154107590Sobrien find_constant_pool_ref (XEXP (x, i), ref); 5155107590Sobrien } 5156107590Sobrien else if (fmt[i] == 'E') 5157107590Sobrien { 5158107590Sobrien for (j = 0; j < XVECLEN (x, i); j++) 5159107590Sobrien find_constant_pool_ref (XVECEXP (x, i, j), ref); 5160107590Sobrien } 5161107590Sobrien } 5162107590Sobrien} 5163107590Sobrien 5164169689Skan/* Replace every reference to the annotated literal pool 5165169689Skan symbol REF in X by its base plus OFFSET. */ 5166107590Sobrien 5167107590Sobrienstatic void 5168169689Skanreplace_constant_pool_ref (rtx *x, rtx ref, rtx offset) 5169107590Sobrien{ 5170107590Sobrien int i, j; 5171107590Sobrien const char *fmt; 5172107590Sobrien 5173169689Skan gcc_assert (*x != ref); 5174107590Sobrien 5175169689Skan if (GET_CODE (*x) == UNSPEC 5176169689Skan && XINT (*x, 1) == UNSPEC_LTREF 5177169689Skan && XVECEXP (*x, 0, 0) == ref) 5178107590Sobrien { 5179169689Skan *x = gen_rtx_PLUS (Pmode, XVECEXP (*x, 0, 1), offset); 5180169689Skan return; 5181107590Sobrien } 5182107590Sobrien 5183169689Skan if (GET_CODE (*x) == PLUS 5184169689Skan && GET_CODE (XEXP (*x, 1)) == CONST_INT 5185169689Skan && GET_CODE (XEXP (*x, 0)) == UNSPEC 5186169689Skan && XINT (XEXP (*x, 0), 1) == UNSPEC_LTREF 5187169689Skan && XVECEXP (XEXP (*x, 0), 0, 0) == ref) 5188107590Sobrien { 5189169689Skan rtx addr = gen_rtx_PLUS (Pmode, XVECEXP (XEXP (*x, 0), 0, 1), offset); 5190169689Skan *x = plus_constant (addr, INTVAL (XEXP (*x, 1))); 5191169689Skan return; 5192107590Sobrien } 5193107590Sobrien 5194107590Sobrien fmt = GET_RTX_FORMAT (GET_CODE (*x)); 5195107590Sobrien for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--) 5196107590Sobrien { 5197107590Sobrien if (fmt[i] == 'e') 5198107590Sobrien { 5199169689Skan replace_constant_pool_ref (&XEXP (*x, i), ref, offset); 5200107590Sobrien } 5201107590Sobrien else if (fmt[i] == 'E') 5202107590Sobrien { 5203107590Sobrien for (j = 0; j < XVECLEN (*x, i); j++) 5204169689Skan replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset); 5205107590Sobrien } 5206107590Sobrien } 5207107590Sobrien} 5208107590Sobrien 5209132718Skan/* Check whether X contains an UNSPEC_LTREL_BASE. 5210132718Skan Return its constant pool symbol if found, NULL_RTX otherwise. */ 5211117395Skan 5212132718Skanstatic rtx 5213132718Skanfind_ltrel_base (rtx x) 5214117395Skan{ 5215117395Skan int i, j; 5216117395Skan const char *fmt; 5217117395Skan 5218132718Skan if (GET_CODE (x) == UNSPEC 5219132718Skan && XINT (x, 1) == UNSPEC_LTREL_BASE) 5220132718Skan return XVECEXP (x, 0, 0); 5221117395Skan 5222117395Skan fmt = GET_RTX_FORMAT (GET_CODE (x)); 5223117395Skan for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) 5224117395Skan { 5225117395Skan if (fmt[i] == 'e') 5226117395Skan { 5227132718Skan rtx fnd = find_ltrel_base (XEXP (x, i)); 5228132718Skan if (fnd) 5229132718Skan return fnd; 5230117395Skan } 5231117395Skan else if (fmt[i] == 'E') 5232117395Skan { 5233117395Skan for (j = 0; j < XVECLEN (x, i); j++) 5234132718Skan { 5235132718Skan rtx fnd = find_ltrel_base (XVECEXP (x, i, j)); 5236132718Skan if (fnd) 5237132718Skan return fnd; 5238132718Skan } 5239117395Skan } 5240117395Skan } 5241117395Skan 5242132718Skan return NULL_RTX; 5243117395Skan} 5244117395Skan 5245169689Skan/* Replace any occurrence of UNSPEC_LTREL_BASE in X with its base. */ 5246117395Skan 5247117395Skanstatic void 5248169689Skanreplace_ltrel_base (rtx *x) 5249117395Skan{ 5250132718Skan int i, j; 5251117395Skan const char *fmt; 5252117395Skan 5253132718Skan if (GET_CODE (*x) == UNSPEC 5254132718Skan && XINT (*x, 1) == UNSPEC_LTREL_BASE) 5255117395Skan { 5256169689Skan *x = XVECEXP (*x, 0, 1); 5257132718Skan return; 5258117395Skan } 5259117395Skan 5260117395Skan fmt = GET_RTX_FORMAT (GET_CODE (*x)); 5261117395Skan for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--) 5262117395Skan { 5263117395Skan if (fmt[i] == 'e') 5264117395Skan { 5265169689Skan replace_ltrel_base (&XEXP (*x, i)); 5266117395Skan } 5267117395Skan else if (fmt[i] == 'E') 5268117395Skan { 5269117395Skan for (j = 0; j < XVECLEN (*x, i); j++) 5270169689Skan replace_ltrel_base (&XVECEXP (*x, i, j)); 5271117395Skan } 5272117395Skan } 5273117395Skan} 5274117395Skan 5275117395Skan 5276132718Skan/* We keep a list of constants which we have to add to internal 5277107590Sobrien constant tables in the middle of large functions. */ 5278107590Sobrien 5279169689Skan#define NR_C_MODES 11 5280132718Skanenum machine_mode constant_modes[NR_C_MODES] = 5281107590Sobrien{ 5282169689Skan TFmode, TImode, TDmode, 5283169689Skan DFmode, DImode, DDmode, 5284169689Skan SFmode, SImode, SDmode, 5285107590Sobrien HImode, 5286107590Sobrien QImode 5287107590Sobrien}; 5288107590Sobrien 5289107590Sobrienstruct constant 5290107590Sobrien{ 5291107590Sobrien struct constant *next; 5292107590Sobrien rtx value; 5293107590Sobrien rtx label; 5294107590Sobrien}; 5295107590Sobrien 5296107590Sobrienstruct constant_pool 5297107590Sobrien{ 5298107590Sobrien struct constant_pool *next; 5299107590Sobrien rtx first_insn; 5300117395Skan rtx pool_insn; 5301117395Skan bitmap insns; 5302107590Sobrien 5303107590Sobrien struct constant *constants[NR_C_MODES]; 5304169689Skan struct constant *execute; 5305107590Sobrien rtx label; 5306107590Sobrien int size; 5307107590Sobrien}; 5308107590Sobrien 5309169689Skan/* Allocate new constant_pool structure. */ 5310117395Skan 5311169689Skanstatic struct constant_pool * 5312169689Skans390_alloc_pool (void) 5313169689Skan{ 5314169689Skan struct constant_pool *pool; 5315169689Skan int i; 5316107590Sobrien 5317169689Skan pool = (struct constant_pool *) xmalloc (sizeof *pool); 5318169689Skan pool->next = NULL; 5319169689Skan for (i = 0; i < NR_C_MODES; i++) 5320169689Skan pool->constants[i] = NULL; 5321132718Skan 5322169689Skan pool->execute = NULL; 5323169689Skan pool->label = gen_label_rtx (); 5324169689Skan pool->first_insn = NULL_RTX; 5325169689Skan pool->pool_insn = NULL_RTX; 5326169689Skan pool->insns = BITMAP_ALLOC (NULL); 5327169689Skan pool->size = 0; 5328169689Skan 5329169689Skan return pool; 5330169689Skan} 5331169689Skan 5332107590Sobrien/* Create new constant pool covering instructions starting at INSN 5333107590Sobrien and chain it to the end of POOL_LIST. */ 5334107590Sobrien 5335107590Sobrienstatic struct constant_pool * 5336132718Skans390_start_pool (struct constant_pool **pool_list, rtx insn) 5337107590Sobrien{ 5338107590Sobrien struct constant_pool *pool, **prev; 5339107590Sobrien 5340132718Skan pool = s390_alloc_pool (); 5341107590Sobrien pool->first_insn = insn; 5342117395Skan 5343107590Sobrien for (prev = pool_list; *prev; prev = &(*prev)->next) 5344107590Sobrien ; 5345107590Sobrien *prev = pool; 5346107590Sobrien 5347107590Sobrien return pool; 5348107590Sobrien} 5349107590Sobrien 5350117395Skan/* End range of instructions covered by POOL at INSN and emit 5351117395Skan placeholder insn representing the pool. */ 5352107590Sobrien 5353107590Sobrienstatic void 5354132718Skans390_end_pool (struct constant_pool *pool, rtx insn) 5355107590Sobrien{ 5356117395Skan rtx pool_size = GEN_INT (pool->size + 8 /* alignment slop */); 5357117395Skan 5358117395Skan if (!insn) 5359117395Skan insn = get_last_insn (); 5360117395Skan 5361117395Skan pool->pool_insn = emit_insn_after (gen_pool (pool_size), insn); 5362117395Skan INSN_ADDRESSES_NEW (pool->pool_insn, -1); 5363107590Sobrien} 5364107590Sobrien 5365117395Skan/* Add INSN to the list of insns covered by POOL. */ 5366117395Skan 5367117395Skanstatic void 5368132718Skans390_add_pool_insn (struct constant_pool *pool, rtx insn) 5369117395Skan{ 5370117395Skan bitmap_set_bit (pool->insns, INSN_UID (insn)); 5371117395Skan} 5372117395Skan 5373107590Sobrien/* Return pool out of POOL_LIST that covers INSN. */ 5374107590Sobrien 5375107590Sobrienstatic struct constant_pool * 5376132718Skans390_find_pool (struct constant_pool *pool_list, rtx insn) 5377107590Sobrien{ 5378107590Sobrien struct constant_pool *pool; 5379107590Sobrien 5380107590Sobrien for (pool = pool_list; pool; pool = pool->next) 5381117395Skan if (bitmap_bit_p (pool->insns, INSN_UID (insn))) 5382107590Sobrien break; 5383107590Sobrien 5384107590Sobrien return pool; 5385107590Sobrien} 5386107590Sobrien 5387117395Skan/* Add constant VAL of mode MODE to the constant pool POOL. */ 5388107590Sobrien 5389117395Skanstatic void 5390132718Skans390_add_constant (struct constant_pool *pool, rtx val, enum machine_mode mode) 5391107590Sobrien{ 5392107590Sobrien struct constant *c; 5393107590Sobrien int i; 5394107590Sobrien 5395107590Sobrien for (i = 0; i < NR_C_MODES; i++) 5396107590Sobrien if (constant_modes[i] == mode) 5397107590Sobrien break; 5398169689Skan gcc_assert (i != NR_C_MODES); 5399107590Sobrien 5400107590Sobrien for (c = pool->constants[i]; c != NULL; c = c->next) 5401107590Sobrien if (rtx_equal_p (val, c->value)) 5402107590Sobrien break; 5403107590Sobrien 5404107590Sobrien if (c == NULL) 5405107590Sobrien { 5406107590Sobrien c = (struct constant *) xmalloc (sizeof *c); 5407107590Sobrien c->value = val; 5408107590Sobrien c->label = gen_label_rtx (); 5409107590Sobrien c->next = pool->constants[i]; 5410107590Sobrien pool->constants[i] = c; 5411107590Sobrien pool->size += GET_MODE_SIZE (mode); 5412107590Sobrien } 5413117395Skan} 5414107590Sobrien 5415117395Skan/* Find constant VAL of mode MODE in the constant pool POOL. 5416117395Skan Return an RTX describing the distance from the start of 5417117395Skan the pool to the location of the new constant. */ 5418132718Skan 5419117395Skanstatic rtx 5420132718Skans390_find_constant (struct constant_pool *pool, rtx val, 5421132718Skan enum machine_mode mode) 5422117395Skan{ 5423117395Skan struct constant *c; 5424117395Skan rtx offset; 5425117395Skan int i; 5426132718Skan 5427117395Skan for (i = 0; i < NR_C_MODES; i++) 5428117395Skan if (constant_modes[i] == mode) 5429117395Skan break; 5430169689Skan gcc_assert (i != NR_C_MODES); 5431132718Skan 5432117395Skan for (c = pool->constants[i]; c != NULL; c = c->next) 5433117395Skan if (rtx_equal_p (val, c->value)) 5434117395Skan break; 5435132718Skan 5436169689Skan gcc_assert (c); 5437132718Skan 5438117395Skan offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label), 5439117395Skan gen_rtx_LABEL_REF (Pmode, pool->label)); 5440107590Sobrien offset = gen_rtx_CONST (Pmode, offset); 5441107590Sobrien return offset; 5442107590Sobrien} 5443107590Sobrien 5444169689Skan/* Check whether INSN is an execute. Return the label_ref to its 5445169689Skan execute target template if so, NULL_RTX otherwise. */ 5446169689Skan 5447169689Skanstatic rtx 5448169689Skans390_execute_label (rtx insn) 5449169689Skan{ 5450169689Skan if (GET_CODE (insn) == INSN 5451169689Skan && GET_CODE (PATTERN (insn)) == PARALLEL 5452169689Skan && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == UNSPEC 5453169689Skan && XINT (XVECEXP (PATTERN (insn), 0, 0), 1) == UNSPEC_EXECUTE) 5454169689Skan return XVECEXP (XVECEXP (PATTERN (insn), 0, 0), 0, 2); 5455169689Skan 5456169689Skan return NULL_RTX; 5457169689Skan} 5458169689Skan 5459169689Skan/* Add execute target for INSN to the constant pool POOL. */ 5460169689Skan 5461169689Skanstatic void 5462169689Skans390_add_execute (struct constant_pool *pool, rtx insn) 5463169689Skan{ 5464169689Skan struct constant *c; 5465169689Skan 5466169689Skan for (c = pool->execute; c != NULL; c = c->next) 5467169689Skan if (INSN_UID (insn) == INSN_UID (c->value)) 5468169689Skan break; 5469169689Skan 5470169689Skan if (c == NULL) 5471169689Skan { 5472169689Skan c = (struct constant *) xmalloc (sizeof *c); 5473169689Skan c->value = insn; 5474169689Skan c->label = gen_label_rtx (); 5475169689Skan c->next = pool->execute; 5476169689Skan pool->execute = c; 5477169689Skan pool->size += 6; 5478169689Skan } 5479169689Skan} 5480169689Skan 5481169689Skan/* Find execute target for INSN in the constant pool POOL. 5482169689Skan Return an RTX describing the distance from the start of 5483169689Skan the pool to the location of the execute target. */ 5484169689Skan 5485169689Skanstatic rtx 5486169689Skans390_find_execute (struct constant_pool *pool, rtx insn) 5487169689Skan{ 5488169689Skan struct constant *c; 5489169689Skan rtx offset; 5490169689Skan 5491169689Skan for (c = pool->execute; c != NULL; c = c->next) 5492169689Skan if (INSN_UID (insn) == INSN_UID (c->value)) 5493169689Skan break; 5494169689Skan 5495169689Skan gcc_assert (c); 5496169689Skan 5497169689Skan offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label), 5498169689Skan gen_rtx_LABEL_REF (Pmode, pool->label)); 5499169689Skan offset = gen_rtx_CONST (Pmode, offset); 5500169689Skan return offset; 5501169689Skan} 5502169689Skan 5503169689Skan/* For an execute INSN, extract the execute target template. */ 5504169689Skan 5505169689Skanstatic rtx 5506169689Skans390_execute_target (rtx insn) 5507169689Skan{ 5508169689Skan rtx pattern = PATTERN (insn); 5509169689Skan gcc_assert (s390_execute_label (insn)); 5510169689Skan 5511169689Skan if (XVECLEN (pattern, 0) == 2) 5512169689Skan { 5513169689Skan pattern = copy_rtx (XVECEXP (pattern, 0, 1)); 5514169689Skan } 5515169689Skan else 5516169689Skan { 5517169689Skan rtvec vec = rtvec_alloc (XVECLEN (pattern, 0) - 1); 5518169689Skan int i; 5519169689Skan 5520169689Skan for (i = 0; i < XVECLEN (pattern, 0) - 1; i++) 5521169689Skan RTVEC_ELT (vec, i) = copy_rtx (XVECEXP (pattern, 0, i + 1)); 5522169689Skan 5523169689Skan pattern = gen_rtx_PARALLEL (VOIDmode, vec); 5524169689Skan } 5525169689Skan 5526169689Skan return pattern; 5527169689Skan} 5528169689Skan 5529169689Skan/* Indicate that INSN cannot be duplicated. This is the case for 5530169689Skan execute insns that carry a unique label. */ 5531169689Skan 5532169689Skanstatic bool 5533169689Skans390_cannot_copy_insn_p (rtx insn) 5534169689Skan{ 5535169689Skan rtx label = s390_execute_label (insn); 5536169689Skan return label && label != const0_rtx; 5537169689Skan} 5538169689Skan 5539132718Skan/* Dump out the constants in POOL. If REMOTE_LABEL is true, 5540132718Skan do not emit the pool base label. */ 5541117395Skan 5542169689Skanstatic void 5543132718Skans390_dump_pool (struct constant_pool *pool, bool remote_label) 5544107590Sobrien{ 5545107590Sobrien struct constant *c; 5546169689Skan rtx insn = pool->pool_insn; 5547107590Sobrien int i; 5548107590Sobrien 5549169689Skan /* Switch to rodata section. */ 5550132718Skan if (TARGET_CPU_ZARCH) 5551169689Skan { 5552169689Skan insn = emit_insn_after (gen_pool_section_start (), insn); 5553169689Skan INSN_ADDRESSES_NEW (insn, -1); 5554169689Skan } 5555169689Skan 5556169689Skan /* Ensure minimum pool alignment. */ 5557169689Skan if (TARGET_CPU_ZARCH) 5558169689Skan insn = emit_insn_after (gen_pool_align (GEN_INT (8)), insn); 5559107590Sobrien else 5560169689Skan insn = emit_insn_after (gen_pool_align (GEN_INT (4)), insn); 5561107590Sobrien INSN_ADDRESSES_NEW (insn, -1); 5562107590Sobrien 5563169689Skan /* Emit pool base label. */ 5564132718Skan if (!remote_label) 5565117395Skan { 5566132718Skan insn = emit_label_after (pool->label, insn); 5567117395Skan INSN_ADDRESSES_NEW (insn, -1); 5568117395Skan } 5569117395Skan 5570107590Sobrien /* Dump constants in descending alignment requirement order, 5571107590Sobrien ensuring proper alignment for every constant. */ 5572107590Sobrien for (i = 0; i < NR_C_MODES; i++) 5573107590Sobrien for (c = pool->constants[i]; c; c = c->next) 5574107590Sobrien { 5575132718Skan /* Convert UNSPEC_LTREL_OFFSET unspecs to pool-relative references. */ 5576117395Skan rtx value = c->value; 5577117395Skan if (GET_CODE (value) == CONST 5578117395Skan && GET_CODE (XEXP (value, 0)) == UNSPEC 5579132718Skan && XINT (XEXP (value, 0), 1) == UNSPEC_LTREL_OFFSET 5580117395Skan && XVECLEN (XEXP (value, 0), 0) == 1) 5581117395Skan { 5582117395Skan value = gen_rtx_MINUS (Pmode, XVECEXP (XEXP (value, 0), 0, 0), 5583132718Skan gen_rtx_LABEL_REF (VOIDmode, pool->label)); 5584117395Skan value = gen_rtx_CONST (VOIDmode, value); 5585117395Skan } 5586117395Skan 5587107590Sobrien insn = emit_label_after (c->label, insn); 5588107590Sobrien INSN_ADDRESSES_NEW (insn, -1); 5589132718Skan 5590169689Skan value = gen_rtx_UNSPEC_VOLATILE (constant_modes[i], 5591132718Skan gen_rtvec (1, value), 5592132718Skan UNSPECV_POOL_ENTRY); 5593132718Skan insn = emit_insn_after (value, insn); 5594107590Sobrien INSN_ADDRESSES_NEW (insn, -1); 5595107590Sobrien } 5596107590Sobrien 5597169689Skan /* Ensure minimum alignment for instructions. */ 5598169689Skan insn = emit_insn_after (gen_pool_align (GEN_INT (2)), insn); 5599107590Sobrien INSN_ADDRESSES_NEW (insn, -1); 5600107590Sobrien 5601169689Skan /* Output in-pool execute template insns. */ 5602169689Skan for (c = pool->execute; c; c = c->next) 5603169689Skan { 5604169689Skan insn = emit_label_after (c->label, insn); 5605169689Skan INSN_ADDRESSES_NEW (insn, -1); 5606169689Skan 5607169689Skan insn = emit_insn_after (s390_execute_target (c->value), insn); 5608169689Skan INSN_ADDRESSES_NEW (insn, -1); 5609169689Skan } 5610169689Skan 5611169689Skan /* Switch back to previous section. */ 5612169689Skan if (TARGET_CPU_ZARCH) 5613169689Skan { 5614169689Skan insn = emit_insn_after (gen_pool_section_end (), insn); 5615169689Skan INSN_ADDRESSES_NEW (insn, -1); 5616169689Skan } 5617169689Skan 5618107590Sobrien insn = emit_barrier_after (insn); 5619107590Sobrien INSN_ADDRESSES_NEW (insn, -1); 5620107590Sobrien 5621117395Skan /* Remove placeholder insn. */ 5622117395Skan remove_insn (pool->pool_insn); 5623107590Sobrien} 5624107590Sobrien 5625107590Sobrien/* Free all memory used by POOL. */ 5626107590Sobrien 5627107590Sobrienstatic void 5628132718Skans390_free_pool (struct constant_pool *pool) 5629107590Sobrien{ 5630169689Skan struct constant *c, *next; 5631107590Sobrien int i; 5632107590Sobrien 5633107590Sobrien for (i = 0; i < NR_C_MODES; i++) 5634169689Skan for (c = pool->constants[i]; c; c = next) 5635169689Skan { 5636169689Skan next = c->next; 5637169689Skan free (c); 5638169689Skan } 5639169689Skan 5640169689Skan for (c = pool->execute; c; c = next) 5641107590Sobrien { 5642169689Skan next = c->next; 5643169689Skan free (c); 5644107590Sobrien } 5645107590Sobrien 5646169689Skan BITMAP_FREE (pool->insns); 5647107590Sobrien free (pool); 5648132718Skan} 5649107590Sobrien 5650107590Sobrien 5651132718Skan/* Collect main literal pool. Return NULL on overflow. */ 5652107590Sobrien 5653132718Skanstatic struct constant_pool * 5654132718Skans390_mainpool_start (void) 5655132718Skan{ 5656132718Skan struct constant_pool *pool; 5657132718Skan rtx insn; 5658117395Skan 5659132718Skan pool = s390_alloc_pool (); 5660132718Skan 5661132718Skan for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 5662132718Skan { 5663132718Skan if (GET_CODE (insn) == INSN 5664169689Skan && GET_CODE (PATTERN (insn)) == SET 5665169689Skan && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE 5666169689Skan && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL) 5667132718Skan { 5668169689Skan gcc_assert (!pool->pool_insn); 5669132718Skan pool->pool_insn = insn; 5670132718Skan } 5671132718Skan 5672169689Skan if (!TARGET_CPU_ZARCH && s390_execute_label (insn)) 5673132718Skan { 5674169689Skan s390_add_execute (pool, insn); 5675169689Skan } 5676169689Skan else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) 5677169689Skan { 5678132718Skan rtx pool_ref = NULL_RTX; 5679132718Skan find_constant_pool_ref (PATTERN (insn), &pool_ref); 5680132718Skan if (pool_ref) 5681132718Skan { 5682132718Skan rtx constant = get_pool_constant (pool_ref); 5683132718Skan enum machine_mode mode = get_pool_mode (pool_ref); 5684132718Skan s390_add_constant (pool, constant, mode); 5685132718Skan } 5686132718Skan } 5687132718Skan } 5688132718Skan 5689169689Skan gcc_assert (pool->pool_insn || pool->size == 0); 5690132718Skan 5691132718Skan if (pool->size >= 4096) 5692132718Skan { 5693132718Skan /* We're going to chunkify the pool, so remove the main 5694132718Skan pool placeholder insn. */ 5695132718Skan remove_insn (pool->pool_insn); 5696132718Skan 5697132718Skan s390_free_pool (pool); 5698132718Skan pool = NULL; 5699132718Skan } 5700132718Skan 5701132718Skan return pool; 5702132718Skan} 5703132718Skan 5704132718Skan/* POOL holds the main literal pool as collected by s390_mainpool_start. 5705132718Skan Modify the current function to output the pool constants as well as 5706169689Skan the pool register setup instruction. */ 5707132718Skan 5708132718Skanstatic void 5709169689Skans390_mainpool_finish (struct constant_pool *pool) 5710132718Skan{ 5711169689Skan rtx base_reg = cfun->machine->base_reg; 5712132718Skan rtx insn; 5713132718Skan 5714132718Skan /* If the pool is empty, we're done. */ 5715132718Skan if (pool->size == 0) 5716132718Skan { 5717169689Skan /* We don't actually need a base register after all. */ 5718169689Skan cfun->machine->base_reg = NULL_RTX; 5719169689Skan 5720169689Skan if (pool->pool_insn) 5721169689Skan remove_insn (pool->pool_insn); 5722132718Skan s390_free_pool (pool); 5723132718Skan return; 5724132718Skan } 5725132718Skan 5726132718Skan /* We need correct insn addresses. */ 5727132718Skan shorten_branches (get_insns ()); 5728132718Skan 5729132718Skan /* On zSeries, we use a LARL to load the pool register. The pool is 5730132718Skan located in the .rodata section, so we emit it after the function. */ 5731132718Skan if (TARGET_CPU_ZARCH) 5732132718Skan { 5733132718Skan insn = gen_main_base_64 (base_reg, pool->label); 5734132718Skan insn = emit_insn_after (insn, pool->pool_insn); 5735132718Skan INSN_ADDRESSES_NEW (insn, -1); 5736132718Skan remove_insn (pool->pool_insn); 5737169689Skan 5738169689Skan insn = get_last_insn (); 5739132718Skan pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn); 5740132718Skan INSN_ADDRESSES_NEW (pool->pool_insn, -1); 5741132718Skan 5742132718Skan s390_dump_pool (pool, 0); 5743132718Skan } 5744132718Skan 5745132718Skan /* On S/390, if the total size of the function's code plus literal pool 5746132718Skan does not exceed 4096 bytes, we use BASR to set up a function base 5747132718Skan pointer, and emit the literal pool at the end of the function. */ 5748132718Skan else if (INSN_ADDRESSES (INSN_UID (get_last_insn ())) 5749132718Skan + pool->size + 8 /* alignment slop */ < 4096) 5750132718Skan { 5751132718Skan insn = gen_main_base_31_small (base_reg, pool->label); 5752132718Skan insn = emit_insn_after (insn, pool->pool_insn); 5753132718Skan INSN_ADDRESSES_NEW (insn, -1); 5754132718Skan remove_insn (pool->pool_insn); 5755132718Skan 5756132718Skan insn = emit_label_after (pool->label, insn); 5757132718Skan INSN_ADDRESSES_NEW (insn, -1); 5758132718Skan 5759132718Skan insn = get_last_insn (); 5760132718Skan pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn); 5761132718Skan INSN_ADDRESSES_NEW (pool->pool_insn, -1); 5762132718Skan 5763132718Skan s390_dump_pool (pool, 1); 5764132718Skan } 5765132718Skan 5766132718Skan /* Otherwise, we emit an inline literal pool and use BASR to branch 5767132718Skan over it, setting up the pool register at the same time. */ 5768132718Skan else 5769132718Skan { 5770132718Skan rtx pool_end = gen_label_rtx (); 5771132718Skan 5772132718Skan insn = gen_main_base_31_large (base_reg, pool->label, pool_end); 5773132718Skan insn = emit_insn_after (insn, pool->pool_insn); 5774132718Skan INSN_ADDRESSES_NEW (insn, -1); 5775132718Skan remove_insn (pool->pool_insn); 5776132718Skan 5777132718Skan insn = emit_label_after (pool->label, insn); 5778132718Skan INSN_ADDRESSES_NEW (insn, -1); 5779132718Skan 5780132718Skan pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn); 5781132718Skan INSN_ADDRESSES_NEW (pool->pool_insn, -1); 5782132718Skan 5783132718Skan insn = emit_label_after (pool_end, pool->pool_insn); 5784132718Skan INSN_ADDRESSES_NEW (insn, -1); 5785132718Skan 5786132718Skan s390_dump_pool (pool, 1); 5787132718Skan } 5788132718Skan 5789132718Skan 5790132718Skan /* Replace all literal pool references. */ 5791132718Skan 5792132718Skan for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 5793132718Skan { 5794132718Skan if (INSN_P (insn)) 5795169689Skan replace_ltrel_base (&PATTERN (insn)); 5796132718Skan 5797132718Skan if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) 5798132718Skan { 5799132718Skan rtx addr, pool_ref = NULL_RTX; 5800132718Skan find_constant_pool_ref (PATTERN (insn), &pool_ref); 5801132718Skan if (pool_ref) 5802132718Skan { 5803169689Skan if (s390_execute_label (insn)) 5804169689Skan addr = s390_find_execute (pool, insn); 5805169689Skan else 5806169689Skan addr = s390_find_constant (pool, get_pool_constant (pool_ref), 5807169689Skan get_pool_mode (pool_ref)); 5808169689Skan 5809132718Skan replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); 5810132718Skan INSN_CODE (insn) = -1; 5811132718Skan } 5812132718Skan } 5813132718Skan } 5814132718Skan 5815132718Skan 5816132718Skan /* Free the pool. */ 5817132718Skan s390_free_pool (pool); 5818132718Skan} 5819132718Skan 5820132718Skan/* POOL holds the main literal pool as collected by s390_mainpool_start. 5821132718Skan We have decided we cannot use this pool, so revert all changes 5822132718Skan to the current function that were done by s390_mainpool_start. */ 5823132718Skanstatic void 5824132718Skans390_mainpool_cancel (struct constant_pool *pool) 5825132718Skan{ 5826132718Skan /* We didn't actually change the instruction stream, so simply 5827132718Skan free the pool memory. */ 5828132718Skan s390_free_pool (pool); 5829132718Skan} 5830132718Skan 5831132718Skan 5832169689Skan/* Chunkify the literal pool. */ 5833132718Skan 5834107590Sobrien#define S390_POOL_CHUNK_MIN 0xc00 5835107590Sobrien#define S390_POOL_CHUNK_MAX 0xe00 5836107590Sobrien 5837132718Skanstatic struct constant_pool * 5838169689Skans390_chunkify_start (void) 5839107590Sobrien{ 5840107590Sobrien struct constant_pool *curr_pool = NULL, *pool_list = NULL; 5841107590Sobrien int extra_size = 0; 5842107590Sobrien bitmap far_labels; 5843132718Skan rtx pending_ltrel = NULL_RTX; 5844107590Sobrien rtx insn; 5845107590Sobrien 5846132718Skan rtx (*gen_reload_base) (rtx, rtx) = 5847132718Skan TARGET_CPU_ZARCH? gen_reload_base_64 : gen_reload_base_31; 5848117395Skan 5849117395Skan 5850117395Skan /* We need correct insn addresses. */ 5851117395Skan 5852117395Skan shorten_branches (get_insns ()); 5853117395Skan 5854132718Skan /* Scan all insns and move literals to pool chunks. */ 5855107590Sobrien 5856107590Sobrien for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 5857107590Sobrien { 5858132718Skan /* Check for pending LTREL_BASE. */ 5859132718Skan if (INSN_P (insn)) 5860132718Skan { 5861132718Skan rtx ltrel_base = find_ltrel_base (PATTERN (insn)); 5862132718Skan if (ltrel_base) 5863132718Skan { 5864169689Skan gcc_assert (ltrel_base == pending_ltrel); 5865169689Skan pending_ltrel = NULL_RTX; 5866132718Skan } 5867132718Skan } 5868132718Skan 5869169689Skan if (!TARGET_CPU_ZARCH && s390_execute_label (insn)) 5870107590Sobrien { 5871169689Skan if (!curr_pool) 5872169689Skan curr_pool = s390_start_pool (&pool_list, insn); 5873169689Skan 5874169689Skan s390_add_execute (curr_pool, insn); 5875169689Skan s390_add_pool_insn (curr_pool, insn); 5876169689Skan } 5877169689Skan else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) 5878169689Skan { 5879117395Skan rtx pool_ref = NULL_RTX; 5880107590Sobrien find_constant_pool_ref (PATTERN (insn), &pool_ref); 5881107590Sobrien if (pool_ref) 5882107590Sobrien { 5883132718Skan rtx constant = get_pool_constant (pool_ref); 5884132718Skan enum machine_mode mode = get_pool_mode (pool_ref); 5885132718Skan 5886107590Sobrien if (!curr_pool) 5887107590Sobrien curr_pool = s390_start_pool (&pool_list, insn); 5888107590Sobrien 5889132718Skan s390_add_constant (curr_pool, constant, mode); 5890117395Skan s390_add_pool_insn (curr_pool, insn); 5891107590Sobrien 5892132718Skan /* Don't split the pool chunk between a LTREL_OFFSET load 5893132718Skan and the corresponding LTREL_BASE. */ 5894132718Skan if (GET_CODE (constant) == CONST 5895132718Skan && GET_CODE (XEXP (constant, 0)) == UNSPEC 5896132718Skan && XINT (XEXP (constant, 0), 1) == UNSPEC_LTREL_OFFSET) 5897132718Skan { 5898169689Skan gcc_assert (!pending_ltrel); 5899132718Skan pending_ltrel = pool_ref; 5900132718Skan } 5901107590Sobrien } 5902107590Sobrien } 5903107590Sobrien 5904117395Skan if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL) 5905132718Skan { 5906132718Skan if (curr_pool) 5907132718Skan s390_add_pool_insn (curr_pool, insn); 5908132718Skan /* An LTREL_BASE must follow within the same basic block. */ 5909169689Skan gcc_assert (!pending_ltrel); 5910132718Skan } 5911117395Skan 5912132718Skan if (!curr_pool 5913107590Sobrien || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn) 5914107590Sobrien || INSN_ADDRESSES (INSN_UID (insn)) == -1) 5915107590Sobrien continue; 5916107590Sobrien 5917132718Skan if (TARGET_CPU_ZARCH) 5918107590Sobrien { 5919107590Sobrien if (curr_pool->size < S390_POOL_CHUNK_MAX) 5920107590Sobrien continue; 5921107590Sobrien 5922117395Skan s390_end_pool (curr_pool, NULL_RTX); 5923107590Sobrien curr_pool = NULL; 5924107590Sobrien } 5925107590Sobrien else 5926107590Sobrien { 5927107590Sobrien int chunk_size = INSN_ADDRESSES (INSN_UID (insn)) 5928132718Skan - INSN_ADDRESSES (INSN_UID (curr_pool->first_insn)) 5929107590Sobrien + extra_size; 5930107590Sobrien 5931107590Sobrien /* We will later have to insert base register reload insns. 5932107590Sobrien Those will have an effect on code size, which we need to 5933107590Sobrien consider here. This calculation makes rather pessimistic 5934107590Sobrien worst-case assumptions. */ 5935117395Skan if (GET_CODE (insn) == CODE_LABEL) 5936107590Sobrien extra_size += 6; 5937107590Sobrien 5938107590Sobrien if (chunk_size < S390_POOL_CHUNK_MIN 5939107590Sobrien && curr_pool->size < S390_POOL_CHUNK_MIN) 5940107590Sobrien continue; 5941107590Sobrien 5942107590Sobrien /* Pool chunks can only be inserted after BARRIERs ... */ 5943107590Sobrien if (GET_CODE (insn) == BARRIER) 5944107590Sobrien { 5945107590Sobrien s390_end_pool (curr_pool, insn); 5946107590Sobrien curr_pool = NULL; 5947107590Sobrien extra_size = 0; 5948107590Sobrien } 5949107590Sobrien 5950107590Sobrien /* ... so if we don't find one in time, create one. */ 5951107590Sobrien else if ((chunk_size > S390_POOL_CHUNK_MAX 5952117395Skan || curr_pool->size > S390_POOL_CHUNK_MAX)) 5953107590Sobrien { 5954107590Sobrien rtx label, jump, barrier; 5955107590Sobrien 5956117395Skan /* We can insert the barrier only after a 'real' insn. */ 5957117395Skan if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN) 5958117395Skan continue; 5959117395Skan if (get_attr_length (insn) == 0) 5960117395Skan continue; 5961117395Skan 5962132718Skan /* Don't separate LTREL_BASE from the corresponding 5963132718Skan LTREL_OFFSET load. */ 5964132718Skan if (pending_ltrel) 5965117395Skan continue; 5966117395Skan 5967132718Skan label = gen_label_rtx (); 5968107590Sobrien jump = emit_jump_insn_after (gen_jump (label), insn); 5969107590Sobrien barrier = emit_barrier_after (jump); 5970107590Sobrien insn = emit_label_after (label, barrier); 5971107590Sobrien JUMP_LABEL (jump) = label; 5972107590Sobrien LABEL_NUSES (label) = 1; 5973107590Sobrien 5974117395Skan INSN_ADDRESSES_NEW (jump, -1); 5975117395Skan INSN_ADDRESSES_NEW (barrier, -1); 5976107590Sobrien INSN_ADDRESSES_NEW (insn, -1); 5977107590Sobrien 5978107590Sobrien s390_end_pool (curr_pool, barrier); 5979107590Sobrien curr_pool = NULL; 5980107590Sobrien extra_size = 0; 5981107590Sobrien } 5982107590Sobrien } 5983107590Sobrien } 5984107590Sobrien 5985117395Skan if (curr_pool) 5986117395Skan s390_end_pool (curr_pool, NULL_RTX); 5987169689Skan gcc_assert (!pending_ltrel); 5988107590Sobrien 5989132718Skan /* Find all labels that are branched into 5990107590Sobrien from an insn belonging to a different chunk. */ 5991107590Sobrien 5992169689Skan far_labels = BITMAP_ALLOC (NULL); 5993107590Sobrien 5994107590Sobrien for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 5995107590Sobrien { 5996107590Sobrien /* Labels marked with LABEL_PRESERVE_P can be target 5997107590Sobrien of non-local jumps, so we have to mark them. 5998107590Sobrien The same holds for named labels. 5999107590Sobrien 6000107590Sobrien Don't do that, however, if it is the label before 6001107590Sobrien a jump table. */ 6002107590Sobrien 6003132718Skan if (GET_CODE (insn) == CODE_LABEL 6004107590Sobrien && (LABEL_PRESERVE_P (insn) || LABEL_NAME (insn))) 6005107590Sobrien { 6006107590Sobrien rtx vec_insn = next_real_insn (insn); 6007132718Skan rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ? 6008107590Sobrien PATTERN (vec_insn) : NULL_RTX; 6009107590Sobrien if (!vec_pat 6010107590Sobrien || !(GET_CODE (vec_pat) == ADDR_VEC 6011107590Sobrien || GET_CODE (vec_pat) == ADDR_DIFF_VEC)) 6012107590Sobrien bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (insn)); 6013107590Sobrien } 6014107590Sobrien 6015107590Sobrien /* If we have a direct jump (conditional or unconditional) 6016107590Sobrien or a casesi jump, check all potential targets. */ 6017132718Skan else if (GET_CODE (insn) == JUMP_INSN) 6018107590Sobrien { 6019107590Sobrien rtx pat = PATTERN (insn); 6020117395Skan if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2) 6021117395Skan pat = XVECEXP (pat, 0, 0); 6022117395Skan 6023132718Skan if (GET_CODE (pat) == SET) 6024107590Sobrien { 6025117395Skan rtx label = JUMP_LABEL (insn); 6026107590Sobrien if (label) 6027107590Sobrien { 6028132718Skan if (s390_find_pool (pool_list, label) 6029107590Sobrien != s390_find_pool (pool_list, insn)) 6030107590Sobrien bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label)); 6031107590Sobrien } 6032132718Skan } 6033107590Sobrien else if (GET_CODE (pat) == PARALLEL 6034107590Sobrien && XVECLEN (pat, 0) == 2 6035107590Sobrien && GET_CODE (XVECEXP (pat, 0, 0)) == SET 6036107590Sobrien && GET_CODE (XVECEXP (pat, 0, 1)) == USE 6037107590Sobrien && GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == LABEL_REF) 6038107590Sobrien { 6039107590Sobrien /* Find the jump table used by this casesi jump. */ 6040107590Sobrien rtx vec_label = XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0); 6041107590Sobrien rtx vec_insn = next_real_insn (vec_label); 6042132718Skan rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ? 6043107590Sobrien PATTERN (vec_insn) : NULL_RTX; 6044107590Sobrien if (vec_pat 6045107590Sobrien && (GET_CODE (vec_pat) == ADDR_VEC 6046107590Sobrien || GET_CODE (vec_pat) == ADDR_DIFF_VEC)) 6047107590Sobrien { 6048107590Sobrien int i, diff_p = GET_CODE (vec_pat) == ADDR_DIFF_VEC; 6049107590Sobrien 6050107590Sobrien for (i = 0; i < XVECLEN (vec_pat, diff_p); i++) 6051107590Sobrien { 6052107590Sobrien rtx label = XEXP (XVECEXP (vec_pat, diff_p, i), 0); 6053107590Sobrien 6054132718Skan if (s390_find_pool (pool_list, label) 6055107590Sobrien != s390_find_pool (pool_list, insn)) 6056107590Sobrien bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label)); 6057107590Sobrien } 6058107590Sobrien } 6059107590Sobrien } 6060107590Sobrien } 6061107590Sobrien } 6062107590Sobrien 6063107590Sobrien /* Insert base register reload insns before every pool. */ 6064107590Sobrien 6065107590Sobrien for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next) 6066117395Skan { 6067169689Skan rtx new_insn = gen_reload_base (cfun->machine->base_reg, 6068169689Skan curr_pool->label); 6069117395Skan rtx insn = curr_pool->first_insn; 6070117395Skan INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1); 6071117395Skan } 6072107590Sobrien 6073107590Sobrien /* Insert base register reload insns at every far label. */ 6074107590Sobrien 6075107590Sobrien for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 6076132718Skan if (GET_CODE (insn) == CODE_LABEL 6077107590Sobrien && bitmap_bit_p (far_labels, CODE_LABEL_NUMBER (insn))) 6078107590Sobrien { 6079107590Sobrien struct constant_pool *pool = s390_find_pool (pool_list, insn); 6080107590Sobrien if (pool) 6081107590Sobrien { 6082169689Skan rtx new_insn = gen_reload_base (cfun->machine->base_reg, 6083169689Skan pool->label); 6084117395Skan INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1); 6085107590Sobrien } 6086107590Sobrien } 6087107590Sobrien 6088107590Sobrien 6089169689Skan BITMAP_FREE (far_labels); 6090107590Sobrien 6091107590Sobrien 6092107590Sobrien /* Recompute insn addresses. */ 6093107590Sobrien 6094107590Sobrien init_insn_lengths (); 6095107590Sobrien shorten_branches (get_insns ()); 6096107590Sobrien 6097117395Skan return pool_list; 6098117395Skan} 6099107590Sobrien 6100117395Skan/* POOL_LIST is a chunk list as prepared by s390_chunkify_start. 6101132718Skan After we have decided to use this list, finish implementing 6102169689Skan all changes to the current function as required. */ 6103117395Skan 6104117395Skanstatic void 6105169689Skans390_chunkify_finish (struct constant_pool *pool_list) 6106117395Skan{ 6107117395Skan struct constant_pool *curr_pool = NULL; 6108117395Skan rtx insn; 6109132718Skan 6110132718Skan 6111117395Skan /* Replace all literal pool references. */ 6112117395Skan 6113132718Skan for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 6114117395Skan { 6115132718Skan if (INSN_P (insn)) 6116169689Skan replace_ltrel_base (&PATTERN (insn)); 6117132718Skan 6118117395Skan curr_pool = s390_find_pool (pool_list, insn); 6119117395Skan if (!curr_pool) 6120117395Skan continue; 6121117395Skan 6122117395Skan if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) 6123117395Skan { 6124117395Skan rtx addr, pool_ref = NULL_RTX; 6125117395Skan find_constant_pool_ref (PATTERN (insn), &pool_ref); 6126117395Skan if (pool_ref) 6127117395Skan { 6128169689Skan if (s390_execute_label (insn)) 6129169689Skan addr = s390_find_execute (curr_pool, insn); 6130169689Skan else 6131169689Skan addr = s390_find_constant (curr_pool, 6132169689Skan get_pool_constant (pool_ref), 6133169689Skan get_pool_mode (pool_ref)); 6134169689Skan 6135117395Skan replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); 6136117395Skan INSN_CODE (insn) = -1; 6137117395Skan } 6138117395Skan } 6139117395Skan } 6140117395Skan 6141117395Skan /* Dump out all literal pools. */ 6142132718Skan 6143117395Skan for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next) 6144132718Skan s390_dump_pool (curr_pool, 0); 6145132718Skan 6146117395Skan /* Free pool list. */ 6147117395Skan 6148117395Skan while (pool_list) 6149117395Skan { 6150117395Skan struct constant_pool *next = pool_list->next; 6151117395Skan s390_free_pool (pool_list); 6152117395Skan pool_list = next; 6153117395Skan } 6154117395Skan} 6155117395Skan 6156117395Skan/* POOL_LIST is a chunk list as prepared by s390_chunkify_start. 6157117395Skan We have decided we cannot use this list, so revert all changes 6158117395Skan to the current function that were done by s390_chunkify_start. */ 6159132718Skan 6160117395Skanstatic void 6161132718Skans390_chunkify_cancel (struct constant_pool *pool_list) 6162117395Skan{ 6163117395Skan struct constant_pool *curr_pool = NULL; 6164117395Skan rtx insn; 6165117395Skan 6166117395Skan /* Remove all pool placeholder insns. */ 6167117395Skan 6168117395Skan for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next) 6169117395Skan { 6170117395Skan /* Did we insert an extra barrier? Remove it. */ 6171117395Skan rtx barrier = PREV_INSN (curr_pool->pool_insn); 6172117395Skan rtx jump = barrier? PREV_INSN (barrier) : NULL_RTX; 6173117395Skan rtx label = NEXT_INSN (curr_pool->pool_insn); 6174117395Skan 6175117395Skan if (jump && GET_CODE (jump) == JUMP_INSN 6176117395Skan && barrier && GET_CODE (barrier) == BARRIER 6177117395Skan && label && GET_CODE (label) == CODE_LABEL 6178117395Skan && GET_CODE (PATTERN (jump)) == SET 6179117395Skan && SET_DEST (PATTERN (jump)) == pc_rtx 6180117395Skan && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF 6181117395Skan && XEXP (SET_SRC (PATTERN (jump)), 0) == label) 6182117395Skan { 6183117395Skan remove_insn (jump); 6184117395Skan remove_insn (barrier); 6185117395Skan remove_insn (label); 6186107590Sobrien } 6187107590Sobrien 6188117395Skan remove_insn (curr_pool->pool_insn); 6189117395Skan } 6190107590Sobrien 6191132718Skan /* Remove all base register reload insns. */ 6192107590Sobrien 6193117395Skan for (insn = get_insns (); insn; ) 6194117395Skan { 6195117395Skan rtx next_insn = NEXT_INSN (insn); 6196117395Skan 6197117395Skan if (GET_CODE (insn) == INSN 6198117395Skan && GET_CODE (PATTERN (insn)) == SET 6199117395Skan && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC 6200132718Skan && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_RELOAD_BASE) 6201117395Skan remove_insn (insn); 6202117395Skan 6203117395Skan insn = next_insn; 6204117395Skan } 6205117395Skan 6206117395Skan /* Free pool list. */ 6207117395Skan 6208107590Sobrien while (pool_list) 6209107590Sobrien { 6210107590Sobrien struct constant_pool *next = pool_list->next; 6211107590Sobrien s390_free_pool (pool_list); 6212107590Sobrien pool_list = next; 6213107590Sobrien } 6214107590Sobrien} 6215107590Sobrien 6216107590Sobrien 6217169689Skan/* Output the constant pool entry EXP in mode MODE with alignment ALIGN. */ 6218107590Sobrien 6219107590Sobrienvoid 6220169689Skans390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align) 6221107590Sobrien{ 6222132718Skan REAL_VALUE_TYPE r; 6223132718Skan 6224132718Skan switch (GET_MODE_CLASS (mode)) 6225107590Sobrien { 6226132718Skan case MODE_FLOAT: 6227169689Skan case MODE_DECIMAL_FLOAT: 6228169689Skan gcc_assert (GET_CODE (exp) == CONST_DOUBLE); 6229117395Skan 6230132718Skan REAL_VALUE_FROM_CONST_DOUBLE (r, exp); 6231132718Skan assemble_real (r, mode, align); 6232132718Skan break; 6233132718Skan 6234132718Skan case MODE_INT: 6235169689Skan assemble_integer (exp, GET_MODE_SIZE (mode), align, 1); 6236132718Skan break; 6237132718Skan 6238132718Skan default: 6239169689Skan gcc_unreachable (); 6240117395Skan } 6241117395Skan} 6242117395Skan 6243132718Skan 6244169689Skan/* Return an RTL expression representing the value of the return address 6245169689Skan for the frame COUNT steps up from the current frame. FRAME is the 6246169689Skan frame pointer of that frame. */ 6247117395Skan 6248169689Skanrtx 6249169689Skans390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED) 6250117395Skan{ 6251169689Skan int offset; 6252169689Skan rtx addr; 6253117395Skan 6254169689Skan /* Without backchain, we fail for all but the current frame. */ 6255117395Skan 6256169689Skan if (!TARGET_BACKCHAIN && count > 0) 6257169689Skan return NULL_RTX; 6258117395Skan 6259169689Skan /* For the current frame, we need to make sure the initial 6260169689Skan value of RETURN_REGNUM is actually saved. */ 6261117395Skan 6262169689Skan if (count == 0) 6263117395Skan { 6264169689Skan /* On non-z architectures branch splitting could overwrite r14. */ 6265169689Skan if (TARGET_CPU_ZARCH) 6266169689Skan return get_hard_reg_initial_val (Pmode, RETURN_REGNUM); 6267169689Skan else 6268169689Skan { 6269169689Skan cfun_frame_layout.save_return_addr_p = true; 6270169689Skan return gen_rtx_MEM (Pmode, return_address_pointer_rtx); 6271169689Skan } 6272117395Skan } 6273169689Skan 6274169689Skan if (TARGET_PACKED_STACK) 6275169689Skan offset = -2 * UNITS_PER_WORD; 6276117395Skan else 6277169689Skan offset = RETURN_REGNUM * UNITS_PER_WORD; 6278117395Skan 6279169689Skan addr = plus_constant (frame, offset); 6280169689Skan addr = memory_address (Pmode, addr); 6281169689Skan return gen_rtx_MEM (Pmode, addr); 6282169689Skan} 6283117395Skan 6284169689Skan/* Return an RTL expression representing the back chain stored in 6285169689Skan the current stack frame. */ 6286117395Skan 6287169689Skanrtx 6288169689Skans390_back_chain_rtx (void) 6289169689Skan{ 6290169689Skan rtx chain; 6291117395Skan 6292169689Skan gcc_assert (TARGET_BACKCHAIN); 6293117395Skan 6294169689Skan if (TARGET_PACKED_STACK) 6295169689Skan chain = plus_constant (stack_pointer_rtx, 6296169689Skan STACK_POINTER_OFFSET - UNITS_PER_WORD); 6297169689Skan else 6298169689Skan chain = stack_pointer_rtx; 6299117395Skan 6300169689Skan chain = gen_rtx_MEM (Pmode, chain); 6301169689Skan return chain; 6302169689Skan} 6303117395Skan 6304169689Skan/* Find first call clobbered register unused in a function. 6305169689Skan This could be used as base register in a leaf function 6306169689Skan or for holding the return address before epilogue. */ 6307117395Skan 6308169689Skanstatic int 6309169689Skanfind_unused_clobbered_reg (void) 6310169689Skan{ 6311169689Skan int i; 6312169689Skan for (i = 0; i < 6; i++) 6313169689Skan if (!regs_ever_live[i]) 6314169689Skan return i; 6315169689Skan return 0; 6316169689Skan} 6317117395Skan 6318117395Skan 6319169689Skan/* Helper function for s390_regs_ever_clobbered. Sets the fields in DATA for all 6320169689Skan clobbered hard regs in SETREG. */ 6321132718Skan 6322169689Skanstatic void 6323169689Skans390_reg_clobbered_rtx (rtx setreg, rtx set_insn ATTRIBUTE_UNUSED, void *data) 6324169689Skan{ 6325169689Skan int *regs_ever_clobbered = (int *)data; 6326169689Skan unsigned int i, regno; 6327169689Skan enum machine_mode mode = GET_MODE (setreg); 6328132718Skan 6329169689Skan if (GET_CODE (setreg) == SUBREG) 6330169689Skan { 6331169689Skan rtx inner = SUBREG_REG (setreg); 6332169689Skan if (!GENERAL_REG_P (inner)) 6333169689Skan return; 6334169689Skan regno = subreg_regno (setreg); 6335169689Skan } 6336169689Skan else if (GENERAL_REG_P (setreg)) 6337169689Skan regno = REGNO (setreg); 6338169689Skan else 6339169689Skan return; 6340132718Skan 6341169689Skan for (i = regno; 6342169689Skan i < regno + HARD_REGNO_NREGS (regno, mode); 6343169689Skan i++) 6344169689Skan regs_ever_clobbered[i] = 1; 6345169689Skan} 6346132718Skan 6347169689Skan/* Walks through all basic blocks of the current function looking 6348169689Skan for clobbered hard regs using s390_reg_clobbered_rtx. The fields 6349169689Skan of the passed integer array REGS_EVER_CLOBBERED are set to one for 6350169689Skan each of those regs. */ 6351117395Skan 6352169689Skanstatic void 6353169689Skans390_regs_ever_clobbered (int *regs_ever_clobbered) 6354169689Skan{ 6355169689Skan basic_block cur_bb; 6356169689Skan rtx cur_insn; 6357169689Skan unsigned int i; 6358117395Skan 6359169689Skan memset (regs_ever_clobbered, 0, 16 * sizeof (int)); 6360117395Skan 6361169689Skan /* For non-leaf functions we have to consider all call clobbered regs to be 6362169689Skan clobbered. */ 6363169689Skan if (!current_function_is_leaf) 6364169689Skan { 6365169689Skan for (i = 0; i < 16; i++) 6366169689Skan regs_ever_clobbered[i] = call_really_used_regs[i]; 6367169689Skan } 6368117395Skan 6369169689Skan /* Make the "magic" eh_return registers live if necessary. For regs_ever_live 6370169689Skan this work is done by liveness analysis (mark_regs_live_at_end). 6371169689Skan Special care is needed for functions containing landing pads. Landing pads 6372169689Skan may use the eh registers, but the code which sets these registers is not 6373169689Skan contained in that function. Hence s390_regs_ever_clobbered is not able to 6374169689Skan deal with this automatically. */ 6375169689Skan if (current_function_calls_eh_return || cfun->machine->has_landing_pad_p) 6376169689Skan for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM ; i++) 6377169689Skan if (current_function_calls_eh_return 6378169689Skan || (cfun->machine->has_landing_pad_p 6379169689Skan && regs_ever_live [EH_RETURN_DATA_REGNO (i)])) 6380169689Skan regs_ever_clobbered[EH_RETURN_DATA_REGNO (i)] = 1; 6381117395Skan 6382169689Skan /* For nonlocal gotos all call-saved registers have to be saved. 6383169689Skan This flag is also set for the unwinding code in libgcc. 6384169689Skan See expand_builtin_unwind_init. For regs_ever_live this is done by 6385169689Skan reload. */ 6386169689Skan if (current_function_has_nonlocal_label) 6387169689Skan for (i = 0; i < 16; i++) 6388169689Skan if (!call_really_used_regs[i]) 6389169689Skan regs_ever_clobbered[i] = 1; 6390117395Skan 6391169689Skan FOR_EACH_BB (cur_bb) 6392169689Skan { 6393169689Skan FOR_BB_INSNS (cur_bb, cur_insn) 6394169689Skan { 6395169689Skan if (INSN_P (cur_insn)) 6396169689Skan note_stores (PATTERN (cur_insn), 6397169689Skan s390_reg_clobbered_rtx, 6398169689Skan regs_ever_clobbered); 6399117395Skan } 6400169689Skan } 6401169689Skan} 6402117395Skan 6403169689Skan/* Determine the frame area which actually has to be accessed 6404169689Skan in the function epilogue. The values are stored at the 6405169689Skan given pointers AREA_BOTTOM (address of the lowest used stack 6406169689Skan address) and AREA_TOP (address of the first item which does 6407169689Skan not belong to the stack frame). */ 6408117395Skan 6409169689Skanstatic void 6410169689Skans390_frame_area (int *area_bottom, int *area_top) 6411169689Skan{ 6412169689Skan int b, t; 6413169689Skan int i; 6414117395Skan 6415169689Skan b = INT_MAX; 6416169689Skan t = INT_MIN; 6417117395Skan 6418169689Skan if (cfun_frame_layout.first_restore_gpr != -1) 6419169689Skan { 6420169689Skan b = (cfun_frame_layout.gprs_offset 6421169689Skan + cfun_frame_layout.first_restore_gpr * UNITS_PER_WORD); 6422169689Skan t = b + (cfun_frame_layout.last_restore_gpr 6423169689Skan - cfun_frame_layout.first_restore_gpr + 1) * UNITS_PER_WORD; 6424169689Skan } 6425169689Skan 6426169689Skan if (TARGET_64BIT && cfun_save_high_fprs_p) 6427169689Skan { 6428169689Skan b = MIN (b, cfun_frame_layout.f8_offset); 6429169689Skan t = MAX (t, (cfun_frame_layout.f8_offset 6430169689Skan + cfun_frame_layout.high_fprs * 8)); 6431169689Skan } 6432169689Skan 6433169689Skan if (!TARGET_64BIT) 6434169689Skan for (i = 2; i < 4; i++) 6435169689Skan if (cfun_fpr_bit_p (i)) 6436169689Skan { 6437169689Skan b = MIN (b, cfun_frame_layout.f4_offset + (i - 2) * 8); 6438169689Skan t = MAX (t, cfun_frame_layout.f4_offset + (i - 1) * 8); 6439107590Sobrien } 6440169689Skan 6441169689Skan *area_bottom = b; 6442169689Skan *area_top = t; 6443107590Sobrien} 6444107590Sobrien 6445169689Skan/* Fill cfun->machine with info about register usage of current function. 6446169689Skan Return in CLOBBERED_REGS which GPRs are currently considered set. */ 6447107590Sobrien 6448132718Skanstatic void 6449169689Skans390_register_info (int clobbered_regs[]) 6450117395Skan{ 6451169689Skan int i, j; 6452107590Sobrien 6453169689Skan /* fprs 8 - 15 are call saved for 64 Bit ABI. */ 6454169689Skan cfun_frame_layout.fpr_bitmap = 0; 6455169689Skan cfun_frame_layout.high_fprs = 0; 6456169689Skan if (TARGET_64BIT) 6457169689Skan for (i = 24; i < 32; i++) 6458169689Skan if (regs_ever_live[i] && !global_regs[i]) 6459169689Skan { 6460169689Skan cfun_set_fpr_bit (i - 16); 6461169689Skan cfun_frame_layout.high_fprs++; 6462169689Skan } 6463117395Skan 6464169689Skan /* Find first and last gpr to be saved. We trust regs_ever_live 6465169689Skan data, except that we don't save and restore global registers. 6466117395Skan 6467169689Skan Also, all registers with special meaning to the compiler need 6468169689Skan to be handled extra. */ 6469132718Skan 6470169689Skan s390_regs_ever_clobbered (clobbered_regs); 6471132718Skan 6472169689Skan for (i = 0; i < 16; i++) 6473169689Skan clobbered_regs[i] = clobbered_regs[i] && !global_regs[i] && !fixed_regs[i]; 6474132718Skan 6475169689Skan if (frame_pointer_needed) 6476169689Skan clobbered_regs[HARD_FRAME_POINTER_REGNUM] = 1; 6477132718Skan 6478169689Skan if (flag_pic) 6479169689Skan clobbered_regs[PIC_OFFSET_TABLE_REGNUM] 6480169689Skan |= regs_ever_live[PIC_OFFSET_TABLE_REGNUM]; 6481132718Skan 6482169689Skan clobbered_regs[BASE_REGNUM] 6483169689Skan |= (cfun->machine->base_reg 6484169689Skan && REGNO (cfun->machine->base_reg) == BASE_REGNUM); 6485132718Skan 6486169689Skan clobbered_regs[RETURN_REGNUM] 6487169689Skan |= (!current_function_is_leaf 6488169689Skan || TARGET_TPF_PROFILING 6489169689Skan || cfun->machine->split_branches_pending_p 6490169689Skan || cfun_frame_layout.save_return_addr_p 6491169689Skan || current_function_calls_eh_return 6492169689Skan || current_function_stdarg); 6493132718Skan 6494169689Skan clobbered_regs[STACK_POINTER_REGNUM] 6495169689Skan |= (!current_function_is_leaf 6496169689Skan || TARGET_TPF_PROFILING 6497169689Skan || cfun_save_high_fprs_p 6498169689Skan || get_frame_size () > 0 6499169689Skan || current_function_calls_alloca 6500169689Skan || current_function_stdarg); 6501132718Skan 6502169689Skan for (i = 6; i < 16; i++) 6503169689Skan if (regs_ever_live[i] || clobbered_regs[i]) 6504169689Skan break; 6505169689Skan for (j = 15; j > i; j--) 6506169689Skan if (regs_ever_live[j] || clobbered_regs[j]) 6507169689Skan break; 6508132718Skan 6509169689Skan if (i == 16) 6510107590Sobrien { 6511169689Skan /* Nothing to save/restore. */ 6512169689Skan cfun_frame_layout.first_save_gpr_slot = -1; 6513169689Skan cfun_frame_layout.last_save_gpr_slot = -1; 6514169689Skan cfun_frame_layout.first_save_gpr = -1; 6515169689Skan cfun_frame_layout.first_restore_gpr = -1; 6516169689Skan cfun_frame_layout.last_save_gpr = -1; 6517169689Skan cfun_frame_layout.last_restore_gpr = -1; 6518169689Skan } 6519169689Skan else 6520169689Skan { 6521169689Skan /* Save slots for gprs from i to j. */ 6522169689Skan cfun_frame_layout.first_save_gpr_slot = i; 6523169689Skan cfun_frame_layout.last_save_gpr_slot = j; 6524117395Skan 6525169689Skan for (i = cfun_frame_layout.first_save_gpr_slot; 6526169689Skan i < cfun_frame_layout.last_save_gpr_slot + 1; 6527169689Skan i++) 6528169689Skan if (clobbered_regs[i]) 6529169689Skan break; 6530169689Skan 6531169689Skan for (j = cfun_frame_layout.last_save_gpr_slot; j > i; j--) 6532169689Skan if (clobbered_regs[j]) 6533169689Skan break; 6534169689Skan 6535169689Skan if (i == cfun_frame_layout.last_save_gpr_slot + 1) 6536132718Skan { 6537169689Skan /* Nothing to save/restore. */ 6538169689Skan cfun_frame_layout.first_save_gpr = -1; 6539169689Skan cfun_frame_layout.first_restore_gpr = -1; 6540169689Skan cfun_frame_layout.last_save_gpr = -1; 6541169689Skan cfun_frame_layout.last_restore_gpr = -1; 6542132718Skan } 6543169689Skan else 6544169689Skan { 6545169689Skan /* Save / Restore from gpr i to j. */ 6546169689Skan cfun_frame_layout.first_save_gpr = i; 6547169689Skan cfun_frame_layout.first_restore_gpr = i; 6548169689Skan cfun_frame_layout.last_save_gpr = j; 6549169689Skan cfun_frame_layout.last_restore_gpr = j; 6550169689Skan } 6551169689Skan } 6552132718Skan 6553169689Skan if (current_function_stdarg) 6554169689Skan { 6555169689Skan /* Varargs functions need to save gprs 2 to 6. */ 6556169689Skan if (cfun->va_list_gpr_size 6557169689Skan && current_function_args_info.gprs < GP_ARG_NUM_REG) 6558169689Skan { 6559169689Skan int min_gpr = current_function_args_info.gprs; 6560169689Skan int max_gpr = min_gpr + cfun->va_list_gpr_size; 6561169689Skan if (max_gpr > GP_ARG_NUM_REG) 6562169689Skan max_gpr = GP_ARG_NUM_REG; 6563132718Skan 6564169689Skan if (cfun_frame_layout.first_save_gpr == -1 6565169689Skan || cfun_frame_layout.first_save_gpr > 2 + min_gpr) 6566169689Skan { 6567169689Skan cfun_frame_layout.first_save_gpr = 2 + min_gpr; 6568169689Skan cfun_frame_layout.first_save_gpr_slot = 2 + min_gpr; 6569169689Skan } 6570132718Skan 6571169689Skan if (cfun_frame_layout.last_save_gpr == -1 6572169689Skan || cfun_frame_layout.last_save_gpr < 2 + max_gpr - 1) 6573169689Skan { 6574169689Skan cfun_frame_layout.last_save_gpr = 2 + max_gpr - 1; 6575169689Skan cfun_frame_layout.last_save_gpr_slot = 2 + max_gpr - 1; 6576169689Skan } 6577169689Skan } 6578117395Skan 6579169689Skan /* Mark f0, f2 for 31 bit and f0-f4 for 64 bit to be saved. */ 6580169689Skan if (TARGET_HARD_FLOAT && cfun->va_list_fpr_size 6581169689Skan && current_function_args_info.fprs < FP_ARG_NUM_REG) 6582169689Skan { 6583169689Skan int min_fpr = current_function_args_info.fprs; 6584169689Skan int max_fpr = min_fpr + cfun->va_list_fpr_size; 6585169689Skan if (max_fpr > FP_ARG_NUM_REG) 6586169689Skan max_fpr = FP_ARG_NUM_REG; 6587117395Skan 6588169689Skan /* ??? This is currently required to ensure proper location 6589169689Skan of the fpr save slots within the va_list save area. */ 6590169689Skan if (TARGET_PACKED_STACK) 6591169689Skan min_fpr = 0; 6592117395Skan 6593169689Skan for (i = min_fpr; i < max_fpr; i++) 6594169689Skan cfun_set_fpr_bit (i); 6595169689Skan } 6596107590Sobrien } 6597132718Skan 6598169689Skan if (!TARGET_64BIT) 6599169689Skan for (i = 2; i < 4; i++) 6600169689Skan if (regs_ever_live[i + 16] && !global_regs[i + 16]) 6601169689Skan cfun_set_fpr_bit (i); 6602107590Sobrien} 6603107590Sobrien 6604169689Skan/* Fill cfun->machine with info about frame of current function. */ 6605117395Skan 6606169689Skanstatic void 6607169689Skans390_frame_info (void) 6608117395Skan{ 6609169689Skan int i; 6610117395Skan 6611169689Skan cfun_frame_layout.frame_size = get_frame_size (); 6612169689Skan if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000) 6613169689Skan fatal_error ("total size of local variables exceeds architecture limit"); 6614169689Skan 6615169689Skan if (!TARGET_PACKED_STACK) 6616169689Skan { 6617169689Skan cfun_frame_layout.backchain_offset = 0; 6618169689Skan cfun_frame_layout.f0_offset = 16 * UNITS_PER_WORD; 6619169689Skan cfun_frame_layout.f4_offset = cfun_frame_layout.f0_offset + 2 * 8; 6620169689Skan cfun_frame_layout.f8_offset = -cfun_frame_layout.high_fprs * 8; 6621169689Skan cfun_frame_layout.gprs_offset = (cfun_frame_layout.first_save_gpr_slot 6622169689Skan * UNITS_PER_WORD); 6623169689Skan } 6624169689Skan else if (TARGET_BACKCHAIN) /* kernel stack layout */ 6625169689Skan { 6626169689Skan cfun_frame_layout.backchain_offset = (STACK_POINTER_OFFSET 6627169689Skan - UNITS_PER_WORD); 6628169689Skan cfun_frame_layout.gprs_offset 6629169689Skan = (cfun_frame_layout.backchain_offset 6630169689Skan - (STACK_POINTER_REGNUM - cfun_frame_layout.first_save_gpr_slot + 1) 6631169689Skan * UNITS_PER_WORD); 6632169689Skan 6633169689Skan if (TARGET_64BIT) 6634169689Skan { 6635169689Skan cfun_frame_layout.f4_offset 6636169689Skan = (cfun_frame_layout.gprs_offset 6637169689Skan - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3))); 6638169689Skan 6639169689Skan cfun_frame_layout.f0_offset 6640169689Skan = (cfun_frame_layout.f4_offset 6641169689Skan - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1))); 6642169689Skan } 6643169689Skan else 6644169689Skan { 6645169689Skan /* On 31 bit we have to care about alignment of the 6646169689Skan floating point regs to provide fastest access. */ 6647169689Skan cfun_frame_layout.f0_offset 6648169689Skan = ((cfun_frame_layout.gprs_offset 6649169689Skan & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1)) 6650169689Skan - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1))); 6651169689Skan 6652169689Skan cfun_frame_layout.f4_offset 6653169689Skan = (cfun_frame_layout.f0_offset 6654169689Skan - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3))); 6655169689Skan } 6656169689Skan } 6657169689Skan else /* no backchain */ 6658169689Skan { 6659169689Skan cfun_frame_layout.f4_offset 6660169689Skan = (STACK_POINTER_OFFSET 6661169689Skan - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3))); 6662169689Skan 6663169689Skan cfun_frame_layout.f0_offset 6664169689Skan = (cfun_frame_layout.f4_offset 6665169689Skan - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1))); 6666169689Skan 6667169689Skan cfun_frame_layout.gprs_offset 6668169689Skan = cfun_frame_layout.f0_offset - cfun_gprs_save_area_size; 6669169689Skan } 6670117395Skan 6671169689Skan if (current_function_is_leaf 6672169689Skan && !TARGET_TPF_PROFILING 6673169689Skan && cfun_frame_layout.frame_size == 0 6674169689Skan && !cfun_save_high_fprs_p 6675169689Skan && !current_function_calls_alloca 6676169689Skan && !current_function_stdarg) 6677169689Skan return; 6678132718Skan 6679169689Skan if (!TARGET_PACKED_STACK) 6680169689Skan cfun_frame_layout.frame_size += (STACK_POINTER_OFFSET 6681169689Skan + current_function_outgoing_args_size 6682169689Skan + cfun_frame_layout.high_fprs * 8); 6683169689Skan else 6684169689Skan { 6685169689Skan if (TARGET_BACKCHAIN) 6686169689Skan cfun_frame_layout.frame_size += UNITS_PER_WORD; 6687132718Skan 6688169689Skan /* No alignment trouble here because f8-f15 are only saved under 6689169689Skan 64 bit. */ 6690169689Skan cfun_frame_layout.f8_offset = (MIN (MIN (cfun_frame_layout.f0_offset, 6691169689Skan cfun_frame_layout.f4_offset), 6692169689Skan cfun_frame_layout.gprs_offset) 6693169689Skan - cfun_frame_layout.high_fprs * 8); 6694117395Skan 6695169689Skan cfun_frame_layout.frame_size += cfun_frame_layout.high_fprs * 8; 6696117395Skan 6697169689Skan for (i = 0; i < 8; i++) 6698169689Skan if (cfun_fpr_bit_p (i)) 6699169689Skan cfun_frame_layout.frame_size += 8; 6700169689Skan 6701169689Skan cfun_frame_layout.frame_size += cfun_gprs_save_area_size; 6702169689Skan 6703169689Skan /* If under 31 bit an odd number of gprs has to be saved we have to adjust 6704169689Skan the frame size to sustain 8 byte alignment of stack frames. */ 6705169689Skan cfun_frame_layout.frame_size = ((cfun_frame_layout.frame_size + 6706169689Skan STACK_BOUNDARY / BITS_PER_UNIT - 1) 6707169689Skan & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1)); 6708169689Skan 6709169689Skan cfun_frame_layout.frame_size += current_function_outgoing_args_size; 6710169689Skan } 6711132718Skan} 6712117395Skan 6713169689Skan/* Generate frame layout. Fills in register and frame data for the current 6714169689Skan function in cfun->machine. This routine can be called multiple times; 6715169689Skan it will re-do the complete frame layout every time. */ 6716107590Sobrien 6717169689Skanstatic void 6718169689Skans390_init_frame_layout (void) 6719107590Sobrien{ 6720169689Skan HOST_WIDE_INT frame_size; 6721169689Skan int base_used; 6722169689Skan int clobbered_regs[16]; 6723169689Skan 6724169689Skan /* On S/390 machines, we may need to perform branch splitting, which 6725169689Skan will require both base and return address register. We have no 6726169689Skan choice but to assume we're going to need them until right at the 6727169689Skan end of the machine dependent reorg phase. */ 6728169689Skan if (!TARGET_CPU_ZARCH) 6729169689Skan cfun->machine->split_branches_pending_p = true; 6730169689Skan 6731169689Skan do 6732169689Skan { 6733169689Skan frame_size = cfun_frame_layout.frame_size; 6734169689Skan 6735169689Skan /* Try to predict whether we'll need the base register. */ 6736169689Skan base_used = cfun->machine->split_branches_pending_p 6737169689Skan || current_function_uses_const_pool 6738169689Skan || (!DISP_IN_RANGE (frame_size) 6739169689Skan && !CONST_OK_FOR_K (frame_size)); 6740169689Skan 6741169689Skan /* Decide which register to use as literal pool base. In small 6742169689Skan leaf functions, try to use an unused call-clobbered register 6743169689Skan as base register to avoid save/restore overhead. */ 6744169689Skan if (!base_used) 6745169689Skan cfun->machine->base_reg = NULL_RTX; 6746169689Skan else if (current_function_is_leaf && !regs_ever_live[5]) 6747169689Skan cfun->machine->base_reg = gen_rtx_REG (Pmode, 5); 6748169689Skan else 6749169689Skan cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM); 6750169689Skan 6751169689Skan s390_register_info (clobbered_regs); 6752169689Skan s390_frame_info (); 6753169689Skan } 6754169689Skan while (frame_size != cfun_frame_layout.frame_size); 6755107590Sobrien} 6756107590Sobrien 6757169689Skan/* Update frame layout. Recompute actual register save data based on 6758169689Skan current info and update regs_ever_live for the special registers. 6759169689Skan May be called multiple times, but may never cause *more* registers 6760169689Skan to be saved than s390_init_frame_layout allocated room for. */ 6761107590Sobrien 6762107590Sobrienstatic void 6763169689Skans390_update_frame_layout (void) 6764107590Sobrien{ 6765169689Skan int clobbered_regs[16]; 6766107590Sobrien 6767169689Skan s390_register_info (clobbered_regs); 6768107590Sobrien 6769169689Skan regs_ever_live[BASE_REGNUM] = clobbered_regs[BASE_REGNUM]; 6770169689Skan regs_ever_live[RETURN_REGNUM] = clobbered_regs[RETURN_REGNUM]; 6771169689Skan regs_ever_live[STACK_POINTER_REGNUM] = clobbered_regs[STACK_POINTER_REGNUM]; 6772169689Skan 6773169689Skan if (cfun->machine->base_reg) 6774169689Skan regs_ever_live[REGNO (cfun->machine->base_reg)] = 1; 6775169689Skan} 6776169689Skan 6777169689Skan/* Return true if it is legal to put a value with MODE into REGNO. */ 6778169689Skan 6779169689Skanbool 6780169689Skans390_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) 6781169689Skan{ 6782169689Skan switch (REGNO_REG_CLASS (regno)) 6783169689Skan { 6784169689Skan case FP_REGS: 6785169689Skan if (REGNO_PAIR_OK (regno, mode)) 6786117395Skan { 6787169689Skan if (mode == SImode || mode == DImode) 6788169689Skan return true; 6789169689Skan 6790169689Skan if (FLOAT_MODE_P (mode) && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) 6791169689Skan return true; 6792117395Skan } 6793169689Skan break; 6794169689Skan case ADDR_REGS: 6795169689Skan if (FRAME_REGNO_P (regno) && mode == Pmode) 6796169689Skan return true; 6797107590Sobrien 6798169689Skan /* fallthrough */ 6799169689Skan case GENERAL_REGS: 6800169689Skan if (REGNO_PAIR_OK (regno, mode)) 6801169689Skan { 6802169689Skan if (TARGET_64BIT 6803169689Skan || (mode != TFmode && mode != TCmode && mode != TDmode)) 6804169689Skan return true; 6805169689Skan } 6806169689Skan break; 6807169689Skan case CC_REGS: 6808169689Skan if (GET_MODE_CLASS (mode) == MODE_CC) 6809169689Skan return true; 6810169689Skan break; 6811169689Skan case ACCESS_REGS: 6812169689Skan if (REGNO_PAIR_OK (regno, mode)) 6813169689Skan { 6814169689Skan if (mode == SImode || mode == Pmode) 6815169689Skan return true; 6816169689Skan } 6817169689Skan break; 6818169689Skan default: 6819169689Skan return false; 6820169689Skan } 6821169689Skan 6822169689Skan return false; 6823169689Skan} 6824107590Sobrien 6825169689Skan/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */ 6826132718Skan 6827169689Skanbool 6828169689Skans390_hard_regno_rename_ok (unsigned int old_reg, unsigned int new_reg) 6829169689Skan{ 6830169689Skan /* Once we've decided upon a register to use as base register, it must 6831169689Skan no longer be used for any other purpose. */ 6832169689Skan if (cfun->machine->base_reg) 6833169689Skan if (REGNO (cfun->machine->base_reg) == old_reg 6834169689Skan || REGNO (cfun->machine->base_reg) == new_reg) 6835169689Skan return false; 6836107590Sobrien 6837169689Skan return true; 6838169689Skan} 6839132718Skan 6840169689Skan/* Maximum number of registers to represent a value of mode MODE 6841169689Skan in a register of class CLASS. */ 6842132718Skan 6843169689Skanbool 6844169689Skans390_class_max_nregs (enum reg_class class, enum machine_mode mode) 6845169689Skan{ 6846169689Skan switch (class) 6847169689Skan { 6848169689Skan case FP_REGS: 6849169689Skan if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) 6850169689Skan return 2 * ((GET_MODE_SIZE (mode) / 2 + 8 - 1) / 8); 6851169689Skan else 6852169689Skan return (GET_MODE_SIZE (mode) + 8 - 1) / 8; 6853169689Skan case ACCESS_REGS: 6854169689Skan return (GET_MODE_SIZE (mode) + 4 - 1) / 4; 6855169689Skan default: 6856169689Skan break; 6857169689Skan } 6858169689Skan return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 6859169689Skan} 6860107590Sobrien 6861169689Skan/* Return true if register FROM can be eliminated via register TO. */ 6862107590Sobrien 6863169689Skanbool 6864169689Skans390_can_eliminate (int from, int to) 6865169689Skan{ 6866169689Skan /* On zSeries machines, we have not marked the base register as fixed. 6867169689Skan Instead, we have an elimination rule BASE_REGNUM -> BASE_REGNUM. 6868169689Skan If a function requires the base register, we say here that this 6869169689Skan elimination cannot be performed. This will cause reload to free 6870169689Skan up the base register (as if it were fixed). On the other hand, 6871169689Skan if the current function does *not* require the base register, we 6872169689Skan say here the elimination succeeds, which in turn allows reload 6873169689Skan to allocate the base register for any other purpose. */ 6874169689Skan if (from == BASE_REGNUM && to == BASE_REGNUM) 6875169689Skan { 6876169689Skan if (TARGET_CPU_ZARCH) 6877169689Skan { 6878169689Skan s390_init_frame_layout (); 6879169689Skan return cfun->machine->base_reg == NULL_RTX; 6880169689Skan } 6881107590Sobrien 6882169689Skan return false; 6883169689Skan } 6884107590Sobrien 6885169689Skan /* Everything else must point into the stack frame. */ 6886169689Skan gcc_assert (to == STACK_POINTER_REGNUM 6887169689Skan || to == HARD_FRAME_POINTER_REGNUM); 6888117395Skan 6889169689Skan gcc_assert (from == FRAME_POINTER_REGNUM 6890169689Skan || from == ARG_POINTER_REGNUM 6891169689Skan || from == RETURN_ADDRESS_POINTER_REGNUM); 6892169689Skan 6893169689Skan /* Make sure we actually saved the return address. */ 6894169689Skan if (from == RETURN_ADDRESS_POINTER_REGNUM) 6895169689Skan if (!current_function_calls_eh_return 6896169689Skan && !current_function_stdarg 6897169689Skan && !cfun_frame_layout.save_return_addr_p) 6898169689Skan return false; 6899169689Skan 6900169689Skan return true; 6901107590Sobrien} 6902107590Sobrien 6903169689Skan/* Return offset between register FROM and TO initially after prolog. */ 6904107590Sobrien 6905132718SkanHOST_WIDE_INT 6906169689Skans390_initial_elimination_offset (int from, int to) 6907107590Sobrien{ 6908169689Skan HOST_WIDE_INT offset; 6909169689Skan int index; 6910107590Sobrien 6911169689Skan /* ??? Why are we called for non-eliminable pairs? */ 6912169689Skan if (!s390_can_eliminate (from, to)) 6913169689Skan return 0; 6914107590Sobrien 6915169689Skan switch (from) 6916169689Skan { 6917169689Skan case FRAME_POINTER_REGNUM: 6918169689Skan offset = (get_frame_size() 6919169689Skan + STACK_POINTER_OFFSET 6920169689Skan + current_function_outgoing_args_size); 6921169689Skan break; 6922107590Sobrien 6923169689Skan case ARG_POINTER_REGNUM: 6924169689Skan s390_init_frame_layout (); 6925169689Skan offset = cfun_frame_layout.frame_size + STACK_POINTER_OFFSET; 6926169689Skan break; 6927132718Skan 6928169689Skan case RETURN_ADDRESS_POINTER_REGNUM: 6929169689Skan s390_init_frame_layout (); 6930169689Skan index = RETURN_REGNUM - cfun_frame_layout.first_save_gpr_slot; 6931169689Skan gcc_assert (index >= 0); 6932169689Skan offset = cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset; 6933169689Skan offset += index * UNITS_PER_WORD; 6934169689Skan break; 6935169689Skan 6936169689Skan case BASE_REGNUM: 6937169689Skan offset = 0; 6938169689Skan break; 6939169689Skan 6940169689Skan default: 6941169689Skan gcc_unreachable (); 6942169689Skan } 6943169689Skan 6944169689Skan return offset; 6945107590Sobrien} 6946107590Sobrien 6947107590Sobrien/* Emit insn to save fpr REGNUM at offset OFFSET relative 6948132718Skan to register BASE. Return generated insn. */ 6949107590Sobrien 6950107590Sobrienstatic rtx 6951132718Skansave_fpr (rtx base, int offset, int regnum) 6952107590Sobrien{ 6953107590Sobrien rtx addr; 6954107590Sobrien addr = gen_rtx_MEM (DFmode, plus_constant (base, offset)); 6955107590Sobrien 6956169689Skan if (regnum >= 16 && regnum <= (16 + FP_ARG_NUM_REG)) 6957169689Skan set_mem_alias_set (addr, get_varargs_alias_set ()); 6958169689Skan else 6959169689Skan set_mem_alias_set (addr, get_frame_alias_set ()); 6960169689Skan 6961107590Sobrien return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum)); 6962107590Sobrien} 6963107590Sobrien 6964107590Sobrien/* Emit insn to restore fpr REGNUM from offset OFFSET relative 6965132718Skan to register BASE. Return generated insn. */ 6966107590Sobrien 6967107590Sobrienstatic rtx 6968132718Skanrestore_fpr (rtx base, int offset, int regnum) 6969107590Sobrien{ 6970107590Sobrien rtx addr; 6971107590Sobrien addr = gen_rtx_MEM (DFmode, plus_constant (base, offset)); 6972169689Skan set_mem_alias_set (addr, get_frame_alias_set ()); 6973107590Sobrien 6974107590Sobrien return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr); 6975107590Sobrien} 6976107590Sobrien 6977117395Skan/* Generate insn to save registers FIRST to LAST into 6978132718Skan the register save area located at offset OFFSET 6979117395Skan relative to register BASE. */ 6980107590Sobrien 6981117395Skanstatic rtx 6982132718Skansave_gprs (rtx base, int offset, int first, int last) 6983107590Sobrien{ 6984117395Skan rtx addr, insn, note; 6985117395Skan int i; 6986117395Skan 6987169689Skan addr = plus_constant (base, offset); 6988117395Skan addr = gen_rtx_MEM (Pmode, addr); 6989117395Skan 6990169689Skan set_mem_alias_set (addr, get_frame_alias_set ()); 6991169689Skan 6992117395Skan /* Special-case single register. */ 6993117395Skan if (first == last) 6994117395Skan { 6995117395Skan if (TARGET_64BIT) 6996117395Skan insn = gen_movdi (addr, gen_rtx_REG (Pmode, first)); 6997117395Skan else 6998117395Skan insn = gen_movsi (addr, gen_rtx_REG (Pmode, first)); 6999117395Skan 7000117395Skan RTX_FRAME_RELATED_P (insn) = 1; 7001117395Skan return insn; 7002117395Skan } 7003117395Skan 7004117395Skan 7005117395Skan insn = gen_store_multiple (addr, 7006117395Skan gen_rtx_REG (Pmode, first), 7007117395Skan GEN_INT (last - first + 1)); 7008117395Skan 7009169689Skan if (first <= 6 && current_function_stdarg) 7010169689Skan for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) 7011169689Skan { 7012169689Skan rtx mem = XEXP (XVECEXP (PATTERN (insn), 0, i), 0); 7013169689Skan 7014169689Skan if (first + i <= 6) 7015169689Skan set_mem_alias_set (mem, get_varargs_alias_set ()); 7016169689Skan } 7017117395Skan 7018117395Skan /* We need to set the FRAME_RELATED flag on all SETs 7019117395Skan inside the store-multiple pattern. 7020117395Skan 7021117395Skan However, we must not emit DWARF records for registers 2..5 7022132718Skan if they are stored for use by variable arguments ... 7023117395Skan 7024169689Skan ??? Unfortunately, it is not enough to simply not the 7025117395Skan FRAME_RELATED flags for those SETs, because the first SET 7026117395Skan of the PARALLEL is always treated as if it had the flag 7027117395Skan set, even if it does not. Therefore we emit a new pattern 7028117395Skan without those registers as REG_FRAME_RELATED_EXPR note. */ 7029117395Skan 7030117395Skan if (first >= 6) 7031117395Skan { 7032117395Skan rtx pat = PATTERN (insn); 7033117395Skan 7034117395Skan for (i = 0; i < XVECLEN (pat, 0); i++) 7035117395Skan if (GET_CODE (XVECEXP (pat, 0, i)) == SET) 7036117395Skan RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1; 7037117395Skan 7038117395Skan RTX_FRAME_RELATED_P (insn) = 1; 7039117395Skan } 7040117395Skan else if (last >= 6) 7041117395Skan { 7042169689Skan addr = plus_constant (base, offset + (6 - first) * UNITS_PER_WORD); 7043132718Skan note = gen_store_multiple (gen_rtx_MEM (Pmode, addr), 7044117395Skan gen_rtx_REG (Pmode, 6), 7045117395Skan GEN_INT (last - 6 + 1)); 7046117395Skan note = PATTERN (note); 7047117395Skan 7048117395Skan REG_NOTES (insn) = 7049132718Skan gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 7050117395Skan note, REG_NOTES (insn)); 7051117395Skan 7052117395Skan for (i = 0; i < XVECLEN (note, 0); i++) 7053117395Skan if (GET_CODE (XVECEXP (note, 0, i)) == SET) 7054117395Skan RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1; 7055117395Skan 7056117395Skan RTX_FRAME_RELATED_P (insn) = 1; 7057117395Skan } 7058117395Skan 7059117395Skan return insn; 7060107590Sobrien} 7061107590Sobrien 7062117395Skan/* Generate insn to restore registers FIRST to LAST from 7063132718Skan the register save area located at offset OFFSET 7064117395Skan relative to register BASE. */ 7065107590Sobrien 7066117395Skanstatic rtx 7067132718Skanrestore_gprs (rtx base, int offset, int first, int last) 7068107590Sobrien{ 7069117395Skan rtx addr, insn; 7070117395Skan 7071169689Skan addr = plus_constant (base, offset); 7072117395Skan addr = gen_rtx_MEM (Pmode, addr); 7073169689Skan set_mem_alias_set (addr, get_frame_alias_set ()); 7074117395Skan 7075117395Skan /* Special-case single register. */ 7076117395Skan if (first == last) 7077117395Skan { 7078117395Skan if (TARGET_64BIT) 7079117395Skan insn = gen_movdi (gen_rtx_REG (Pmode, first), addr); 7080117395Skan else 7081117395Skan insn = gen_movsi (gen_rtx_REG (Pmode, first), addr); 7082117395Skan 7083117395Skan return insn; 7084117395Skan } 7085117395Skan 7086117395Skan insn = gen_load_multiple (gen_rtx_REG (Pmode, first), 7087117395Skan addr, 7088117395Skan GEN_INT (last - first + 1)); 7089117395Skan return insn; 7090107590Sobrien} 7091107590Sobrien 7092169689Skan/* Return insn sequence to load the GOT register. */ 7093132718Skan 7094132718Skanstatic GTY(()) rtx got_symbol; 7095169689Skanrtx 7096169689Skans390_load_got (void) 7097132718Skan{ 7098169689Skan rtx insns; 7099169689Skan 7100132718Skan if (!got_symbol) 7101132718Skan { 7102132718Skan got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 7103132718Skan SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL; 7104132718Skan } 7105132718Skan 7106169689Skan start_sequence (); 7107169689Skan 7108132718Skan if (TARGET_CPU_ZARCH) 7109132718Skan { 7110169689Skan emit_move_insn (pic_offset_table_rtx, got_symbol); 7111132718Skan } 7112132718Skan else 7113132718Skan { 7114169689Skan rtx offset; 7115132718Skan 7116132718Skan offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol), 7117132718Skan UNSPEC_LTREL_OFFSET); 7118132718Skan offset = gen_rtx_CONST (Pmode, offset); 7119132718Skan offset = force_const_mem (Pmode, offset); 7120132718Skan 7121169689Skan emit_move_insn (pic_offset_table_rtx, offset); 7122132718Skan 7123132718Skan offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)), 7124132718Skan UNSPEC_LTREL_BASE); 7125132718Skan offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset); 7126132718Skan 7127169689Skan emit_move_insn (pic_offset_table_rtx, offset); 7128132718Skan } 7129169689Skan 7130169689Skan insns = get_insns (); 7131169689Skan end_sequence (); 7132169689Skan return insns; 7133132718Skan} 7134132718Skan 7135107590Sobrien/* Expand the prologue into a bunch of separate insns. */ 7136107590Sobrien 7137107590Sobrienvoid 7138132718Skans390_emit_prologue (void) 7139107590Sobrien{ 7140107590Sobrien rtx insn, addr; 7141107590Sobrien rtx temp_reg; 7142107590Sobrien int i; 7143169689Skan int offset; 7144169689Skan int next_fpr = 0; 7145107590Sobrien 7146169689Skan /* Complete frame layout. */ 7147107590Sobrien 7148169689Skan s390_update_frame_layout (); 7149107590Sobrien 7150169689Skan /* Annotate all constant pool references to let the scheduler know 7151169689Skan they implicitly use the base register. */ 7152169689Skan 7153169689Skan push_topmost_sequence (); 7154169689Skan 7155169689Skan for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 7156169689Skan if (INSN_P (insn)) 7157169689Skan annotate_constant_pool_refs (&PATTERN (insn)); 7158169689Skan 7159169689Skan pop_topmost_sequence (); 7160169689Skan 7161132718Skan /* Choose best register to use for temp use within prologue. 7162132718Skan See below for why TPF must use the register 1. */ 7163132718Skan 7164169689Skan if (!has_hard_reg_initial_val (Pmode, RETURN_REGNUM) 7165169689Skan && !current_function_is_leaf 7166169689Skan && !TARGET_TPF_PROFILING) 7167107590Sobrien temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); 7168107590Sobrien else 7169107590Sobrien temp_reg = gen_rtx_REG (Pmode, 1); 7170107590Sobrien 7171107590Sobrien /* Save call saved gprs. */ 7172169689Skan if (cfun_frame_layout.first_save_gpr != -1) 7173169689Skan { 7174169689Skan insn = save_gprs (stack_pointer_rtx, 7175169689Skan cfun_frame_layout.gprs_offset + 7176169689Skan UNITS_PER_WORD * (cfun_frame_layout.first_save_gpr 7177169689Skan - cfun_frame_layout.first_save_gpr_slot), 7178169689Skan cfun_frame_layout.first_save_gpr, 7179169689Skan cfun_frame_layout.last_save_gpr); 7180169689Skan emit_insn (insn); 7181169689Skan } 7182107590Sobrien 7183132718Skan /* Dummy insn to mark literal pool slot. */ 7184107590Sobrien 7185169689Skan if (cfun->machine->base_reg) 7186169689Skan emit_insn (gen_main_pool (cfun->machine->base_reg)); 7187132718Skan 7188169689Skan offset = cfun_frame_layout.f0_offset; 7189107590Sobrien 7190169689Skan /* Save f0 and f2. */ 7191169689Skan for (i = 0; i < 2; i++) 7192169689Skan { 7193169689Skan if (cfun_fpr_bit_p (i)) 7194169689Skan { 7195169689Skan save_fpr (stack_pointer_rtx, offset, i + 16); 7196169689Skan offset += 8; 7197169689Skan } 7198169689Skan else if (!TARGET_PACKED_STACK) 7199169689Skan offset += 8; 7200169689Skan } 7201107590Sobrien 7202169689Skan /* Save f4 and f6. */ 7203169689Skan offset = cfun_frame_layout.f4_offset; 7204169689Skan for (i = 2; i < 4; i++) 7205169689Skan { 7206169689Skan if (cfun_fpr_bit_p (i)) 7207169689Skan { 7208169689Skan insn = save_fpr (stack_pointer_rtx, offset, i + 16); 7209169689Skan offset += 8; 7210107590Sobrien 7211169689Skan /* If f4 and f6 are call clobbered they are saved due to stdargs and 7212169689Skan therefore are not frame related. */ 7213169689Skan if (!call_really_used_regs[i + 16]) 7214169689Skan RTX_FRAME_RELATED_P (insn) = 1; 7215107590Sobrien } 7216169689Skan else if (!TARGET_PACKED_STACK) 7217169689Skan offset += 8; 7218169689Skan } 7219107590Sobrien 7220169689Skan if (TARGET_PACKED_STACK 7221169689Skan && cfun_save_high_fprs_p 7222169689Skan && cfun_frame_layout.f8_offset + cfun_frame_layout.high_fprs * 8 > 0) 7223169689Skan { 7224169689Skan offset = (cfun_frame_layout.f8_offset 7225169689Skan + (cfun_frame_layout.high_fprs - 1) * 8); 7226169689Skan 7227169689Skan for (i = 15; i > 7 && offset >= 0; i--) 7228169689Skan if (cfun_fpr_bit_p (i)) 7229169689Skan { 7230169689Skan insn = save_fpr (stack_pointer_rtx, offset, i + 16); 7231169689Skan 7232169689Skan RTX_FRAME_RELATED_P (insn) = 1; 7233169689Skan offset -= 8; 7234169689Skan } 7235169689Skan if (offset >= cfun_frame_layout.f8_offset) 7236169689Skan next_fpr = i + 16; 7237169689Skan } 7238169689Skan 7239169689Skan if (!TARGET_PACKED_STACK) 7240169689Skan next_fpr = cfun_save_high_fprs_p ? 31 : 0; 7241169689Skan 7242107590Sobrien /* Decrement stack pointer. */ 7243107590Sobrien 7244169689Skan if (cfun_frame_layout.frame_size > 0) 7245107590Sobrien { 7246169689Skan rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size); 7247107590Sobrien 7248169689Skan if (s390_stack_size) 7249169689Skan { 7250169689Skan HOST_WIDE_INT stack_check_mask = ((s390_stack_size - 1) 7251169689Skan & ~(s390_stack_guard - 1)); 7252169689Skan rtx t = gen_rtx_AND (Pmode, stack_pointer_rtx, 7253169689Skan GEN_INT (stack_check_mask)); 7254169689Skan 7255169689Skan if (TARGET_64BIT) 7256169689Skan gen_cmpdi (t, const0_rtx); 7257169689Skan else 7258169689Skan gen_cmpsi (t, const0_rtx); 7259169689Skan 7260169689Skan emit_insn (gen_conditional_trap (gen_rtx_EQ (CCmode, 7261169689Skan gen_rtx_REG (CCmode, 7262169689Skan CC_REGNUM), 7263169689Skan const0_rtx), 7264169689Skan const0_rtx)); 7265169689Skan } 7266169689Skan 7267169689Skan if (s390_warn_framesize > 0 7268169689Skan && cfun_frame_layout.frame_size >= s390_warn_framesize) 7269169689Skan warning (0, "frame size of %qs is " HOST_WIDE_INT_PRINT_DEC " bytes", 7270169689Skan current_function_name (), cfun_frame_layout.frame_size); 7271169689Skan 7272169689Skan if (s390_warn_dynamicstack_p && cfun->calls_alloca) 7273169689Skan warning (0, "%qs uses dynamic stack allocation", current_function_name ()); 7274169689Skan 7275107590Sobrien /* Save incoming stack pointer into temp reg. */ 7276169689Skan if (TARGET_BACKCHAIN || next_fpr) 7277169689Skan insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx)); 7278132718Skan 7279132718Skan /* Subtract frame size from stack pointer. */ 7280107590Sobrien 7281132718Skan if (DISP_IN_RANGE (INTVAL (frame_off))) 7282132718Skan { 7283132718Skan insn = gen_rtx_SET (VOIDmode, stack_pointer_rtx, 7284169689Skan gen_rtx_PLUS (Pmode, stack_pointer_rtx, 7285132718Skan frame_off)); 7286132718Skan insn = emit_insn (insn); 7287132718Skan } 7288132718Skan else 7289132718Skan { 7290169689Skan if (!CONST_OK_FOR_K (INTVAL (frame_off))) 7291132718Skan frame_off = force_const_mem (Pmode, frame_off); 7292132718Skan 7293132718Skan insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off)); 7294169689Skan annotate_constant_pool_refs (&PATTERN (insn)); 7295132718Skan } 7296132718Skan 7297107590Sobrien RTX_FRAME_RELATED_P (insn) = 1; 7298132718Skan REG_NOTES (insn) = 7299107590Sobrien gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 7300107590Sobrien gen_rtx_SET (VOIDmode, stack_pointer_rtx, 7301169689Skan gen_rtx_PLUS (Pmode, stack_pointer_rtx, 7302169689Skan GEN_INT (-cfun_frame_layout.frame_size))), 7303107590Sobrien REG_NOTES (insn)); 7304107590Sobrien 7305107590Sobrien /* Set backchain. */ 7306132718Skan 7307107590Sobrien if (TARGET_BACKCHAIN) 7308107590Sobrien { 7309169689Skan if (cfun_frame_layout.backchain_offset) 7310169689Skan addr = gen_rtx_MEM (Pmode, 7311169689Skan plus_constant (stack_pointer_rtx, 7312169689Skan cfun_frame_layout.backchain_offset)); 7313169689Skan else 7314169689Skan addr = gen_rtx_MEM (Pmode, stack_pointer_rtx); 7315169689Skan set_mem_alias_set (addr, get_frame_alias_set ()); 7316107590Sobrien insn = emit_insn (gen_move_insn (addr, temp_reg)); 7317107590Sobrien } 7318117395Skan 7319117395Skan /* If we support asynchronous exceptions (e.g. for Java), 7320117395Skan we need to make sure the backchain pointer is set up 7321117395Skan before any possibly trapping memory access. */ 7322117395Skan 7323117395Skan if (TARGET_BACKCHAIN && flag_non_call_exceptions) 7324117395Skan { 7325117395Skan addr = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)); 7326117395Skan emit_insn (gen_rtx_CLOBBER (VOIDmode, addr)); 7327117395Skan } 7328107590Sobrien } 7329107590Sobrien 7330107590Sobrien /* Save fprs 8 - 15 (64 bit ABI). */ 7331132718Skan 7332169689Skan if (cfun_save_high_fprs_p && next_fpr) 7333107590Sobrien { 7334169689Skan insn = emit_insn (gen_add2_insn (temp_reg, 7335169689Skan GEN_INT (cfun_frame_layout.f8_offset))); 7336107590Sobrien 7337169689Skan offset = 0; 7338169689Skan 7339169689Skan for (i = 24; i <= next_fpr; i++) 7340169689Skan if (cfun_fpr_bit_p (i - 16)) 7341107590Sobrien { 7342132718Skan rtx addr = plus_constant (stack_pointer_rtx, 7343169689Skan cfun_frame_layout.frame_size 7344169689Skan + cfun_frame_layout.f8_offset 7345169689Skan + offset); 7346169689Skan 7347169689Skan insn = save_fpr (temp_reg, offset, i); 7348169689Skan offset += 8; 7349107590Sobrien RTX_FRAME_RELATED_P (insn) = 1; 7350132718Skan REG_NOTES (insn) = 7351107590Sobrien gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 7352169689Skan gen_rtx_SET (VOIDmode, 7353169689Skan gen_rtx_MEM (DFmode, addr), 7354169689Skan gen_rtx_REG (DFmode, i)), 7355169689Skan REG_NOTES (insn)); 7356107590Sobrien } 7357107590Sobrien } 7358132718Skan 7359107590Sobrien /* Set frame pointer, if needed. */ 7360132718Skan 7361117395Skan if (frame_pointer_needed) 7362107590Sobrien { 7363107590Sobrien insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); 7364107590Sobrien RTX_FRAME_RELATED_P (insn) = 1; 7365107590Sobrien } 7366107590Sobrien 7367107590Sobrien /* Set up got pointer, if needed. */ 7368132718Skan 7369117395Skan if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) 7370169689Skan { 7371169689Skan rtx insns = s390_load_got (); 7372132718Skan 7373169689Skan for (insn = insns; insn; insn = NEXT_INSN (insn)) 7374169689Skan { 7375169689Skan annotate_constant_pool_refs (&PATTERN (insn)); 7376169689Skan 7377169689Skan REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX, 7378169689Skan REG_NOTES (insn)); 7379169689Skan } 7380169689Skan 7381169689Skan emit_insn (insns); 7382169689Skan } 7383169689Skan 7384169689Skan if (TARGET_TPF_PROFILING) 7385107590Sobrien { 7386132718Skan /* Generate a BAS instruction to serve as a function 7387132718Skan entry intercept to facilitate the use of tracing 7388169689Skan algorithms located at the branch target. */ 7389169689Skan emit_insn (gen_prologue_tpf ()); 7390107590Sobrien 7391132718Skan /* Emit a blockage here so that all code 7392132718Skan lies between the profiling mechanisms. */ 7393132718Skan emit_insn (gen_blockage ()); 7394132718Skan } 7395107590Sobrien} 7396107590Sobrien 7397107590Sobrien/* Expand the epilogue into a bunch of separate insns. */ 7398107590Sobrien 7399107590Sobrienvoid 7400169689Skans390_emit_epilogue (bool sibcall) 7401107590Sobrien{ 7402107590Sobrien rtx frame_pointer, return_reg; 7403117395Skan int area_bottom, area_top, offset = 0; 7404169689Skan int next_offset; 7405107590Sobrien rtvec p; 7406132718Skan int i; 7407107590Sobrien 7408169689Skan if (TARGET_TPF_PROFILING) 7409132718Skan { 7410132718Skan 7411132718Skan /* Generate a BAS instruction to serve as a function 7412132718Skan entry intercept to facilitate the use of tracing 7413169689Skan algorithms located at the branch target. */ 7414132718Skan 7415132718Skan /* Emit a blockage here so that all code 7416132718Skan lies between the profiling mechanisms. */ 7417132718Skan emit_insn (gen_blockage ()); 7418132718Skan 7419169689Skan emit_insn (gen_epilogue_tpf ()); 7420132718Skan } 7421132718Skan 7422107590Sobrien /* Check whether to use frame or stack pointer for restore. */ 7423107590Sobrien 7424169689Skan frame_pointer = (frame_pointer_needed 7425169689Skan ? hard_frame_pointer_rtx : stack_pointer_rtx); 7426107590Sobrien 7427169689Skan s390_frame_area (&area_bottom, &area_top); 7428107590Sobrien 7429132718Skan /* Check whether we can access the register save area. 7430107590Sobrien If not, increment the frame pointer as required. */ 7431107590Sobrien 7432107590Sobrien if (area_top <= area_bottom) 7433107590Sobrien { 7434107590Sobrien /* Nothing to restore. */ 7435107590Sobrien } 7436169689Skan else if (DISP_IN_RANGE (cfun_frame_layout.frame_size + area_bottom) 7437169689Skan && DISP_IN_RANGE (cfun_frame_layout.frame_size + area_top - 1)) 7438107590Sobrien { 7439107590Sobrien /* Area is in range. */ 7440169689Skan offset = cfun_frame_layout.frame_size; 7441107590Sobrien } 7442107590Sobrien else 7443107590Sobrien { 7444107590Sobrien rtx insn, frame_off; 7445107590Sobrien 7446132718Skan offset = area_bottom < 0 ? -area_bottom : 0; 7447169689Skan frame_off = GEN_INT (cfun_frame_layout.frame_size - offset); 7448107590Sobrien 7449132718Skan if (DISP_IN_RANGE (INTVAL (frame_off))) 7450132718Skan { 7451132718Skan insn = gen_rtx_SET (VOIDmode, frame_pointer, 7452132718Skan gen_rtx_PLUS (Pmode, frame_pointer, frame_off)); 7453132718Skan insn = emit_insn (insn); 7454132718Skan } 7455132718Skan else 7456132718Skan { 7457169689Skan if (!CONST_OK_FOR_K (INTVAL (frame_off))) 7458132718Skan frame_off = force_const_mem (Pmode, frame_off); 7459107590Sobrien 7460132718Skan insn = emit_insn (gen_add2_insn (frame_pointer, frame_off)); 7461169689Skan annotate_constant_pool_refs (&PATTERN (insn)); 7462132718Skan } 7463107590Sobrien } 7464107590Sobrien 7465107590Sobrien /* Restore call saved fprs. */ 7466107590Sobrien 7467107590Sobrien if (TARGET_64BIT) 7468107590Sobrien { 7469169689Skan if (cfun_save_high_fprs_p) 7470169689Skan { 7471169689Skan next_offset = cfun_frame_layout.f8_offset; 7472169689Skan for (i = 24; i < 32; i++) 7473169689Skan { 7474169689Skan if (cfun_fpr_bit_p (i - 16)) 7475169689Skan { 7476169689Skan restore_fpr (frame_pointer, 7477169689Skan offset + next_offset, i); 7478169689Skan next_offset += 8; 7479169689Skan } 7480169689Skan } 7481169689Skan } 7482169689Skan 7483107590Sobrien } 7484107590Sobrien else 7485107590Sobrien { 7486169689Skan next_offset = cfun_frame_layout.f4_offset; 7487132718Skan for (i = 18; i < 20; i++) 7488169689Skan { 7489169689Skan if (cfun_fpr_bit_p (i - 16)) 7490169689Skan { 7491169689Skan restore_fpr (frame_pointer, 7492169689Skan offset + next_offset, i); 7493169689Skan next_offset += 8; 7494169689Skan } 7495169689Skan else if (!TARGET_PACKED_STACK) 7496169689Skan next_offset += 8; 7497169689Skan } 7498169689Skan 7499107590Sobrien } 7500107590Sobrien 7501107590Sobrien /* Return register. */ 7502107590Sobrien 7503132718Skan return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); 7504107590Sobrien 7505107590Sobrien /* Restore call saved gprs. */ 7506107590Sobrien 7507169689Skan if (cfun_frame_layout.first_restore_gpr != -1) 7508107590Sobrien { 7509117395Skan rtx insn, addr; 7510107590Sobrien int i; 7511107590Sobrien 7512132718Skan /* Check for global register and save them 7513107590Sobrien to stack location from where they get restored. */ 7514107590Sobrien 7515169689Skan for (i = cfun_frame_layout.first_restore_gpr; 7516169689Skan i <= cfun_frame_layout.last_restore_gpr; 7517107590Sobrien i++) 7518107590Sobrien { 7519132718Skan /* These registers are special and need to be 7520107590Sobrien restored in any case. */ 7521132718Skan if (i == STACK_POINTER_REGNUM 7522107590Sobrien || i == RETURN_REGNUM 7523169689Skan || i == BASE_REGNUM 7524117395Skan || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM)) 7525107590Sobrien continue; 7526107590Sobrien 7527107590Sobrien if (global_regs[i]) 7528107590Sobrien { 7529132718Skan addr = plus_constant (frame_pointer, 7530169689Skan offset + cfun_frame_layout.gprs_offset 7531169689Skan + (i - cfun_frame_layout.first_save_gpr_slot) 7532169689Skan * UNITS_PER_WORD); 7533107590Sobrien addr = gen_rtx_MEM (Pmode, addr); 7534169689Skan set_mem_alias_set (addr, get_frame_alias_set ()); 7535107590Sobrien emit_move_insn (addr, gen_rtx_REG (Pmode, i)); 7536132718Skan } 7537107590Sobrien } 7538107590Sobrien 7539169689Skan if (! sibcall) 7540107590Sobrien { 7541169689Skan /* Fetch return address from stack before load multiple, 7542169689Skan this will do good for scheduling. */ 7543132718Skan 7544169689Skan if (cfun_frame_layout.save_return_addr_p 7545169689Skan || (cfun_frame_layout.first_restore_gpr < BASE_REGNUM 7546169689Skan && cfun_frame_layout.last_restore_gpr > RETURN_REGNUM)) 7547169689Skan { 7548169689Skan int return_regnum = find_unused_clobbered_reg(); 7549169689Skan if (!return_regnum) 7550169689Skan return_regnum = 4; 7551169689Skan return_reg = gen_rtx_REG (Pmode, return_regnum); 7552169689Skan 7553169689Skan addr = plus_constant (frame_pointer, 7554169689Skan offset + cfun_frame_layout.gprs_offset 7555169689Skan + (RETURN_REGNUM 7556169689Skan - cfun_frame_layout.first_save_gpr_slot) 7557169689Skan * UNITS_PER_WORD); 7558169689Skan addr = gen_rtx_MEM (Pmode, addr); 7559169689Skan set_mem_alias_set (addr, get_frame_alias_set ()); 7560169689Skan emit_move_insn (return_reg, addr); 7561169689Skan } 7562107590Sobrien } 7563107590Sobrien 7564169689Skan insn = restore_gprs (frame_pointer, 7565169689Skan offset + cfun_frame_layout.gprs_offset 7566169689Skan + (cfun_frame_layout.first_restore_gpr 7567169689Skan - cfun_frame_layout.first_save_gpr_slot) 7568169689Skan * UNITS_PER_WORD, 7569169689Skan cfun_frame_layout.first_restore_gpr, 7570169689Skan cfun_frame_layout.last_restore_gpr); 7571117395Skan emit_insn (insn); 7572107590Sobrien } 7573107590Sobrien 7574169689Skan if (! sibcall) 7575169689Skan { 7576107590Sobrien 7577169689Skan /* Return to caller. */ 7578132718Skan 7579169689Skan p = rtvec_alloc (2); 7580169689Skan 7581169689Skan RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode); 7582169689Skan RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg); 7583169689Skan emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p)); 7584169689Skan } 7585107590Sobrien} 7586107590Sobrien 7587107590Sobrien 7588132718Skan/* Return the size in bytes of a function argument of 7589107590Sobrien type TYPE and/or mode MODE. At least one of TYPE or 7590107590Sobrien MODE must be specified. */ 7591107590Sobrien 7592107590Sobrienstatic int 7593132718Skans390_function_arg_size (enum machine_mode mode, tree type) 7594107590Sobrien{ 7595107590Sobrien if (type) 7596107590Sobrien return int_size_in_bytes (type); 7597107590Sobrien 7598107590Sobrien /* No type info available for some library calls ... */ 7599107590Sobrien if (mode != BLKmode) 7600107590Sobrien return GET_MODE_SIZE (mode); 7601107590Sobrien 7602107590Sobrien /* If we have neither type nor mode, abort */ 7603169689Skan gcc_unreachable (); 7604107590Sobrien} 7605107590Sobrien 7606132718Skan/* Return true if a function argument of type TYPE and mode MODE 7607132718Skan is to be passed in a floating-point register, if available. */ 7608132718Skan 7609132718Skanstatic bool 7610132718Skans390_function_arg_float (enum machine_mode mode, tree type) 7611132718Skan{ 7612132718Skan int size = s390_function_arg_size (mode, type); 7613132718Skan if (size > 8) 7614132718Skan return false; 7615132718Skan 7616132718Skan /* Soft-float changes the ABI: no floating-point registers are used. */ 7617132718Skan if (TARGET_SOFT_FLOAT) 7618132718Skan return false; 7619132718Skan 7620132718Skan /* No type info available for some library calls ... */ 7621132718Skan if (!type) 7622169689Skan return mode == SFmode || mode == DFmode || mode == SDmode || mode == DDmode; 7623132718Skan 7624132718Skan /* The ABI says that record types with a single member are treated 7625132718Skan just like that member would be. */ 7626132718Skan while (TREE_CODE (type) == RECORD_TYPE) 7627132718Skan { 7628132718Skan tree field, single = NULL_TREE; 7629132718Skan 7630132718Skan for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 7631132718Skan { 7632132718Skan if (TREE_CODE (field) != FIELD_DECL) 7633132718Skan continue; 7634132718Skan 7635132718Skan if (single == NULL_TREE) 7636132718Skan single = TREE_TYPE (field); 7637132718Skan else 7638132718Skan return false; 7639132718Skan } 7640132718Skan 7641132718Skan if (single == NULL_TREE) 7642132718Skan return false; 7643132718Skan else 7644132718Skan type = single; 7645132718Skan } 7646132718Skan 7647132718Skan return TREE_CODE (type) == REAL_TYPE; 7648132718Skan} 7649132718Skan 7650132718Skan/* Return true if a function argument of type TYPE and mode MODE 7651132718Skan is to be passed in an integer register, or a pair of integer 7652132718Skan registers, if available. */ 7653132718Skan 7654132718Skanstatic bool 7655132718Skans390_function_arg_integer (enum machine_mode mode, tree type) 7656132718Skan{ 7657132718Skan int size = s390_function_arg_size (mode, type); 7658132718Skan if (size > 8) 7659132718Skan return false; 7660132718Skan 7661132718Skan /* No type info available for some library calls ... */ 7662132718Skan if (!type) 7663132718Skan return GET_MODE_CLASS (mode) == MODE_INT 7664169689Skan || (TARGET_SOFT_FLOAT && SCALAR_FLOAT_MODE_P (mode)); 7665132718Skan 7666132718Skan /* We accept small integral (and similar) types. */ 7667132718Skan if (INTEGRAL_TYPE_P (type) 7668169689Skan || POINTER_TYPE_P (type) 7669132718Skan || TREE_CODE (type) == OFFSET_TYPE 7670132718Skan || (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE)) 7671132718Skan return true; 7672132718Skan 7673132718Skan /* We also accept structs of size 1, 2, 4, 8 that are not 7674169689Skan passed in floating-point registers. */ 7675132718Skan if (AGGREGATE_TYPE_P (type) 7676132718Skan && exact_log2 (size) >= 0 7677132718Skan && !s390_function_arg_float (mode, type)) 7678132718Skan return true; 7679132718Skan 7680132718Skan return false; 7681132718Skan} 7682132718Skan 7683107590Sobrien/* Return 1 if a function argument of type TYPE and mode MODE 7684107590Sobrien is to be passed by reference. The ABI specifies that only 7685107590Sobrien structures of size 1, 2, 4, or 8 bytes are passed by value, 7686107590Sobrien all other structures (and complex numbers) are passed by 7687107590Sobrien reference. */ 7688107590Sobrien 7689169689Skanstatic bool 7690169689Skans390_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED, 7691169689Skan enum machine_mode mode, tree type, 7692169689Skan bool named ATTRIBUTE_UNUSED) 7693107590Sobrien{ 7694107590Sobrien int size = s390_function_arg_size (mode, type); 7695132718Skan if (size > 8) 7696132718Skan return true; 7697107590Sobrien 7698107590Sobrien if (type) 7699107590Sobrien { 7700132718Skan if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0) 7701107590Sobrien return 1; 7702107590Sobrien 7703132718Skan if (TREE_CODE (type) == COMPLEX_TYPE 7704132718Skan || TREE_CODE (type) == VECTOR_TYPE) 7705107590Sobrien return 1; 7706107590Sobrien } 7707132718Skan 7708107590Sobrien return 0; 7709107590Sobrien} 7710107590Sobrien 7711107590Sobrien/* Update the data in CUM to advance over an argument of mode MODE and 7712107590Sobrien data type TYPE. (TYPE is null for libcalls where that information 7713107590Sobrien may not be available.). The boolean NAMED specifies whether the 7714107590Sobrien argument is a named argument (as opposed to an unnamed argument 7715107590Sobrien matching an ellipsis). */ 7716107590Sobrien 7717107590Sobrienvoid 7718132718Skans390_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, 7719132718Skan tree type, int named ATTRIBUTE_UNUSED) 7720107590Sobrien{ 7721169689Skan if (s390_function_arg_float (mode, type)) 7722107590Sobrien { 7723132718Skan cum->fprs += 1; 7724107590Sobrien } 7725132718Skan else if (s390_function_arg_integer (mode, type)) 7726107590Sobrien { 7727107590Sobrien int size = s390_function_arg_size (mode, type); 7728107590Sobrien cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD); 7729107590Sobrien } 7730132718Skan else 7731169689Skan gcc_unreachable (); 7732107590Sobrien} 7733107590Sobrien 7734107590Sobrien/* Define where to put the arguments to a function. 7735107590Sobrien Value is zero to push the argument on the stack, 7736107590Sobrien or a hard register in which to store the argument. 7737107590Sobrien 7738107590Sobrien MODE is the argument's machine mode. 7739107590Sobrien TYPE is the data type of the argument (as a tree). 7740107590Sobrien This is null for libcalls where that information may 7741107590Sobrien not be available. 7742107590Sobrien CUM is a variable of type CUMULATIVE_ARGS which gives info about 7743107590Sobrien the preceding args and about the function being called. 7744107590Sobrien NAMED is nonzero if this argument is a named parameter 7745132718Skan (otherwise it is an extra parameter matching an ellipsis). 7746107590Sobrien 7747107590Sobrien On S/390, we use general purpose registers 2 through 6 to 7748107590Sobrien pass integer, pointer, and certain structure arguments, and 7749107590Sobrien floating point registers 0 and 2 (0, 2, 4, and 6 on 64-bit) 7750107590Sobrien to pass floating point arguments. All remaining arguments 7751107590Sobrien are pushed to the stack. */ 7752107590Sobrien 7753107590Sobrienrtx 7754132718Skans390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, 7755132718Skan int named ATTRIBUTE_UNUSED) 7756107590Sobrien{ 7757132718Skan if (s390_function_arg_float (mode, type)) 7758107590Sobrien { 7759169689Skan if (cum->fprs + 1 > FP_ARG_NUM_REG) 7760107590Sobrien return 0; 7761107590Sobrien else 7762169689Skan return gen_rtx_REG (mode, cum->fprs + 16); 7763107590Sobrien } 7764132718Skan else if (s390_function_arg_integer (mode, type)) 7765107590Sobrien { 7766107590Sobrien int size = s390_function_arg_size (mode, type); 7767107590Sobrien int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD; 7768107590Sobrien 7769169689Skan if (cum->gprs + n_gprs > GP_ARG_NUM_REG) 7770107590Sobrien return 0; 7771107590Sobrien else 7772169689Skan return gen_rtx_REG (mode, cum->gprs + 2); 7773107590Sobrien } 7774132718Skan 7775132718Skan /* After the real arguments, expand_call calls us once again 7776132718Skan with a void_type_node type. Whatever we return here is 7777132718Skan passed as operand 2 to the call expanders. 7778132718Skan 7779132718Skan We don't need this feature ... */ 7780132718Skan else if (type == void_type_node) 7781132718Skan return const0_rtx; 7782132718Skan 7783169689Skan gcc_unreachable (); 7784107590Sobrien} 7785107590Sobrien 7786132718Skan/* Return true if return values of type TYPE should be returned 7787132718Skan in a memory buffer whose address is passed by the caller as 7788132718Skan hidden first argument. */ 7789107590Sobrien 7790132718Skanstatic bool 7791132718Skans390_return_in_memory (tree type, tree fundecl ATTRIBUTE_UNUSED) 7792132718Skan{ 7793132718Skan /* We accept small integral (and similar) types. */ 7794132718Skan if (INTEGRAL_TYPE_P (type) 7795169689Skan || POINTER_TYPE_P (type) 7796132718Skan || TREE_CODE (type) == OFFSET_TYPE 7797132718Skan || TREE_CODE (type) == REAL_TYPE) 7798132718Skan return int_size_in_bytes (type) > 8; 7799132718Skan 7800132718Skan /* Aggregates and similar constructs are always returned 7801132718Skan in memory. */ 7802132718Skan if (AGGREGATE_TYPE_P (type) 7803132718Skan || TREE_CODE (type) == COMPLEX_TYPE 7804132718Skan || TREE_CODE (type) == VECTOR_TYPE) 7805132718Skan return true; 7806132718Skan 7807132718Skan /* ??? We get called on all sorts of random stuff from 7808132718Skan aggregate_value_p. We can't abort, but it's not clear 7809132718Skan what's safe to return. Pretend it's a struct I guess. */ 7810132718Skan return true; 7811132718Skan} 7812132718Skan 7813132718Skan/* Define where to return a (scalar) value of type TYPE. 7814132718Skan If TYPE is null, define where to return a (scalar) 7815132718Skan value of mode MODE from a libcall. */ 7816132718Skan 7817132718Skanrtx 7818132718Skans390_function_value (tree type, enum machine_mode mode) 7819132718Skan{ 7820132718Skan if (type) 7821132718Skan { 7822169689Skan int unsignedp = TYPE_UNSIGNED (type); 7823132718Skan mode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1); 7824132718Skan } 7825132718Skan 7826169689Skan gcc_assert (GET_MODE_CLASS (mode) == MODE_INT || SCALAR_FLOAT_MODE_P (mode)); 7827169689Skan gcc_assert (GET_MODE_SIZE (mode) <= 8); 7828132718Skan 7829169689Skan if (TARGET_HARD_FLOAT && SCALAR_FLOAT_MODE_P (mode)) 7830132718Skan return gen_rtx_REG (mode, 16); 7831132718Skan else 7832132718Skan return gen_rtx_REG (mode, 2); 7833132718Skan} 7834132718Skan 7835132718Skan 7836107590Sobrien/* Create and return the va_list datatype. 7837107590Sobrien 7838107590Sobrien On S/390, va_list is an array type equivalent to 7839107590Sobrien 7840107590Sobrien typedef struct __va_list_tag 7841107590Sobrien { 7842107590Sobrien long __gpr; 7843107590Sobrien long __fpr; 7844107590Sobrien void *__overflow_arg_area; 7845107590Sobrien void *__reg_save_area; 7846107590Sobrien } va_list[1]; 7847107590Sobrien 7848107590Sobrien where __gpr and __fpr hold the number of general purpose 7849107590Sobrien or floating point arguments used up to now, respectively, 7850132718Skan __overflow_arg_area points to the stack location of the 7851107590Sobrien next argument passed on the stack, and __reg_save_area 7852107590Sobrien always points to the start of the register area in the 7853107590Sobrien call frame of the current function. The function prologue 7854107590Sobrien saves all registers used for argument passing into this 7855107590Sobrien area if the function uses variable arguments. */ 7856107590Sobrien 7857132718Skanstatic tree 7858132718Skans390_build_builtin_va_list (void) 7859107590Sobrien{ 7860107590Sobrien tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl; 7861107590Sobrien 7862132718Skan record = lang_hooks.types.make_type (RECORD_TYPE); 7863107590Sobrien 7864107590Sobrien type_decl = 7865107590Sobrien build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); 7866107590Sobrien 7867132718Skan f_gpr = build_decl (FIELD_DECL, get_identifier ("__gpr"), 7868107590Sobrien long_integer_type_node); 7869132718Skan f_fpr = build_decl (FIELD_DECL, get_identifier ("__fpr"), 7870107590Sobrien long_integer_type_node); 7871107590Sobrien f_ovf = build_decl (FIELD_DECL, get_identifier ("__overflow_arg_area"), 7872107590Sobrien ptr_type_node); 7873107590Sobrien f_sav = build_decl (FIELD_DECL, get_identifier ("__reg_save_area"), 7874107590Sobrien ptr_type_node); 7875107590Sobrien 7876169689Skan va_list_gpr_counter_field = f_gpr; 7877169689Skan va_list_fpr_counter_field = f_fpr; 7878169689Skan 7879107590Sobrien DECL_FIELD_CONTEXT (f_gpr) = record; 7880107590Sobrien DECL_FIELD_CONTEXT (f_fpr) = record; 7881107590Sobrien DECL_FIELD_CONTEXT (f_ovf) = record; 7882107590Sobrien DECL_FIELD_CONTEXT (f_sav) = record; 7883107590Sobrien 7884107590Sobrien TREE_CHAIN (record) = type_decl; 7885107590Sobrien TYPE_NAME (record) = type_decl; 7886107590Sobrien TYPE_FIELDS (record) = f_gpr; 7887107590Sobrien TREE_CHAIN (f_gpr) = f_fpr; 7888107590Sobrien TREE_CHAIN (f_fpr) = f_ovf; 7889107590Sobrien TREE_CHAIN (f_ovf) = f_sav; 7890107590Sobrien 7891107590Sobrien layout_type (record); 7892107590Sobrien 7893107590Sobrien /* The correct type is an array type of one element. */ 7894107590Sobrien return build_array_type (record, build_index_type (size_zero_node)); 7895107590Sobrien} 7896107590Sobrien 7897107590Sobrien/* Implement va_start by filling the va_list structure VALIST. 7898117395Skan STDARG_P is always true, and ignored. 7899117395Skan NEXTARG points to the first anonymous stack argument. 7900107590Sobrien 7901107590Sobrien The following global variables are used to initialize 7902107590Sobrien the va_list structure: 7903107590Sobrien 7904107590Sobrien current_function_args_info: 7905107590Sobrien holds number of gprs and fprs used for named arguments. 7906107590Sobrien current_function_arg_offset_rtx: 7907107590Sobrien holds the offset of the first anonymous stack argument 7908107590Sobrien (relative to the virtual arg pointer). */ 7909107590Sobrien 7910107590Sobrienvoid 7911132718Skans390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) 7912107590Sobrien{ 7913107590Sobrien HOST_WIDE_INT n_gpr, n_fpr; 7914107590Sobrien int off; 7915107590Sobrien tree f_gpr, f_fpr, f_ovf, f_sav; 7916107590Sobrien tree gpr, fpr, ovf, sav, t; 7917107590Sobrien 7918107590Sobrien f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); 7919107590Sobrien f_fpr = TREE_CHAIN (f_gpr); 7920107590Sobrien f_ovf = TREE_CHAIN (f_fpr); 7921107590Sobrien f_sav = TREE_CHAIN (f_ovf); 7922107590Sobrien 7923169689Skan valist = build_va_arg_indirect_ref (valist); 7924169689Skan gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); 7925169689Skan fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); 7926169689Skan ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); 7927169689Skan sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); 7928107590Sobrien 7929107590Sobrien /* Count number of gp and fp argument registers used. */ 7930107590Sobrien 7931107590Sobrien n_gpr = current_function_args_info.gprs; 7932107590Sobrien n_fpr = current_function_args_info.fprs; 7933107590Sobrien 7934169689Skan if (cfun->va_list_gpr_size) 7935169689Skan { 7936169689Skan t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, 7937169689Skan build_int_cst (NULL_TREE, n_gpr)); 7938169689Skan TREE_SIDE_EFFECTS (t) = 1; 7939169689Skan expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 7940169689Skan } 7941107590Sobrien 7942169689Skan if (cfun->va_list_fpr_size) 7943169689Skan { 7944169689Skan t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, 7945169689Skan build_int_cst (NULL_TREE, n_fpr)); 7946169689Skan TREE_SIDE_EFFECTS (t) = 1; 7947169689Skan expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 7948169689Skan } 7949107590Sobrien 7950107590Sobrien /* Find the overflow area. */ 7951169689Skan if (n_gpr + cfun->va_list_gpr_size > GP_ARG_NUM_REG 7952169689Skan || n_fpr + cfun->va_list_fpr_size > FP_ARG_NUM_REG) 7953169689Skan { 7954169689Skan t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx); 7955107590Sobrien 7956169689Skan off = INTVAL (current_function_arg_offset_rtx); 7957169689Skan off = off < 0 ? 0 : off; 7958169689Skan if (TARGET_DEBUG_ARG) 7959169689Skan fprintf (stderr, "va_start: n_gpr = %d, n_fpr = %d off %d\n", 7960169689Skan (int)n_gpr, (int)n_fpr, off); 7961107590Sobrien 7962169689Skan t = build2 (PLUS_EXPR, TREE_TYPE (ovf), t, build_int_cst (NULL_TREE, off)); 7963107590Sobrien 7964169689Skan t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); 7965169689Skan TREE_SIDE_EFFECTS (t) = 1; 7966169689Skan expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 7967169689Skan } 7968107590Sobrien 7969107590Sobrien /* Find the register save area. */ 7970169689Skan if ((cfun->va_list_gpr_size && n_gpr < GP_ARG_NUM_REG) 7971169689Skan || (cfun->va_list_fpr_size && n_fpr < FP_ARG_NUM_REG)) 7972169689Skan { 7973169689Skan t = make_tree (TREE_TYPE (sav), return_address_pointer_rtx); 7974169689Skan t = build2 (PLUS_EXPR, TREE_TYPE (sav), t, 7975169689Skan build_int_cst (NULL_TREE, -RETURN_REGNUM * UNITS_PER_WORD)); 7976169689Skan 7977169689Skan t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t); 7978169689Skan TREE_SIDE_EFFECTS (t) = 1; 7979169689Skan expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 7980169689Skan } 7981107590Sobrien} 7982107590Sobrien 7983132718Skan/* Implement va_arg by updating the va_list structure 7984107590Sobrien VALIST as required to retrieve an argument of type 7985132718Skan TYPE, and returning that argument. 7986132718Skan 7987107590Sobrien Generates code equivalent to: 7988132718Skan 7989107590Sobrien if (integral value) { 7990107590Sobrien if (size <= 4 && args.gpr < 5 || 7991132718Skan size > 4 && args.gpr < 4 ) 7992107590Sobrien ret = args.reg_save_area[args.gpr+8] 7993107590Sobrien else 7994107590Sobrien ret = *args.overflow_arg_area++; 7995107590Sobrien } else if (float value) { 7996107590Sobrien if (args.fgpr < 2) 7997107590Sobrien ret = args.reg_save_area[args.fpr+64] 7998107590Sobrien else 7999107590Sobrien ret = *args.overflow_arg_area++; 8000107590Sobrien } else if (aggregate value) { 8001107590Sobrien if (args.gpr < 5) 8002107590Sobrien ret = *args.reg_save_area[args.gpr] 8003107590Sobrien else 8004107590Sobrien ret = **args.overflow_arg_area++; 8005107590Sobrien } */ 8006107590Sobrien 8007169689Skanstatic tree 8008169689Skans390_gimplify_va_arg (tree valist, tree type, tree *pre_p, 8009169689Skan tree *post_p ATTRIBUTE_UNUSED) 8010107590Sobrien{ 8011107590Sobrien tree f_gpr, f_fpr, f_ovf, f_sav; 8012107590Sobrien tree gpr, fpr, ovf, sav, reg, t, u; 8013107590Sobrien int indirect_p, size, n_reg, sav_ofs, sav_scale, max_reg; 8014169689Skan tree lab_false, lab_over, addr; 8015107590Sobrien 8016107590Sobrien f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); 8017107590Sobrien f_fpr = TREE_CHAIN (f_gpr); 8018107590Sobrien f_ovf = TREE_CHAIN (f_fpr); 8019107590Sobrien f_sav = TREE_CHAIN (f_ovf); 8020107590Sobrien 8021169689Skan valist = build_va_arg_indirect_ref (valist); 8022169689Skan gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); 8023169689Skan fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); 8024169689Skan ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); 8025169689Skan sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); 8026107590Sobrien 8027107590Sobrien size = int_size_in_bytes (type); 8028107590Sobrien 8029169689Skan if (pass_by_reference (NULL, TYPE_MODE (type), type, false)) 8030107590Sobrien { 8031107590Sobrien if (TARGET_DEBUG_ARG) 8032107590Sobrien { 8033107590Sobrien fprintf (stderr, "va_arg: aggregate type"); 8034107590Sobrien debug_tree (type); 8035107590Sobrien } 8036107590Sobrien 8037107590Sobrien /* Aggregates are passed by reference. */ 8038107590Sobrien indirect_p = 1; 8039107590Sobrien reg = gpr; 8040107590Sobrien n_reg = 1; 8041169689Skan 8042169689Skan /* kernel stack layout on 31 bit: It is assumed here that no padding 8043169689Skan will be added by s390_frame_info because for va_args always an even 8044169689Skan number of gprs has to be saved r15-r2 = 14 regs. */ 8045107590Sobrien sav_ofs = 2 * UNITS_PER_WORD; 8046107590Sobrien sav_scale = UNITS_PER_WORD; 8047107590Sobrien size = UNITS_PER_WORD; 8048169689Skan max_reg = GP_ARG_NUM_REG - n_reg; 8049107590Sobrien } 8050132718Skan else if (s390_function_arg_float (TYPE_MODE (type), type)) 8051107590Sobrien { 8052107590Sobrien if (TARGET_DEBUG_ARG) 8053107590Sobrien { 8054107590Sobrien fprintf (stderr, "va_arg: float type"); 8055107590Sobrien debug_tree (type); 8056107590Sobrien } 8057107590Sobrien 8058107590Sobrien /* FP args go in FP registers, if present. */ 8059107590Sobrien indirect_p = 0; 8060107590Sobrien reg = fpr; 8061107590Sobrien n_reg = 1; 8062107590Sobrien sav_ofs = 16 * UNITS_PER_WORD; 8063107590Sobrien sav_scale = 8; 8064169689Skan max_reg = FP_ARG_NUM_REG - n_reg; 8065107590Sobrien } 8066107590Sobrien else 8067107590Sobrien { 8068107590Sobrien if (TARGET_DEBUG_ARG) 8069107590Sobrien { 8070107590Sobrien fprintf (stderr, "va_arg: other type"); 8071107590Sobrien debug_tree (type); 8072107590Sobrien } 8073107590Sobrien 8074107590Sobrien /* Otherwise into GP registers. */ 8075107590Sobrien indirect_p = 0; 8076107590Sobrien reg = gpr; 8077107590Sobrien n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 8078169689Skan 8079169689Skan /* kernel stack layout on 31 bit: It is assumed here that no padding 8080169689Skan will be added by s390_frame_info because for va_args always an even 8081169689Skan number of gprs has to be saved r15-r2 = 14 regs. */ 8082107590Sobrien sav_ofs = 2 * UNITS_PER_WORD; 8083107590Sobrien 8084132718Skan if (size < UNITS_PER_WORD) 8085132718Skan sav_ofs += UNITS_PER_WORD - size; 8086132718Skan 8087107590Sobrien sav_scale = UNITS_PER_WORD; 8088169689Skan max_reg = GP_ARG_NUM_REG - n_reg; 8089107590Sobrien } 8090107590Sobrien 8091107590Sobrien /* Pull the value out of the saved registers ... */ 8092107590Sobrien 8093169689Skan lab_false = create_artificial_label (); 8094169689Skan lab_over = create_artificial_label (); 8095169689Skan addr = create_tmp_var (ptr_type_node, "addr"); 8096169689Skan DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set (); 8097107590Sobrien 8098169689Skan t = fold_convert (TREE_TYPE (reg), size_int (max_reg)); 8099169689Skan t = build2 (GT_EXPR, boolean_type_node, reg, t); 8100169689Skan u = build1 (GOTO_EXPR, void_type_node, lab_false); 8101169689Skan t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE); 8102169689Skan gimplify_and_add (t, pre_p); 8103107590Sobrien 8104169689Skan t = build2 (PLUS_EXPR, ptr_type_node, sav, 8105169689Skan fold_convert (ptr_type_node, size_int (sav_ofs))); 8106169689Skan u = build2 (MULT_EXPR, TREE_TYPE (reg), reg, 8107169689Skan fold_convert (TREE_TYPE (reg), size_int (sav_scale))); 8108169689Skan t = build2 (PLUS_EXPR, ptr_type_node, t, fold_convert (ptr_type_node, u)); 8109107590Sobrien 8110169689Skan t = build2 (MODIFY_EXPR, void_type_node, addr, t); 8111169689Skan gimplify_and_add (t, pre_p); 8112107590Sobrien 8113169689Skan t = build1 (GOTO_EXPR, void_type_node, lab_over); 8114169689Skan gimplify_and_add (t, pre_p); 8115107590Sobrien 8116169689Skan t = build1 (LABEL_EXPR, void_type_node, lab_false); 8117169689Skan append_to_statement_list (t, pre_p); 8118107590Sobrien 8119107590Sobrien 8120107590Sobrien /* ... Otherwise out of the overflow area. */ 8121107590Sobrien 8122169689Skan t = ovf; 8123169689Skan if (size < UNITS_PER_WORD) 8124169689Skan t = build2 (PLUS_EXPR, ptr_type_node, t, 8125169689Skan fold_convert (ptr_type_node, size_int (UNITS_PER_WORD - size))); 8126107590Sobrien 8127169689Skan gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue); 8128107590Sobrien 8129169689Skan u = build2 (MODIFY_EXPR, void_type_node, addr, t); 8130169689Skan gimplify_and_add (u, pre_p); 8131107590Sobrien 8132169689Skan t = build2 (PLUS_EXPR, ptr_type_node, t, 8133169689Skan fold_convert (ptr_type_node, size_int (size))); 8134169689Skan t = build2 (MODIFY_EXPR, ptr_type_node, ovf, t); 8135169689Skan gimplify_and_add (t, pre_p); 8136107590Sobrien 8137169689Skan t = build1 (LABEL_EXPR, void_type_node, lab_over); 8138169689Skan append_to_statement_list (t, pre_p); 8139107590Sobrien 8140107590Sobrien 8141169689Skan /* Increment register save count. */ 8142107590Sobrien 8143169689Skan u = build2 (PREINCREMENT_EXPR, TREE_TYPE (reg), reg, 8144169689Skan fold_convert (TREE_TYPE (reg), size_int (n_reg))); 8145169689Skan gimplify_and_add (u, pre_p); 8146107590Sobrien 8147107590Sobrien if (indirect_p) 8148107590Sobrien { 8149169689Skan t = build_pointer_type (build_pointer_type (type)); 8150169689Skan addr = fold_convert (t, addr); 8151169689Skan addr = build_va_arg_indirect_ref (addr); 8152107590Sobrien } 8153169689Skan else 8154169689Skan { 8155169689Skan t = build_pointer_type (type); 8156169689Skan addr = fold_convert (t, addr); 8157169689Skan } 8158107590Sobrien 8159169689Skan return build_va_arg_indirect_ref (addr); 8160107590Sobrien} 8161107590Sobrien 8162107590Sobrien 8163117395Skan/* Builtins. */ 8164117395Skan 8165117395Skanenum s390_builtin 8166117395Skan{ 8167117395Skan S390_BUILTIN_THREAD_POINTER, 8168117395Skan S390_BUILTIN_SET_THREAD_POINTER, 8169117395Skan 8170117395Skan S390_BUILTIN_max 8171117395Skan}; 8172117395Skan 8173117395Skanstatic unsigned int const code_for_builtin_64[S390_BUILTIN_max] = { 8174117395Skan CODE_FOR_get_tp_64, 8175117395Skan CODE_FOR_set_tp_64 8176117395Skan}; 8177117395Skan 8178117395Skanstatic unsigned int const code_for_builtin_31[S390_BUILTIN_max] = { 8179117395Skan CODE_FOR_get_tp_31, 8180117395Skan CODE_FOR_set_tp_31 8181117395Skan}; 8182117395Skan 8183117395Skanstatic void 8184132718Skans390_init_builtins (void) 8185117395Skan{ 8186117395Skan tree ftype; 8187117395Skan 8188117395Skan ftype = build_function_type (ptr_type_node, void_list_node); 8189169689Skan lang_hooks.builtin_function ("__builtin_thread_pointer", ftype, 8190169689Skan S390_BUILTIN_THREAD_POINTER, BUILT_IN_MD, 8191169689Skan NULL, NULL_TREE); 8192117395Skan 8193117395Skan ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); 8194169689Skan lang_hooks.builtin_function ("__builtin_set_thread_pointer", ftype, 8195169689Skan S390_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD, 8196169689Skan NULL, NULL_TREE); 8197117395Skan} 8198117395Skan 8199117395Skan/* Expand an expression EXP that calls a built-in function, 8200117395Skan with result going to TARGET if that's convenient 8201117395Skan (and in mode MODE if that's convenient). 8202117395Skan SUBTARGET may be used as the target for computing one of EXP's operands. 8203117395Skan IGNORE is nonzero if the value is to be ignored. */ 8204117395Skan 8205117395Skanstatic rtx 8206132718Skans390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, 8207132718Skan enum machine_mode mode ATTRIBUTE_UNUSED, 8208132718Skan int ignore ATTRIBUTE_UNUSED) 8209117395Skan{ 8210117395Skan#define MAX_ARGS 2 8211117395Skan 8212132718Skan unsigned int const *code_for_builtin = 8213117395Skan TARGET_64BIT ? code_for_builtin_64 : code_for_builtin_31; 8214117395Skan 8215117395Skan tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); 8216117395Skan unsigned int fcode = DECL_FUNCTION_CODE (fndecl); 8217117395Skan tree arglist = TREE_OPERAND (exp, 1); 8218117395Skan enum insn_code icode; 8219117395Skan rtx op[MAX_ARGS], pat; 8220117395Skan int arity; 8221117395Skan bool nonvoid; 8222117395Skan 8223117395Skan if (fcode >= S390_BUILTIN_max) 8224117395Skan internal_error ("bad builtin fcode"); 8225117395Skan icode = code_for_builtin[fcode]; 8226117395Skan if (icode == 0) 8227117395Skan internal_error ("bad builtin fcode"); 8228117395Skan 8229117395Skan nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; 8230117395Skan 8231117395Skan for (arglist = TREE_OPERAND (exp, 1), arity = 0; 8232117395Skan arglist; 8233117395Skan arglist = TREE_CHAIN (arglist), arity++) 8234117395Skan { 8235117395Skan const struct insn_operand_data *insn_op; 8236117395Skan 8237117395Skan tree arg = TREE_VALUE (arglist); 8238117395Skan if (arg == error_mark_node) 8239117395Skan return NULL_RTX; 8240117395Skan if (arity > MAX_ARGS) 8241117395Skan return NULL_RTX; 8242117395Skan 8243117395Skan insn_op = &insn_data[icode].operand[arity + nonvoid]; 8244117395Skan 8245117395Skan op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, 0); 8246117395Skan 8247117395Skan if (!(*insn_op->predicate) (op[arity], insn_op->mode)) 8248117395Skan op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]); 8249117395Skan } 8250117395Skan 8251117395Skan if (nonvoid) 8252117395Skan { 8253117395Skan enum machine_mode tmode = insn_data[icode].operand[0].mode; 8254117395Skan if (!target 8255117395Skan || GET_MODE (target) != tmode 8256117395Skan || !(*insn_data[icode].operand[0].predicate) (target, tmode)) 8257117395Skan target = gen_reg_rtx (tmode); 8258117395Skan } 8259117395Skan 8260117395Skan switch (arity) 8261117395Skan { 8262117395Skan case 0: 8263117395Skan pat = GEN_FCN (icode) (target); 8264117395Skan break; 8265117395Skan case 1: 8266117395Skan if (nonvoid) 8267117395Skan pat = GEN_FCN (icode) (target, op[0]); 8268117395Skan else 8269117395Skan pat = GEN_FCN (icode) (op[0]); 8270117395Skan break; 8271117395Skan case 2: 8272117395Skan pat = GEN_FCN (icode) (target, op[0], op[1]); 8273117395Skan break; 8274117395Skan default: 8275169689Skan gcc_unreachable (); 8276117395Skan } 8277117395Skan if (!pat) 8278117395Skan return NULL_RTX; 8279117395Skan emit_insn (pat); 8280117395Skan 8281117395Skan if (nonvoid) 8282117395Skan return target; 8283117395Skan else 8284117395Skan return const0_rtx; 8285117395Skan} 8286117395Skan 8287117395Skan 8288107590Sobrien/* Output assembly code for the trampoline template to 8289107590Sobrien stdio stream FILE. 8290107590Sobrien 8291107590Sobrien On S/390, we use gpr 1 internally in the trampoline code; 8292107590Sobrien gpr 0 is used to hold the static chain. */ 8293107590Sobrien 8294107590Sobrienvoid 8295132718Skans390_trampoline_template (FILE *file) 8296107590Sobrien{ 8297169689Skan rtx op[2]; 8298169689Skan op[0] = gen_rtx_REG (Pmode, 0); 8299169689Skan op[1] = gen_rtx_REG (Pmode, 1); 8300169689Skan 8301107590Sobrien if (TARGET_64BIT) 8302107590Sobrien { 8303169689Skan output_asm_insn ("basr\t%1,0", op); 8304169689Skan output_asm_insn ("lmg\t%0,%1,14(%1)", op); 8305169689Skan output_asm_insn ("br\t%1", op); 8306169689Skan ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 10)); 8307107590Sobrien } 8308107590Sobrien else 8309107590Sobrien { 8310169689Skan output_asm_insn ("basr\t%1,0", op); 8311169689Skan output_asm_insn ("lm\t%0,%1,6(%1)", op); 8312169689Skan output_asm_insn ("br\t%1", op); 8313169689Skan ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 8)); 8314107590Sobrien } 8315107590Sobrien} 8316107590Sobrien 8317107590Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline. 8318107590Sobrien FNADDR is an RTX for the address of the function's pure code. 8319107590Sobrien CXT is an RTX for the static chain value for the function. */ 8320107590Sobrien 8321107590Sobrienvoid 8322132718Skans390_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt) 8323107590Sobrien{ 8324169689Skan emit_move_insn (gen_rtx_MEM (Pmode, 8325132718Skan memory_address (Pmode, 8326169689Skan plus_constant (addr, (TARGET_64BIT ? 16 : 8)))), cxt); 8327169689Skan emit_move_insn (gen_rtx_MEM (Pmode, 8328132718Skan memory_address (Pmode, 8329169689Skan plus_constant (addr, (TARGET_64BIT ? 24 : 12)))), fnaddr); 8330107590Sobrien} 8331107590Sobrien 8332107590Sobrien/* Return rtx for 64-bit constant formed from the 32-bit subwords 8333107590Sobrien LOW and HIGH, independent of the host word size. */ 8334107590Sobrien 8335107590Sobrienrtx 8336132718Skans390_gen_rtx_const_DI (int high, int low) 8337107590Sobrien{ 8338107590Sobrien#if HOST_BITS_PER_WIDE_INT >= 64 8339107590Sobrien HOST_WIDE_INT val; 8340107590Sobrien val = (HOST_WIDE_INT)high; 8341107590Sobrien val <<= 32; 8342107590Sobrien val |= (HOST_WIDE_INT)low; 8343132718Skan 8344107590Sobrien return GEN_INT (val); 8345107590Sobrien#else 8346107590Sobrien#if HOST_BITS_PER_WIDE_INT >= 32 8347107590Sobrien return immed_double_const ((HOST_WIDE_INT)low, (HOST_WIDE_INT)high, DImode); 8348107590Sobrien#else 8349169689Skan gcc_unreachable (); 8350107590Sobrien#endif 8351107590Sobrien#endif 8352132718Skan} 8353107590Sobrien 8354107590Sobrien/* Output assembler code to FILE to increment profiler label # LABELNO 8355107590Sobrien for profiling a function entry. */ 8356107590Sobrien 8357107590Sobrienvoid 8358132718Skans390_function_profiler (FILE *file, int labelno) 8359107590Sobrien{ 8360107590Sobrien rtx op[7]; 8361107590Sobrien 8362107590Sobrien char label[128]; 8363117395Skan ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno); 8364107590Sobrien 8365107590Sobrien fprintf (file, "# function profiler \n"); 8366107590Sobrien 8367107590Sobrien op[0] = gen_rtx_REG (Pmode, RETURN_REGNUM); 8368107590Sobrien op[1] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); 8369107590Sobrien op[1] = gen_rtx_MEM (Pmode, plus_constant (op[1], UNITS_PER_WORD)); 8370107590Sobrien 8371107590Sobrien op[2] = gen_rtx_REG (Pmode, 1); 8372107590Sobrien op[3] = gen_rtx_SYMBOL_REF (Pmode, label); 8373132718Skan SYMBOL_REF_FLAGS (op[3]) = SYMBOL_FLAG_LOCAL; 8374107590Sobrien 8375107590Sobrien op[4] = gen_rtx_SYMBOL_REF (Pmode, "_mcount"); 8376107590Sobrien if (flag_pic) 8377107590Sobrien { 8378132718Skan op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), UNSPEC_PLT); 8379107590Sobrien op[4] = gen_rtx_CONST (Pmode, op[4]); 8380107590Sobrien } 8381107590Sobrien 8382107590Sobrien if (TARGET_64BIT) 8383107590Sobrien { 8384107590Sobrien output_asm_insn ("stg\t%0,%1", op); 8385107590Sobrien output_asm_insn ("larl\t%2,%3", op); 8386107590Sobrien output_asm_insn ("brasl\t%0,%4", op); 8387107590Sobrien output_asm_insn ("lg\t%0,%1", op); 8388107590Sobrien } 8389107590Sobrien else if (!flag_pic) 8390107590Sobrien { 8391107590Sobrien op[6] = gen_label_rtx (); 8392107590Sobrien 8393107590Sobrien output_asm_insn ("st\t%0,%1", op); 8394107590Sobrien output_asm_insn ("bras\t%2,%l6", op); 8395107590Sobrien output_asm_insn (".long\t%4", op); 8396107590Sobrien output_asm_insn (".long\t%3", op); 8397132718Skan targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6])); 8398107590Sobrien output_asm_insn ("l\t%0,0(%2)", op); 8399107590Sobrien output_asm_insn ("l\t%2,4(%2)", op); 8400107590Sobrien output_asm_insn ("basr\t%0,%0", op); 8401107590Sobrien output_asm_insn ("l\t%0,%1", op); 8402107590Sobrien } 8403107590Sobrien else 8404107590Sobrien { 8405107590Sobrien op[5] = gen_label_rtx (); 8406107590Sobrien op[6] = gen_label_rtx (); 8407107590Sobrien 8408107590Sobrien output_asm_insn ("st\t%0,%1", op); 8409107590Sobrien output_asm_insn ("bras\t%2,%l6", op); 8410132718Skan targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[5])); 8411107590Sobrien output_asm_insn (".long\t%4-%l5", op); 8412107590Sobrien output_asm_insn (".long\t%3-%l5", op); 8413132718Skan targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6])); 8414107590Sobrien output_asm_insn ("lr\t%0,%2", op); 8415107590Sobrien output_asm_insn ("a\t%0,0(%2)", op); 8416107590Sobrien output_asm_insn ("a\t%2,4(%2)", op); 8417107590Sobrien output_asm_insn ("basr\t%0,%0", op); 8418107590Sobrien output_asm_insn ("l\t%0,%1", op); 8419107590Sobrien } 8420107590Sobrien} 8421107590Sobrien 8422117395Skan/* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF 8423132718Skan into its SYMBOL_REF_FLAGS. */ 8424117395Skan 8425117395Skanstatic void 8426132718Skans390_encode_section_info (tree decl, rtx rtl, int first) 8427117395Skan{ 8428132718Skan default_encode_section_info (decl, rtl, first); 8429117395Skan 8430132718Skan /* If a variable has a forced alignment to < 2 bytes, mark it with 8431132718Skan SYMBOL_FLAG_ALIGN1 to prevent it from being used as LARL operand. */ 8432132718Skan if (TREE_CODE (decl) == VAR_DECL 8433132718Skan && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16) 8434132718Skan SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1; 8435117395Skan} 8436117395Skan 8437117395Skan/* Output thunk to FILE that implements a C++ virtual function call (with 8438132718Skan multiple inheritance) to FUNCTION. The thunk adjusts the this pointer 8439117395Skan by DELTA, and unless VCALL_OFFSET is zero, applies an additional adjustment 8440117395Skan stored at VCALL_OFFSET in the vtable whose address is located at offset 0 8441117395Skan relative to the resulting this pointer. */ 8442117395Skan 8443117395Skanstatic void 8444132718Skans390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, 8445132718Skan HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 8446132718Skan tree function) 8447117395Skan{ 8448117395Skan rtx op[10]; 8449117395Skan int nonlocal = 0; 8450117395Skan 8451117395Skan /* Operand 0 is the target function. */ 8452117395Skan op[0] = XEXP (DECL_RTL (function), 0); 8453132718Skan if (flag_pic && !SYMBOL_REF_LOCAL_P (op[0])) 8454117395Skan { 8455117395Skan nonlocal = 1; 8456117395Skan op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]), 8457132718Skan TARGET_64BIT ? UNSPEC_PLT : UNSPEC_GOT); 8458117395Skan op[0] = gen_rtx_CONST (Pmode, op[0]); 8459117395Skan } 8460117395Skan 8461117395Skan /* Operand 1 is the 'this' pointer. */ 8462132718Skan if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) 8463117395Skan op[1] = gen_rtx_REG (Pmode, 3); 8464117395Skan else 8465117395Skan op[1] = gen_rtx_REG (Pmode, 2); 8466117395Skan 8467117395Skan /* Operand 2 is the delta. */ 8468117395Skan op[2] = GEN_INT (delta); 8469117395Skan 8470117395Skan /* Operand 3 is the vcall_offset. */ 8471117395Skan op[3] = GEN_INT (vcall_offset); 8472117395Skan 8473117395Skan /* Operand 4 is the temporary register. */ 8474117395Skan op[4] = gen_rtx_REG (Pmode, 1); 8475117395Skan 8476117395Skan /* Operands 5 to 8 can be used as labels. */ 8477117395Skan op[5] = NULL_RTX; 8478117395Skan op[6] = NULL_RTX; 8479117395Skan op[7] = NULL_RTX; 8480117395Skan op[8] = NULL_RTX; 8481117395Skan 8482117395Skan /* Operand 9 can be used for temporary register. */ 8483117395Skan op[9] = NULL_RTX; 8484117395Skan 8485117395Skan /* Generate code. */ 8486117395Skan if (TARGET_64BIT) 8487117395Skan { 8488117395Skan /* Setup literal pool pointer if required. */ 8489132718Skan if ((!DISP_IN_RANGE (delta) 8490169689Skan && !CONST_OK_FOR_K (delta) 8491169689Skan && !CONST_OK_FOR_Os (delta)) 8492132718Skan || (!DISP_IN_RANGE (vcall_offset) 8493169689Skan && !CONST_OK_FOR_K (vcall_offset) 8494169689Skan && !CONST_OK_FOR_Os (vcall_offset))) 8495117395Skan { 8496117395Skan op[5] = gen_label_rtx (); 8497117395Skan output_asm_insn ("larl\t%4,%5", op); 8498117395Skan } 8499117395Skan 8500117395Skan /* Add DELTA to this pointer. */ 8501117395Skan if (delta) 8502117395Skan { 8503169689Skan if (CONST_OK_FOR_J (delta)) 8504117395Skan output_asm_insn ("la\t%1,%2(%1)", op); 8505132718Skan else if (DISP_IN_RANGE (delta)) 8506132718Skan output_asm_insn ("lay\t%1,%2(%1)", op); 8507169689Skan else if (CONST_OK_FOR_K (delta)) 8508117395Skan output_asm_insn ("aghi\t%1,%2", op); 8509169689Skan else if (CONST_OK_FOR_Os (delta)) 8510169689Skan output_asm_insn ("agfi\t%1,%2", op); 8511117395Skan else 8512117395Skan { 8513117395Skan op[6] = gen_label_rtx (); 8514117395Skan output_asm_insn ("agf\t%1,%6-%5(%4)", op); 8515117395Skan } 8516117395Skan } 8517117395Skan 8518117395Skan /* Perform vcall adjustment. */ 8519117395Skan if (vcall_offset) 8520117395Skan { 8521132718Skan if (DISP_IN_RANGE (vcall_offset)) 8522117395Skan { 8523117395Skan output_asm_insn ("lg\t%4,0(%1)", op); 8524117395Skan output_asm_insn ("ag\t%1,%3(%4)", op); 8525117395Skan } 8526169689Skan else if (CONST_OK_FOR_K (vcall_offset)) 8527117395Skan { 8528117395Skan output_asm_insn ("lghi\t%4,%3", op); 8529117395Skan output_asm_insn ("ag\t%4,0(%1)", op); 8530117395Skan output_asm_insn ("ag\t%1,0(%4)", op); 8531117395Skan } 8532169689Skan else if (CONST_OK_FOR_Os (vcall_offset)) 8533169689Skan { 8534169689Skan output_asm_insn ("lgfi\t%4,%3", op); 8535169689Skan output_asm_insn ("ag\t%4,0(%1)", op); 8536169689Skan output_asm_insn ("ag\t%1,0(%4)", op); 8537169689Skan } 8538117395Skan else 8539117395Skan { 8540117395Skan op[7] = gen_label_rtx (); 8541117395Skan output_asm_insn ("llgf\t%4,%7-%5(%4)", op); 8542117395Skan output_asm_insn ("ag\t%4,0(%1)", op); 8543117395Skan output_asm_insn ("ag\t%1,0(%4)", op); 8544117395Skan } 8545117395Skan } 8546132718Skan 8547117395Skan /* Jump to target. */ 8548117395Skan output_asm_insn ("jg\t%0", op); 8549117395Skan 8550117395Skan /* Output literal pool if required. */ 8551117395Skan if (op[5]) 8552117395Skan { 8553117395Skan output_asm_insn (".align\t4", op); 8554132718Skan targetm.asm_out.internal_label (file, "L", 8555132718Skan CODE_LABEL_NUMBER (op[5])); 8556117395Skan } 8557117395Skan if (op[6]) 8558117395Skan { 8559132718Skan targetm.asm_out.internal_label (file, "L", 8560132718Skan CODE_LABEL_NUMBER (op[6])); 8561117395Skan output_asm_insn (".long\t%2", op); 8562117395Skan } 8563117395Skan if (op[7]) 8564117395Skan { 8565132718Skan targetm.asm_out.internal_label (file, "L", 8566132718Skan CODE_LABEL_NUMBER (op[7])); 8567117395Skan output_asm_insn (".long\t%3", op); 8568117395Skan } 8569117395Skan } 8570117395Skan else 8571117395Skan { 8572117395Skan /* Setup base pointer if required. */ 8573117395Skan if (!vcall_offset 8574132718Skan || (!DISP_IN_RANGE (delta) 8575169689Skan && !CONST_OK_FOR_K (delta) 8576169689Skan && !CONST_OK_FOR_Os (delta)) 8577132718Skan || (!DISP_IN_RANGE (delta) 8578169689Skan && !CONST_OK_FOR_K (vcall_offset) 8579169689Skan && !CONST_OK_FOR_Os (vcall_offset))) 8580117395Skan { 8581117395Skan op[5] = gen_label_rtx (); 8582117395Skan output_asm_insn ("basr\t%4,0", op); 8583132718Skan targetm.asm_out.internal_label (file, "L", 8584132718Skan CODE_LABEL_NUMBER (op[5])); 8585117395Skan } 8586117395Skan 8587117395Skan /* Add DELTA to this pointer. */ 8588117395Skan if (delta) 8589117395Skan { 8590169689Skan if (CONST_OK_FOR_J (delta)) 8591117395Skan output_asm_insn ("la\t%1,%2(%1)", op); 8592132718Skan else if (DISP_IN_RANGE (delta)) 8593132718Skan output_asm_insn ("lay\t%1,%2(%1)", op); 8594169689Skan else if (CONST_OK_FOR_K (delta)) 8595117395Skan output_asm_insn ("ahi\t%1,%2", op); 8596169689Skan else if (CONST_OK_FOR_Os (delta)) 8597169689Skan output_asm_insn ("afi\t%1,%2", op); 8598117395Skan else 8599117395Skan { 8600117395Skan op[6] = gen_label_rtx (); 8601117395Skan output_asm_insn ("a\t%1,%6-%5(%4)", op); 8602117395Skan } 8603117395Skan } 8604117395Skan 8605117395Skan /* Perform vcall adjustment. */ 8606117395Skan if (vcall_offset) 8607117395Skan { 8608169689Skan if (CONST_OK_FOR_J (vcall_offset)) 8609117395Skan { 8610169689Skan output_asm_insn ("l\t%4,0(%1)", op); 8611117395Skan output_asm_insn ("a\t%1,%3(%4)", op); 8612117395Skan } 8613132718Skan else if (DISP_IN_RANGE (vcall_offset)) 8614117395Skan { 8615169689Skan output_asm_insn ("l\t%4,0(%1)", op); 8616132718Skan output_asm_insn ("ay\t%1,%3(%4)", op); 8617132718Skan } 8618169689Skan else if (CONST_OK_FOR_K (vcall_offset)) 8619132718Skan { 8620117395Skan output_asm_insn ("lhi\t%4,%3", op); 8621117395Skan output_asm_insn ("a\t%4,0(%1)", op); 8622117395Skan output_asm_insn ("a\t%1,0(%4)", op); 8623117395Skan } 8624169689Skan else if (CONST_OK_FOR_Os (vcall_offset)) 8625169689Skan { 8626169689Skan output_asm_insn ("iilf\t%4,%3", op); 8627169689Skan output_asm_insn ("a\t%4,0(%1)", op); 8628169689Skan output_asm_insn ("a\t%1,0(%4)", op); 8629169689Skan } 8630117395Skan else 8631117395Skan { 8632117395Skan op[7] = gen_label_rtx (); 8633117395Skan output_asm_insn ("l\t%4,%7-%5(%4)", op); 8634117395Skan output_asm_insn ("a\t%4,0(%1)", op); 8635117395Skan output_asm_insn ("a\t%1,0(%4)", op); 8636117395Skan } 8637117395Skan 8638117395Skan /* We had to clobber the base pointer register. 8639117395Skan Re-setup the base pointer (with a different base). */ 8640117395Skan op[5] = gen_label_rtx (); 8641117395Skan output_asm_insn ("basr\t%4,0", op); 8642132718Skan targetm.asm_out.internal_label (file, "L", 8643132718Skan CODE_LABEL_NUMBER (op[5])); 8644117395Skan } 8645117395Skan 8646117395Skan /* Jump to target. */ 8647117395Skan op[8] = gen_label_rtx (); 8648117395Skan 8649117395Skan if (!flag_pic) 8650117395Skan output_asm_insn ("l\t%4,%8-%5(%4)", op); 8651117395Skan else if (!nonlocal) 8652117395Skan output_asm_insn ("a\t%4,%8-%5(%4)", op); 8653117395Skan /* We cannot call through .plt, since .plt requires %r12 loaded. */ 8654117395Skan else if (flag_pic == 1) 8655117395Skan { 8656117395Skan output_asm_insn ("a\t%4,%8-%5(%4)", op); 8657117395Skan output_asm_insn ("l\t%4,%0(%4)", op); 8658117395Skan } 8659117395Skan else if (flag_pic == 2) 8660117395Skan { 8661117395Skan op[9] = gen_rtx_REG (Pmode, 0); 8662117395Skan output_asm_insn ("l\t%9,%8-4-%5(%4)", op); 8663117395Skan output_asm_insn ("a\t%4,%8-%5(%4)", op); 8664117395Skan output_asm_insn ("ar\t%4,%9", op); 8665117395Skan output_asm_insn ("l\t%4,0(%4)", op); 8666117395Skan } 8667117395Skan 8668117395Skan output_asm_insn ("br\t%4", op); 8669117395Skan 8670117395Skan /* Output literal pool. */ 8671117395Skan output_asm_insn (".align\t4", op); 8672117395Skan 8673117395Skan if (nonlocal && flag_pic == 2) 8674117395Skan output_asm_insn (".long\t%0", op); 8675117395Skan if (nonlocal) 8676117395Skan { 8677117395Skan op[0] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 8678132718Skan SYMBOL_REF_FLAGS (op[0]) = SYMBOL_FLAG_LOCAL; 8679117395Skan } 8680117395Skan 8681132718Skan targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[8])); 8682117395Skan if (!flag_pic) 8683117395Skan output_asm_insn (".long\t%0", op); 8684117395Skan else 8685117395Skan output_asm_insn (".long\t%0-%5", op); 8686117395Skan 8687117395Skan if (op[6]) 8688117395Skan { 8689132718Skan targetm.asm_out.internal_label (file, "L", 8690132718Skan CODE_LABEL_NUMBER (op[6])); 8691117395Skan output_asm_insn (".long\t%2", op); 8692117395Skan } 8693117395Skan if (op[7]) 8694117395Skan { 8695132718Skan targetm.asm_out.internal_label (file, "L", 8696132718Skan CODE_LABEL_NUMBER (op[7])); 8697117395Skan output_asm_insn (".long\t%3", op); 8698117395Skan } 8699117395Skan } 8700117395Skan} 8701117395Skan 8702169689Skanstatic bool 8703132718Skans390_valid_pointer_mode (enum machine_mode mode) 8704132718Skan{ 8705132718Skan return (mode == SImode || (TARGET_64BIT && mode == DImode)); 8706132718Skan} 8707132718Skan 8708169689Skan/* Checks whether the given ARGUMENT_LIST would use a caller 8709169689Skan saved register. This is used to decide whether sibling call 8710169689Skan optimization could be performed on the respective function 8711169689Skan call. */ 8712117395Skan 8713169689Skanstatic bool 8714169689Skans390_call_saved_register_used (tree argument_list) 8715117395Skan{ 8716169689Skan CUMULATIVE_ARGS cum; 8717169689Skan tree parameter; 8718169689Skan enum machine_mode mode; 8719169689Skan tree type; 8720169689Skan rtx parm_rtx; 8721169689Skan int reg; 8722169689Skan 8723169689Skan INIT_CUMULATIVE_ARGS (cum, NULL, NULL, 0, 0); 8724169689Skan 8725169689Skan while (argument_list) 8726169689Skan { 8727169689Skan parameter = TREE_VALUE (argument_list); 8728169689Skan argument_list = TREE_CHAIN (argument_list); 8729169689Skan 8730169689Skan gcc_assert (parameter); 8731169689Skan 8732169689Skan /* For an undeclared variable passed as parameter we will get 8733169689Skan an ERROR_MARK node here. */ 8734169689Skan if (TREE_CODE (parameter) == ERROR_MARK) 8735169689Skan return true; 8736169689Skan 8737169689Skan type = TREE_TYPE (parameter); 8738169689Skan gcc_assert (type); 8739169689Skan 8740169689Skan mode = TYPE_MODE (type); 8741169689Skan gcc_assert (mode); 8742169689Skan 8743169689Skan if (pass_by_reference (&cum, mode, type, true)) 8744169689Skan { 8745169689Skan mode = Pmode; 8746169689Skan type = build_pointer_type (type); 8747169689Skan } 8748169689Skan 8749169689Skan parm_rtx = s390_function_arg (&cum, mode, type, 0); 8750169689Skan 8751169689Skan s390_function_arg_advance (&cum, mode, type, 0); 8752169689Skan 8753169689Skan if (parm_rtx && REG_P (parm_rtx)) 8754169689Skan { 8755169689Skan for (reg = 0; 8756169689Skan reg < HARD_REGNO_NREGS (REGNO (parm_rtx), GET_MODE (parm_rtx)); 8757169689Skan reg++) 8758169689Skan if (! call_used_regs[reg + REGNO (parm_rtx)]) 8759169689Skan return true; 8760169689Skan } 8761169689Skan } 8762169689Skan return false; 8763117395Skan} 8764117395Skan 8765169689Skan/* Return true if the given call expression can be 8766169689Skan turned into a sibling call. 8767169689Skan DECL holds the declaration of the function to be called whereas 8768169689Skan EXP is the call expression itself. */ 8769169689Skan 8770169689Skanstatic bool 8771169689Skans390_function_ok_for_sibcall (tree decl, tree exp) 8772169689Skan{ 8773169689Skan /* The TPF epilogue uses register 1. */ 8774169689Skan if (TARGET_TPF_PROFILING) 8775169689Skan return false; 8776169689Skan 8777169689Skan /* The 31 bit PLT code uses register 12 (GOT pointer - caller saved) 8778169689Skan which would have to be restored before the sibcall. */ 8779169689Skan if (!TARGET_64BIT && flag_pic && decl && !targetm.binds_local_p (decl)) 8780169689Skan return false; 8781169689Skan 8782169689Skan /* Register 6 on s390 is available as an argument register but unfortunately 8783169689Skan "caller saved". This makes functions needing this register for arguments 8784169689Skan not suitable for sibcalls. */ 8785169689Skan if (TREE_OPERAND (exp, 1) 8786169689Skan && s390_call_saved_register_used (TREE_OPERAND (exp, 1))) 8787169689Skan return false; 8788169689Skan 8789169689Skan return true; 8790169689Skan} 8791169689Skan 8792169689Skan/* Return the fixed registers used for condition codes. */ 8793169689Skan 8794169689Skanstatic bool 8795169689Skans390_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2) 8796169689Skan{ 8797169689Skan *p1 = CC_REGNUM; 8798169689Skan *p2 = INVALID_REGNUM; 8799169689Skan 8800169689Skan return true; 8801169689Skan} 8802169689Skan 8803169689Skan/* This function is used by the call expanders of the machine description. 8804169689Skan It emits the call insn itself together with the necessary operations 8805169689Skan to adjust the target address and returns the emitted insn. 8806169689Skan ADDR_LOCATION is the target address rtx 8807169689Skan TLS_CALL the location of the thread-local symbol 8808169689Skan RESULT_REG the register where the result of the call should be stored 8809169689Skan RETADDR_REG the register where the return address should be stored 8810169689Skan If this parameter is NULL_RTX the call is considered 8811169689Skan to be a sibling call. */ 8812169689Skan 8813169689Skanrtx 8814169689Skans390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg, 8815169689Skan rtx retaddr_reg) 8816169689Skan{ 8817169689Skan bool plt_call = false; 8818169689Skan rtx insn; 8819169689Skan rtx call; 8820169689Skan rtx clobber; 8821169689Skan rtvec vec; 8822169689Skan 8823169689Skan /* Direct function calls need special treatment. */ 8824169689Skan if (GET_CODE (addr_location) == SYMBOL_REF) 8825169689Skan { 8826169689Skan /* When calling a global routine in PIC mode, we must 8827169689Skan replace the symbol itself with the PLT stub. */ 8828169689Skan if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location)) 8829169689Skan { 8830169689Skan addr_location = gen_rtx_UNSPEC (Pmode, 8831169689Skan gen_rtvec (1, addr_location), 8832169689Skan UNSPEC_PLT); 8833169689Skan addr_location = gen_rtx_CONST (Pmode, addr_location); 8834169689Skan plt_call = true; 8835169689Skan } 8836169689Skan 8837169689Skan /* Unless we can use the bras(l) insn, force the 8838169689Skan routine address into a register. */ 8839169689Skan if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH) 8840169689Skan { 8841169689Skan if (flag_pic) 8842169689Skan addr_location = legitimize_pic_address (addr_location, 0); 8843169689Skan else 8844169689Skan addr_location = force_reg (Pmode, addr_location); 8845169689Skan } 8846169689Skan } 8847169689Skan 8848169689Skan /* If it is already an indirect call or the code above moved the 8849169689Skan SYMBOL_REF to somewhere else make sure the address can be found in 8850169689Skan register 1. */ 8851169689Skan if (retaddr_reg == NULL_RTX 8852169689Skan && GET_CODE (addr_location) != SYMBOL_REF 8853169689Skan && !plt_call) 8854169689Skan { 8855169689Skan emit_move_insn (gen_rtx_REG (Pmode, SIBCALL_REGNUM), addr_location); 8856169689Skan addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM); 8857169689Skan } 8858169689Skan 8859169689Skan addr_location = gen_rtx_MEM (QImode, addr_location); 8860169689Skan call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx); 8861169689Skan 8862169689Skan if (result_reg != NULL_RTX) 8863169689Skan call = gen_rtx_SET (VOIDmode, result_reg, call); 8864169689Skan 8865169689Skan if (retaddr_reg != NULL_RTX) 8866169689Skan { 8867169689Skan clobber = gen_rtx_CLOBBER (VOIDmode, retaddr_reg); 8868169689Skan 8869169689Skan if (tls_call != NULL_RTX) 8870169689Skan vec = gen_rtvec (3, call, clobber, 8871169689Skan gen_rtx_USE (VOIDmode, tls_call)); 8872169689Skan else 8873169689Skan vec = gen_rtvec (2, call, clobber); 8874169689Skan 8875169689Skan call = gen_rtx_PARALLEL (VOIDmode, vec); 8876169689Skan } 8877169689Skan 8878169689Skan insn = emit_call_insn (call); 8879169689Skan 8880169689Skan /* 31-bit PLT stubs and tls calls use the GOT register implicitly. */ 8881169689Skan if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX) 8882169689Skan { 8883169689Skan /* s390_function_ok_for_sibcall should 8884169689Skan have denied sibcalls in this case. */ 8885169689Skan gcc_assert (retaddr_reg != NULL_RTX); 8886169689Skan 8887169689Skan use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); 8888169689Skan } 8889169689Skan return insn; 8890169689Skan} 8891169689Skan 8892169689Skan/* Implement CONDITIONAL_REGISTER_USAGE. */ 8893169689Skan 8894169689Skanvoid 8895169689Skans390_conditional_register_usage (void) 8896169689Skan{ 8897169689Skan int i; 8898169689Skan 8899169689Skan if (flag_pic) 8900169689Skan { 8901169689Skan fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 8902169689Skan call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 8903169689Skan } 8904169689Skan if (TARGET_CPU_ZARCH) 8905169689Skan { 8906169689Skan fixed_regs[BASE_REGNUM] = 0; 8907169689Skan call_used_regs[BASE_REGNUM] = 0; 8908169689Skan fixed_regs[RETURN_REGNUM] = 0; 8909169689Skan call_used_regs[RETURN_REGNUM] = 0; 8910169689Skan } 8911169689Skan if (TARGET_64BIT) 8912169689Skan { 8913169689Skan for (i = 24; i < 32; i++) 8914169689Skan call_used_regs[i] = call_really_used_regs[i] = 0; 8915169689Skan } 8916169689Skan else 8917169689Skan { 8918169689Skan for (i = 18; i < 20; i++) 8919169689Skan call_used_regs[i] = call_really_used_regs[i] = 0; 8920169689Skan } 8921169689Skan 8922169689Skan if (TARGET_SOFT_FLOAT) 8923169689Skan { 8924169689Skan for (i = 16; i < 32; i++) 8925169689Skan call_used_regs[i] = fixed_regs[i] = 1; 8926169689Skan } 8927169689Skan} 8928169689Skan 8929169689Skan/* Corresponding function to eh_return expander. */ 8930169689Skan 8931169689Skanstatic GTY(()) rtx s390_tpf_eh_return_symbol; 8932169689Skanvoid 8933169689Skans390_emit_tpf_eh_return (rtx target) 8934169689Skan{ 8935169689Skan rtx insn, reg; 8936169689Skan 8937169689Skan if (!s390_tpf_eh_return_symbol) 8938169689Skan s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return"); 8939169689Skan 8940169689Skan reg = gen_rtx_REG (Pmode, 2); 8941169689Skan 8942169689Skan emit_move_insn (reg, target); 8943169689Skan insn = s390_emit_call (s390_tpf_eh_return_symbol, NULL_RTX, reg, 8944169689Skan gen_rtx_REG (Pmode, RETURN_REGNUM)); 8945169689Skan use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg); 8946169689Skan 8947169689Skan emit_move_insn (EH_RETURN_HANDLER_RTX, reg); 8948169689Skan} 8949169689Skan 8950169689Skan/* Rework the prologue/epilogue to avoid saving/restoring 8951169689Skan registers unnecessarily. */ 8952169689Skan 8953169689Skanstatic void 8954169689Skans390_optimize_prologue (void) 8955169689Skan{ 8956169689Skan rtx insn, new_insn, next_insn; 8957169689Skan 8958169689Skan /* Do a final recompute of the frame-related data. */ 8959169689Skan 8960169689Skan s390_update_frame_layout (); 8961169689Skan 8962169689Skan /* If all special registers are in fact used, there's nothing we 8963169689Skan can do, so no point in walking the insn list. */ 8964169689Skan 8965169689Skan if (cfun_frame_layout.first_save_gpr <= BASE_REGNUM 8966169689Skan && cfun_frame_layout.last_save_gpr >= BASE_REGNUM 8967169689Skan && (TARGET_CPU_ZARCH 8968169689Skan || (cfun_frame_layout.first_save_gpr <= RETURN_REGNUM 8969169689Skan && cfun_frame_layout.last_save_gpr >= RETURN_REGNUM))) 8970169689Skan return; 8971169689Skan 8972169689Skan /* Search for prologue/epilogue insns and replace them. */ 8973169689Skan 8974169689Skan for (insn = get_insns (); insn; insn = next_insn) 8975169689Skan { 8976169689Skan int first, last, off; 8977169689Skan rtx set, base, offset; 8978169689Skan 8979169689Skan next_insn = NEXT_INSN (insn); 8980169689Skan 8981169689Skan if (GET_CODE (insn) != INSN) 8982169689Skan continue; 8983169689Skan 8984169689Skan if (GET_CODE (PATTERN (insn)) == PARALLEL 8985169689Skan && store_multiple_operation (PATTERN (insn), VOIDmode)) 8986169689Skan { 8987169689Skan set = XVECEXP (PATTERN (insn), 0, 0); 8988169689Skan first = REGNO (SET_SRC (set)); 8989169689Skan last = first + XVECLEN (PATTERN (insn), 0) - 1; 8990169689Skan offset = const0_rtx; 8991169689Skan base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); 8992169689Skan off = INTVAL (offset); 8993169689Skan 8994169689Skan if (GET_CODE (base) != REG || off < 0) 8995169689Skan continue; 8996169689Skan if (cfun_frame_layout.first_save_gpr != -1 8997169689Skan && (cfun_frame_layout.first_save_gpr < first 8998169689Skan || cfun_frame_layout.last_save_gpr > last)) 8999169689Skan continue; 9000169689Skan if (REGNO (base) != STACK_POINTER_REGNUM 9001169689Skan && REGNO (base) != HARD_FRAME_POINTER_REGNUM) 9002169689Skan continue; 9003169689Skan if (first > BASE_REGNUM || last < BASE_REGNUM) 9004169689Skan continue; 9005169689Skan 9006169689Skan if (cfun_frame_layout.first_save_gpr != -1) 9007169689Skan { 9008169689Skan new_insn = save_gprs (base, 9009169689Skan off + (cfun_frame_layout.first_save_gpr 9010169689Skan - first) * UNITS_PER_WORD, 9011169689Skan cfun_frame_layout.first_save_gpr, 9012169689Skan cfun_frame_layout.last_save_gpr); 9013169689Skan new_insn = emit_insn_before (new_insn, insn); 9014169689Skan INSN_ADDRESSES_NEW (new_insn, -1); 9015169689Skan } 9016169689Skan 9017169689Skan remove_insn (insn); 9018169689Skan continue; 9019169689Skan } 9020169689Skan 9021169689Skan if (cfun_frame_layout.first_save_gpr == -1 9022169689Skan && GET_CODE (PATTERN (insn)) == SET 9023169689Skan && GET_CODE (SET_SRC (PATTERN (insn))) == REG 9024169689Skan && (REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM 9025169689Skan || (!TARGET_CPU_ZARCH 9026169689Skan && REGNO (SET_SRC (PATTERN (insn))) == RETURN_REGNUM)) 9027169689Skan && GET_CODE (SET_DEST (PATTERN (insn))) == MEM) 9028169689Skan { 9029169689Skan set = PATTERN (insn); 9030169689Skan first = REGNO (SET_SRC (set)); 9031169689Skan offset = const0_rtx; 9032169689Skan base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); 9033169689Skan off = INTVAL (offset); 9034169689Skan 9035169689Skan if (GET_CODE (base) != REG || off < 0) 9036169689Skan continue; 9037169689Skan if (REGNO (base) != STACK_POINTER_REGNUM 9038169689Skan && REGNO (base) != HARD_FRAME_POINTER_REGNUM) 9039169689Skan continue; 9040169689Skan 9041169689Skan remove_insn (insn); 9042169689Skan continue; 9043169689Skan } 9044169689Skan 9045169689Skan if (GET_CODE (PATTERN (insn)) == PARALLEL 9046169689Skan && load_multiple_operation (PATTERN (insn), VOIDmode)) 9047169689Skan { 9048169689Skan set = XVECEXP (PATTERN (insn), 0, 0); 9049169689Skan first = REGNO (SET_DEST (set)); 9050169689Skan last = first + XVECLEN (PATTERN (insn), 0) - 1; 9051169689Skan offset = const0_rtx; 9052169689Skan base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); 9053169689Skan off = INTVAL (offset); 9054169689Skan 9055169689Skan if (GET_CODE (base) != REG || off < 0) 9056169689Skan continue; 9057169689Skan if (cfun_frame_layout.first_restore_gpr != -1 9058169689Skan && (cfun_frame_layout.first_restore_gpr < first 9059169689Skan || cfun_frame_layout.last_restore_gpr > last)) 9060169689Skan continue; 9061169689Skan if (REGNO (base) != STACK_POINTER_REGNUM 9062169689Skan && REGNO (base) != HARD_FRAME_POINTER_REGNUM) 9063169689Skan continue; 9064169689Skan if (first > BASE_REGNUM || last < BASE_REGNUM) 9065169689Skan continue; 9066169689Skan 9067169689Skan if (cfun_frame_layout.first_restore_gpr != -1) 9068169689Skan { 9069169689Skan new_insn = restore_gprs (base, 9070169689Skan off + (cfun_frame_layout.first_restore_gpr 9071169689Skan - first) * UNITS_PER_WORD, 9072169689Skan cfun_frame_layout.first_restore_gpr, 9073169689Skan cfun_frame_layout.last_restore_gpr); 9074169689Skan new_insn = emit_insn_before (new_insn, insn); 9075169689Skan INSN_ADDRESSES_NEW (new_insn, -1); 9076169689Skan } 9077169689Skan 9078169689Skan remove_insn (insn); 9079169689Skan continue; 9080169689Skan } 9081169689Skan 9082169689Skan if (cfun_frame_layout.first_restore_gpr == -1 9083169689Skan && GET_CODE (PATTERN (insn)) == SET 9084169689Skan && GET_CODE (SET_DEST (PATTERN (insn))) == REG 9085169689Skan && (REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM 9086169689Skan || (!TARGET_CPU_ZARCH 9087169689Skan && REGNO (SET_DEST (PATTERN (insn))) == RETURN_REGNUM)) 9088169689Skan && GET_CODE (SET_SRC (PATTERN (insn))) == MEM) 9089169689Skan { 9090169689Skan set = PATTERN (insn); 9091169689Skan first = REGNO (SET_DEST (set)); 9092169689Skan offset = const0_rtx; 9093169689Skan base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); 9094169689Skan off = INTVAL (offset); 9095169689Skan 9096169689Skan if (GET_CODE (base) != REG || off < 0) 9097169689Skan continue; 9098169689Skan if (REGNO (base) != STACK_POINTER_REGNUM 9099169689Skan && REGNO (base) != HARD_FRAME_POINTER_REGNUM) 9100169689Skan continue; 9101169689Skan 9102169689Skan remove_insn (insn); 9103169689Skan continue; 9104169689Skan } 9105169689Skan } 9106169689Skan} 9107169689Skan 9108169689Skan/* Perform machine-dependent processing. */ 9109169689Skan 9110169689Skanstatic void 9111169689Skans390_reorg (void) 9112169689Skan{ 9113169689Skan bool pool_overflow = false; 9114169689Skan 9115169689Skan /* Make sure all splits have been performed; splits after 9116169689Skan machine_dependent_reorg might confuse insn length counts. */ 9117169689Skan split_all_insns_noflow (); 9118169689Skan 9119169689Skan /* From here on decomposed literal pool addresses must be accepted. */ 9120169689Skan cfun->machine->decomposed_literal_pool_addresses_ok_p = true; 9121169689Skan 9122169689Skan /* Install the main literal pool and the associated base 9123169689Skan register load insns. 9124169689Skan 9125169689Skan In addition, there are two problematic situations we need 9126169689Skan to correct: 9127169689Skan 9128169689Skan - the literal pool might be > 4096 bytes in size, so that 9129169689Skan some of its elements cannot be directly accessed 9130169689Skan 9131169689Skan - a branch target might be > 64K away from the branch, so that 9132169689Skan it is not possible to use a PC-relative instruction. 9133169689Skan 9134169689Skan To fix those, we split the single literal pool into multiple 9135169689Skan pool chunks, reloading the pool base register at various 9136169689Skan points throughout the function to ensure it always points to 9137169689Skan the pool chunk the following code expects, and / or replace 9138169689Skan PC-relative branches by absolute branches. 9139169689Skan 9140169689Skan However, the two problems are interdependent: splitting the 9141169689Skan literal pool can move a branch further away from its target, 9142169689Skan causing the 64K limit to overflow, and on the other hand, 9143169689Skan replacing a PC-relative branch by an absolute branch means 9144169689Skan we need to put the branch target address into the literal 9145169689Skan pool, possibly causing it to overflow. 9146169689Skan 9147169689Skan So, we loop trying to fix up both problems until we manage 9148169689Skan to satisfy both conditions at the same time. Note that the 9149169689Skan loop is guaranteed to terminate as every pass of the loop 9150169689Skan strictly decreases the total number of PC-relative branches 9151169689Skan in the function. (This is not completely true as there 9152169689Skan might be branch-over-pool insns introduced by chunkify_start. 9153169689Skan Those never need to be split however.) */ 9154169689Skan 9155169689Skan for (;;) 9156169689Skan { 9157169689Skan struct constant_pool *pool = NULL; 9158169689Skan 9159169689Skan /* Collect the literal pool. */ 9160169689Skan if (!pool_overflow) 9161169689Skan { 9162169689Skan pool = s390_mainpool_start (); 9163169689Skan if (!pool) 9164169689Skan pool_overflow = true; 9165169689Skan } 9166169689Skan 9167169689Skan /* If literal pool overflowed, start to chunkify it. */ 9168169689Skan if (pool_overflow) 9169169689Skan pool = s390_chunkify_start (); 9170169689Skan 9171169689Skan /* Split out-of-range branches. If this has created new 9172169689Skan literal pool entries, cancel current chunk list and 9173169689Skan recompute it. zSeries machines have large branch 9174169689Skan instructions, so we never need to split a branch. */ 9175169689Skan if (!TARGET_CPU_ZARCH && s390_split_branches ()) 9176169689Skan { 9177169689Skan if (pool_overflow) 9178169689Skan s390_chunkify_cancel (pool); 9179169689Skan else 9180169689Skan s390_mainpool_cancel (pool); 9181169689Skan 9182169689Skan continue; 9183169689Skan } 9184169689Skan 9185169689Skan /* If we made it up to here, both conditions are satisfied. 9186169689Skan Finish up literal pool related changes. */ 9187169689Skan if (pool_overflow) 9188169689Skan s390_chunkify_finish (pool); 9189169689Skan else 9190169689Skan s390_mainpool_finish (pool); 9191169689Skan 9192169689Skan /* We're done splitting branches. */ 9193169689Skan cfun->machine->split_branches_pending_p = false; 9194169689Skan break; 9195169689Skan } 9196169689Skan 9197169689Skan /* Generate out-of-pool execute target insns. */ 9198169689Skan if (TARGET_CPU_ZARCH) 9199169689Skan { 9200169689Skan rtx insn, label, target; 9201169689Skan 9202169689Skan for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 9203169689Skan { 9204169689Skan label = s390_execute_label (insn); 9205169689Skan if (!label) 9206169689Skan continue; 9207169689Skan 9208169689Skan gcc_assert (label != const0_rtx); 9209169689Skan 9210169689Skan target = emit_label (XEXP (label, 0)); 9211169689Skan INSN_ADDRESSES_NEW (target, -1); 9212169689Skan 9213169689Skan target = emit_insn (s390_execute_target (insn)); 9214169689Skan INSN_ADDRESSES_NEW (target, -1); 9215169689Skan } 9216169689Skan } 9217169689Skan 9218169689Skan /* Try to optimize prologue and epilogue further. */ 9219169689Skan s390_optimize_prologue (); 9220169689Skan} 9221169689Skan 9222169689Skan 9223169689Skan/* Initialize GCC target structure. */ 9224169689Skan 9225169689Skan#undef TARGET_ASM_ALIGNED_HI_OP 9226169689Skan#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" 9227169689Skan#undef TARGET_ASM_ALIGNED_DI_OP 9228169689Skan#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" 9229169689Skan#undef TARGET_ASM_INTEGER 9230169689Skan#define TARGET_ASM_INTEGER s390_assemble_integer 9231169689Skan 9232169689Skan#undef TARGET_ASM_OPEN_PAREN 9233169689Skan#define TARGET_ASM_OPEN_PAREN "" 9234169689Skan 9235169689Skan#undef TARGET_ASM_CLOSE_PAREN 9236169689Skan#define TARGET_ASM_CLOSE_PAREN "" 9237169689Skan 9238169689Skan#undef TARGET_DEFAULT_TARGET_FLAGS 9239169689Skan#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_FUSED_MADD) 9240169689Skan#undef TARGET_HANDLE_OPTION 9241169689Skan#define TARGET_HANDLE_OPTION s390_handle_option 9242169689Skan 9243169689Skan#undef TARGET_ENCODE_SECTION_INFO 9244169689Skan#define TARGET_ENCODE_SECTION_INFO s390_encode_section_info 9245169689Skan 9246169689Skan#ifdef HAVE_AS_TLS 9247169689Skan#undef TARGET_HAVE_TLS 9248169689Skan#define TARGET_HAVE_TLS true 9249169689Skan#endif 9250169689Skan#undef TARGET_CANNOT_FORCE_CONST_MEM 9251169689Skan#define TARGET_CANNOT_FORCE_CONST_MEM s390_cannot_force_const_mem 9252169689Skan 9253169689Skan#undef TARGET_DELEGITIMIZE_ADDRESS 9254169689Skan#define TARGET_DELEGITIMIZE_ADDRESS s390_delegitimize_address 9255169689Skan 9256169689Skan#undef TARGET_RETURN_IN_MEMORY 9257169689Skan#define TARGET_RETURN_IN_MEMORY s390_return_in_memory 9258169689Skan 9259169689Skan#undef TARGET_INIT_BUILTINS 9260169689Skan#define TARGET_INIT_BUILTINS s390_init_builtins 9261169689Skan#undef TARGET_EXPAND_BUILTIN 9262169689Skan#define TARGET_EXPAND_BUILTIN s390_expand_builtin 9263169689Skan 9264169689Skan#undef TARGET_ASM_OUTPUT_MI_THUNK 9265169689Skan#define TARGET_ASM_OUTPUT_MI_THUNK s390_output_mi_thunk 9266169689Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 9267169689Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true 9268169689Skan 9269169689Skan#undef TARGET_SCHED_ADJUST_PRIORITY 9270169689Skan#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority 9271169689Skan#undef TARGET_SCHED_ISSUE_RATE 9272169689Skan#define TARGET_SCHED_ISSUE_RATE s390_issue_rate 9273169689Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD 9274169689Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD s390_first_cycle_multipass_dfa_lookahead 9275169689Skan 9276169689Skan#undef TARGET_CANNOT_COPY_INSN_P 9277169689Skan#define TARGET_CANNOT_COPY_INSN_P s390_cannot_copy_insn_p 9278169689Skan#undef TARGET_RTX_COSTS 9279169689Skan#define TARGET_RTX_COSTS s390_rtx_costs 9280169689Skan#undef TARGET_ADDRESS_COST 9281169689Skan#define TARGET_ADDRESS_COST s390_address_cost 9282169689Skan 9283169689Skan#undef TARGET_MACHINE_DEPENDENT_REORG 9284169689Skan#define TARGET_MACHINE_DEPENDENT_REORG s390_reorg 9285169689Skan 9286169689Skan#undef TARGET_VALID_POINTER_MODE 9287169689Skan#define TARGET_VALID_POINTER_MODE s390_valid_pointer_mode 9288169689Skan 9289169689Skan#undef TARGET_BUILD_BUILTIN_VA_LIST 9290169689Skan#define TARGET_BUILD_BUILTIN_VA_LIST s390_build_builtin_va_list 9291169689Skan#undef TARGET_GIMPLIFY_VA_ARG_EXPR 9292169689Skan#define TARGET_GIMPLIFY_VA_ARG_EXPR s390_gimplify_va_arg 9293169689Skan 9294169689Skan#undef TARGET_PROMOTE_FUNCTION_ARGS 9295169689Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true 9296169689Skan#undef TARGET_PROMOTE_FUNCTION_RETURN 9297169689Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true 9298169689Skan#undef TARGET_PASS_BY_REFERENCE 9299169689Skan#define TARGET_PASS_BY_REFERENCE s390_pass_by_reference 9300169689Skan 9301169689Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL 9302169689Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL s390_function_ok_for_sibcall 9303169689Skan 9304169689Skan#undef TARGET_FIXED_CONDITION_CODE_REGS 9305169689Skan#define TARGET_FIXED_CONDITION_CODE_REGS s390_fixed_condition_code_regs 9306169689Skan 9307169689Skan#undef TARGET_CC_MODES_COMPATIBLE 9308169689Skan#define TARGET_CC_MODES_COMPATIBLE s390_cc_modes_compatible 9309169689Skan 9310169689Skan#undef TARGET_INVALID_WITHIN_DOLOOP 9311169689Skan#define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_rtx_null 9312169689Skan 9313169689Skan#ifdef HAVE_AS_TLS 9314169689Skan#undef TARGET_ASM_OUTPUT_DWARF_DTPREL 9315169689Skan#define TARGET_ASM_OUTPUT_DWARF_DTPREL s390_output_dwarf_dtprel 9316169689Skan#endif 9317169689Skan 9318169689Skan#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING 9319169689Skan#undef TARGET_MANGLE_FUNDAMENTAL_TYPE 9320169689Skan#define TARGET_MANGLE_FUNDAMENTAL_TYPE s390_mangle_fundamental_type 9321169689Skan#endif 9322169689Skan 9323169689Skan#undef TARGET_SCALAR_MODE_SUPPORTED_P 9324169689Skan#define TARGET_SCALAR_MODE_SUPPORTED_P s390_scalar_mode_supported_p 9325169689Skan 9326169689Skanstruct gcc_target targetm = TARGET_INITIALIZER; 9327169689Skan 9328117395Skan#include "gt-s390.h" 9329