| 1 |
282 |
jeremybenn |
/* Subroutines used for code generation on IBM S/390 and zSeries
|
| 2 |
|
|
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
| 3 |
|
|
2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
| 4 |
|
|
Contributed by Hartmut Penner (hpenner@de.ibm.com) and
|
| 5 |
|
|
Ulrich Weigand (uweigand@de.ibm.com) and
|
| 6 |
|
|
Andreas Krebbel (Andreas.Krebbel@de.ibm.com).
|
| 7 |
|
|
|
| 8 |
|
|
This file is part of GCC.
|
| 9 |
|
|
|
| 10 |
|
|
GCC is free software; you can redistribute it and/or modify it under
|
| 11 |
|
|
the terms of the GNU General Public License as published by the Free
|
| 12 |
|
|
Software Foundation; either version 3, or (at your option) any later
|
| 13 |
|
|
version.
|
| 14 |
|
|
|
| 15 |
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
| 16 |
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
| 17 |
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
| 18 |
|
|
for more details.
|
| 19 |
|
|
|
| 20 |
|
|
You should have received a copy of the GNU General Public License
|
| 21 |
|
|
along with GCC; see the file COPYING3. If not see
|
| 22 |
|
|
<http://www.gnu.org/licenses/>. */
|
| 23 |
|
|
|
| 24 |
|
|
#include "config.h"
|
| 25 |
|
|
#include "system.h"
|
| 26 |
|
|
#include "coretypes.h"
|
| 27 |
|
|
#include "tm.h"
|
| 28 |
|
|
#include "rtl.h"
|
| 29 |
|
|
#include "tree.h"
|
| 30 |
|
|
#include "tm_p.h"
|
| 31 |
|
|
#include "regs.h"
|
| 32 |
|
|
#include "hard-reg-set.h"
|
| 33 |
|
|
#include "real.h"
|
| 34 |
|
|
#include "insn-config.h"
|
| 35 |
|
|
#include "conditions.h"
|
| 36 |
|
|
#include "output.h"
|
| 37 |
|
|
#include "insn-attr.h"
|
| 38 |
|
|
#include "flags.h"
|
| 39 |
|
|
#include "except.h"
|
| 40 |
|
|
#include "function.h"
|
| 41 |
|
|
#include "recog.h"
|
| 42 |
|
|
#include "expr.h"
|
| 43 |
|
|
#include "reload.h"
|
| 44 |
|
|
#include "toplev.h"
|
| 45 |
|
|
#include "basic-block.h"
|
| 46 |
|
|
#include "integrate.h"
|
| 47 |
|
|
#include "ggc.h"
|
| 48 |
|
|
#include "target.h"
|
| 49 |
|
|
#include "target-def.h"
|
| 50 |
|
|
#include "debug.h"
|
| 51 |
|
|
#include "langhooks.h"
|
| 52 |
|
|
#include "optabs.h"
|
| 53 |
|
|
#include "gimple.h"
|
| 54 |
|
|
#include "df.h"
|
| 55 |
|
|
#include "params.h"
|
| 56 |
|
|
|
| 57 |
|
|
|
| 58 |
|
|
/* Define the specific costs for a given cpu. */
|
| 59 |
|
|
|
| 60 |
|
|
struct processor_costs
|
| 61 |
|
|
{
|
| 62 |
|
|
/* multiplication */
|
| 63 |
|
|
const int m; /* cost of an M instruction. */
|
| 64 |
|
|
const int mghi; /* cost of an MGHI instruction. */
|
| 65 |
|
|
const int mh; /* cost of an MH instruction. */
|
| 66 |
|
|
const int mhi; /* cost of an MHI instruction. */
|
| 67 |
|
|
const int ml; /* cost of an ML instruction. */
|
| 68 |
|
|
const int mr; /* cost of an MR instruction. */
|
| 69 |
|
|
const int ms; /* cost of an MS instruction. */
|
| 70 |
|
|
const int msg; /* cost of an MSG instruction. */
|
| 71 |
|
|
const int msgf; /* cost of an MSGF instruction. */
|
| 72 |
|
|
const int msgfr; /* cost of an MSGFR instruction. */
|
| 73 |
|
|
const int msgr; /* cost of an MSGR instruction. */
|
| 74 |
|
|
const int msr; /* cost of an MSR instruction. */
|
| 75 |
|
|
const int mult_df; /* cost of multiplication in DFmode. */
|
| 76 |
|
|
const int mxbr;
|
| 77 |
|
|
/* square root */
|
| 78 |
|
|
const int sqxbr; /* cost of square root in TFmode. */
|
| 79 |
|
|
const int sqdbr; /* cost of square root in DFmode. */
|
| 80 |
|
|
const int sqebr; /* cost of square root in SFmode. */
|
| 81 |
|
|
/* multiply and add */
|
| 82 |
|
|
const int madbr; /* cost of multiply and add in DFmode. */
|
| 83 |
|
|
const int maebr; /* cost of multiply and add in SFmode. */
|
| 84 |
|
|
/* division */
|
| 85 |
|
|
const int dxbr;
|
| 86 |
|
|
const int ddbr;
|
| 87 |
|
|
const int debr;
|
| 88 |
|
|
const int dlgr;
|
| 89 |
|
|
const int dlr;
|
| 90 |
|
|
const int dr;
|
| 91 |
|
|
const int dsgfr;
|
| 92 |
|
|
const int dsgr;
|
| 93 |
|
|
};
|
| 94 |
|
|
|
| 95 |
|
|
const struct processor_costs *s390_cost;
|
| 96 |
|
|
|
| 97 |
|
|
static const
|
| 98 |
|
|
struct processor_costs z900_cost =
|
| 99 |
|
|
{
|
| 100 |
|
|
COSTS_N_INSNS (5), /* M */
|
| 101 |
|
|
COSTS_N_INSNS (10), /* MGHI */
|
| 102 |
|
|
COSTS_N_INSNS (5), /* MH */
|
| 103 |
|
|
COSTS_N_INSNS (4), /* MHI */
|
| 104 |
|
|
COSTS_N_INSNS (5), /* ML */
|
| 105 |
|
|
COSTS_N_INSNS (5), /* MR */
|
| 106 |
|
|
COSTS_N_INSNS (4), /* MS */
|
| 107 |
|
|
COSTS_N_INSNS (15), /* MSG */
|
| 108 |
|
|
COSTS_N_INSNS (7), /* MSGF */
|
| 109 |
|
|
COSTS_N_INSNS (7), /* MSGFR */
|
| 110 |
|
|
COSTS_N_INSNS (10), /* MSGR */
|
| 111 |
|
|
COSTS_N_INSNS (4), /* MSR */
|
| 112 |
|
|
COSTS_N_INSNS (7), /* multiplication in DFmode */
|
| 113 |
|
|
COSTS_N_INSNS (13), /* MXBR */
|
| 114 |
|
|
COSTS_N_INSNS (136), /* SQXBR */
|
| 115 |
|
|
COSTS_N_INSNS (44), /* SQDBR */
|
| 116 |
|
|
COSTS_N_INSNS (35), /* SQEBR */
|
| 117 |
|
|
COSTS_N_INSNS (18), /* MADBR */
|
| 118 |
|
|
COSTS_N_INSNS (13), /* MAEBR */
|
| 119 |
|
|
COSTS_N_INSNS (134), /* DXBR */
|
| 120 |
|
|
COSTS_N_INSNS (30), /* DDBR */
|
| 121 |
|
|
COSTS_N_INSNS (27), /* DEBR */
|
| 122 |
|
|
COSTS_N_INSNS (220), /* DLGR */
|
| 123 |
|
|
COSTS_N_INSNS (34), /* DLR */
|
| 124 |
|
|
COSTS_N_INSNS (34), /* DR */
|
| 125 |
|
|
COSTS_N_INSNS (32), /* DSGFR */
|
| 126 |
|
|
COSTS_N_INSNS (32), /* DSGR */
|
| 127 |
|
|
};
|
| 128 |
|
|
|
| 129 |
|
|
static const
|
| 130 |
|
|
struct processor_costs z990_cost =
|
| 131 |
|
|
{
|
| 132 |
|
|
COSTS_N_INSNS (4), /* M */
|
| 133 |
|
|
COSTS_N_INSNS (2), /* MGHI */
|
| 134 |
|
|
COSTS_N_INSNS (2), /* MH */
|
| 135 |
|
|
COSTS_N_INSNS (2), /* MHI */
|
| 136 |
|
|
COSTS_N_INSNS (4), /* ML */
|
| 137 |
|
|
COSTS_N_INSNS (4), /* MR */
|
| 138 |
|
|
COSTS_N_INSNS (5), /* MS */
|
| 139 |
|
|
COSTS_N_INSNS (6), /* MSG */
|
| 140 |
|
|
COSTS_N_INSNS (4), /* MSGF */
|
| 141 |
|
|
COSTS_N_INSNS (4), /* MSGFR */
|
| 142 |
|
|
COSTS_N_INSNS (4), /* MSGR */
|
| 143 |
|
|
COSTS_N_INSNS (4), /* MSR */
|
| 144 |
|
|
COSTS_N_INSNS (1), /* multiplication in DFmode */
|
| 145 |
|
|
COSTS_N_INSNS (28), /* MXBR */
|
| 146 |
|
|
COSTS_N_INSNS (130), /* SQXBR */
|
| 147 |
|
|
COSTS_N_INSNS (66), /* SQDBR */
|
| 148 |
|
|
COSTS_N_INSNS (38), /* SQEBR */
|
| 149 |
|
|
COSTS_N_INSNS (1), /* MADBR */
|
| 150 |
|
|
COSTS_N_INSNS (1), /* MAEBR */
|
| 151 |
|
|
COSTS_N_INSNS (60), /* DXBR */
|
| 152 |
|
|
COSTS_N_INSNS (40), /* DDBR */
|
| 153 |
|
|
COSTS_N_INSNS (26), /* DEBR */
|
| 154 |
|
|
COSTS_N_INSNS (176), /* DLGR */
|
| 155 |
|
|
COSTS_N_INSNS (31), /* DLR */
|
| 156 |
|
|
COSTS_N_INSNS (31), /* DR */
|
| 157 |
|
|
COSTS_N_INSNS (31), /* DSGFR */
|
| 158 |
|
|
COSTS_N_INSNS (31), /* DSGR */
|
| 159 |
|
|
};
|
| 160 |
|
|
|
| 161 |
|
|
static const
|
| 162 |
|
|
struct processor_costs z9_109_cost =
|
| 163 |
|
|
{
|
| 164 |
|
|
COSTS_N_INSNS (4), /* M */
|
| 165 |
|
|
COSTS_N_INSNS (2), /* MGHI */
|
| 166 |
|
|
COSTS_N_INSNS (2), /* MH */
|
| 167 |
|
|
COSTS_N_INSNS (2), /* MHI */
|
| 168 |
|
|
COSTS_N_INSNS (4), /* ML */
|
| 169 |
|
|
COSTS_N_INSNS (4), /* MR */
|
| 170 |
|
|
COSTS_N_INSNS (5), /* MS */
|
| 171 |
|
|
COSTS_N_INSNS (6), /* MSG */
|
| 172 |
|
|
COSTS_N_INSNS (4), /* MSGF */
|
| 173 |
|
|
COSTS_N_INSNS (4), /* MSGFR */
|
| 174 |
|
|
COSTS_N_INSNS (4), /* MSGR */
|
| 175 |
|
|
COSTS_N_INSNS (4), /* MSR */
|
| 176 |
|
|
COSTS_N_INSNS (1), /* multiplication in DFmode */
|
| 177 |
|
|
COSTS_N_INSNS (28), /* MXBR */
|
| 178 |
|
|
COSTS_N_INSNS (130), /* SQXBR */
|
| 179 |
|
|
COSTS_N_INSNS (66), /* SQDBR */
|
| 180 |
|
|
COSTS_N_INSNS (38), /* SQEBR */
|
| 181 |
|
|
COSTS_N_INSNS (1), /* MADBR */
|
| 182 |
|
|
COSTS_N_INSNS (1), /* MAEBR */
|
| 183 |
|
|
COSTS_N_INSNS (60), /* DXBR */
|
| 184 |
|
|
COSTS_N_INSNS (40), /* DDBR */
|
| 185 |
|
|
COSTS_N_INSNS (26), /* DEBR */
|
| 186 |
|
|
COSTS_N_INSNS (30), /* DLGR */
|
| 187 |
|
|
COSTS_N_INSNS (23), /* DLR */
|
| 188 |
|
|
COSTS_N_INSNS (23), /* DR */
|
| 189 |
|
|
COSTS_N_INSNS (24), /* DSGFR */
|
| 190 |
|
|
COSTS_N_INSNS (24), /* DSGR */
|
| 191 |
|
|
};
|
| 192 |
|
|
|
| 193 |
|
|
static const
|
| 194 |
|
|
struct processor_costs z10_cost =
|
| 195 |
|
|
{
|
| 196 |
|
|
COSTS_N_INSNS (10), /* M */
|
| 197 |
|
|
COSTS_N_INSNS (10), /* MGHI */
|
| 198 |
|
|
COSTS_N_INSNS (10), /* MH */
|
| 199 |
|
|
COSTS_N_INSNS (10), /* MHI */
|
| 200 |
|
|
COSTS_N_INSNS (10), /* ML */
|
| 201 |
|
|
COSTS_N_INSNS (10), /* MR */
|
| 202 |
|
|
COSTS_N_INSNS (10), /* MS */
|
| 203 |
|
|
COSTS_N_INSNS (10), /* MSG */
|
| 204 |
|
|
COSTS_N_INSNS (10), /* MSGF */
|
| 205 |
|
|
COSTS_N_INSNS (10), /* MSGFR */
|
| 206 |
|
|
COSTS_N_INSNS (10), /* MSGR */
|
| 207 |
|
|
COSTS_N_INSNS (10), /* MSR */
|
| 208 |
|
|
COSTS_N_INSNS (1) , /* multiplication in DFmode */
|
| 209 |
|
|
COSTS_N_INSNS (50), /* MXBR */
|
| 210 |
|
|
COSTS_N_INSNS (120), /* SQXBR */
|
| 211 |
|
|
COSTS_N_INSNS (52), /* SQDBR */
|
| 212 |
|
|
COSTS_N_INSNS (38), /* SQEBR */
|
| 213 |
|
|
COSTS_N_INSNS (1), /* MADBR */
|
| 214 |
|
|
COSTS_N_INSNS (1), /* MAEBR */
|
| 215 |
|
|
COSTS_N_INSNS (111), /* DXBR */
|
| 216 |
|
|
COSTS_N_INSNS (39), /* DDBR */
|
| 217 |
|
|
COSTS_N_INSNS (32), /* DEBR */
|
| 218 |
|
|
COSTS_N_INSNS (160), /* DLGR */
|
| 219 |
|
|
COSTS_N_INSNS (71), /* DLR */
|
| 220 |
|
|
COSTS_N_INSNS (71), /* DR */
|
| 221 |
|
|
COSTS_N_INSNS (71), /* DSGFR */
|
| 222 |
|
|
COSTS_N_INSNS (71), /* DSGR */
|
| 223 |
|
|
};
|
| 224 |
|
|
|
| 225 |
|
|
extern int reload_completed;
|
| 226 |
|
|
|
| 227 |
|
|
/* Kept up to date using the SCHED_VARIABLE_ISSUE hook. */
|
| 228 |
|
|
static rtx last_scheduled_insn;
|
| 229 |
|
|
|
| 230 |
|
|
/* Structure used to hold the components of a S/390 memory
|
| 231 |
|
|
address. A legitimate address on S/390 is of the general
|
| 232 |
|
|
form
|
| 233 |
|
|
base + index + displacement
|
| 234 |
|
|
where any of the components is optional.
|
| 235 |
|
|
|
| 236 |
|
|
base and index are registers of the class ADDR_REGS,
|
| 237 |
|
|
displacement is an unsigned 12-bit immediate constant. */
|
| 238 |
|
|
|
| 239 |
|
|
struct s390_address
|
| 240 |
|
|
{
|
| 241 |
|
|
rtx base;
|
| 242 |
|
|
rtx indx;
|
| 243 |
|
|
rtx disp;
|
| 244 |
|
|
bool pointer;
|
| 245 |
|
|
bool literal_pool;
|
| 246 |
|
|
};
|
| 247 |
|
|
|
| 248 |
|
|
/* Which cpu are we tuning for. */
|
| 249 |
|
|
enum processor_type s390_tune = PROCESSOR_max;
|
| 250 |
|
|
int s390_tune_flags;
|
| 251 |
|
|
/* Which instruction set architecture to use. */
|
| 252 |
|
|
enum processor_type s390_arch;
|
| 253 |
|
|
int s390_arch_flags;
|
| 254 |
|
|
|
| 255 |
|
|
HOST_WIDE_INT s390_warn_framesize = 0;
|
| 256 |
|
|
HOST_WIDE_INT s390_stack_size = 0;
|
| 257 |
|
|
HOST_WIDE_INT s390_stack_guard = 0;
|
| 258 |
|
|
|
| 259 |
|
|
/* The following structure is embedded in the machine
|
| 260 |
|
|
specific part of struct function. */
|
| 261 |
|
|
|
| 262 |
|
|
struct GTY (()) s390_frame_layout
|
| 263 |
|
|
{
|
| 264 |
|
|
/* Offset within stack frame. */
|
| 265 |
|
|
HOST_WIDE_INT gprs_offset;
|
| 266 |
|
|
HOST_WIDE_INT f0_offset;
|
| 267 |
|
|
HOST_WIDE_INT f4_offset;
|
| 268 |
|
|
HOST_WIDE_INT f8_offset;
|
| 269 |
|
|
HOST_WIDE_INT backchain_offset;
|
| 270 |
|
|
|
| 271 |
|
|
/* Number of first and last gpr where slots in the register
|
| 272 |
|
|
save area are reserved for. */
|
| 273 |
|
|
int first_save_gpr_slot;
|
| 274 |
|
|
int last_save_gpr_slot;
|
| 275 |
|
|
|
| 276 |
|
|
/* Number of first and last gpr to be saved, restored. */
|
| 277 |
|
|
int first_save_gpr;
|
| 278 |
|
|
int first_restore_gpr;
|
| 279 |
|
|
int last_save_gpr;
|
| 280 |
|
|
int last_restore_gpr;
|
| 281 |
|
|
|
| 282 |
|
|
/* Bits standing for floating point registers. Set, if the
|
| 283 |
|
|
respective register has to be saved. Starting with reg 16 (f0)
|
| 284 |
|
|
at the rightmost bit.
|
| 285 |
|
|
Bit 15 - 8 7 6 5 4 3 2 1 0
|
| 286 |
|
|
fpr 15 - 8 7 5 3 1 6 4 2 0
|
| 287 |
|
|
reg 31 - 24 23 22 21 20 19 18 17 16 */
|
| 288 |
|
|
unsigned int fpr_bitmap;
|
| 289 |
|
|
|
| 290 |
|
|
/* Number of floating point registers f8-f15 which must be saved. */
|
| 291 |
|
|
int high_fprs;
|
| 292 |
|
|
|
| 293 |
|
|
/* Set if return address needs to be saved.
|
| 294 |
|
|
This flag is set by s390_return_addr_rtx if it could not use
|
| 295 |
|
|
the initial value of r14 and therefore depends on r14 saved
|
| 296 |
|
|
to the stack. */
|
| 297 |
|
|
bool save_return_addr_p;
|
| 298 |
|
|
|
| 299 |
|
|
/* Size of stack frame. */
|
| 300 |
|
|
HOST_WIDE_INT frame_size;
|
| 301 |
|
|
};
|
| 302 |
|
|
|
| 303 |
|
|
/* Define the structure for the machine field in struct function. */
|
| 304 |
|
|
|
| 305 |
|
|
struct GTY(()) machine_function
|
| 306 |
|
|
{
|
| 307 |
|
|
struct s390_frame_layout frame_layout;
|
| 308 |
|
|
|
| 309 |
|
|
/* Literal pool base register. */
|
| 310 |
|
|
rtx base_reg;
|
| 311 |
|
|
|
| 312 |
|
|
/* True if we may need to perform branch splitting. */
|
| 313 |
|
|
bool split_branches_pending_p;
|
| 314 |
|
|
|
| 315 |
|
|
/* Some local-dynamic TLS symbol name. */
|
| 316 |
|
|
const char *some_ld_name;
|
| 317 |
|
|
|
| 318 |
|
|
bool has_landing_pad_p;
|
| 319 |
|
|
};
|
| 320 |
|
|
|
| 321 |
|
|
/* Few accessor macros for struct cfun->machine->s390_frame_layout. */
|
| 322 |
|
|
|
| 323 |
|
|
#define cfun_frame_layout (cfun->machine->frame_layout)
|
| 324 |
|
|
#define cfun_save_high_fprs_p (!!cfun_frame_layout.high_fprs)
|
| 325 |
|
|
#define cfun_gprs_save_area_size ((cfun_frame_layout.last_save_gpr_slot - \
|
| 326 |
|
|
cfun_frame_layout.first_save_gpr_slot + 1) * UNITS_PER_WORD)
|
| 327 |
|
|
#define cfun_set_fpr_bit(BITNUM) (cfun->machine->frame_layout.fpr_bitmap |= \
|
| 328 |
|
|
(1 << (BITNUM)))
|
| 329 |
|
|
#define cfun_fpr_bit_p(BITNUM) (!!(cfun->machine->frame_layout.fpr_bitmap & \
|
| 330 |
|
|
(1 << (BITNUM))))
|
| 331 |
|
|
|
| 332 |
|
|
/* Number of GPRs and FPRs used for argument passing. */
|
| 333 |
|
|
#define GP_ARG_NUM_REG 5
|
| 334 |
|
|
#define FP_ARG_NUM_REG (TARGET_64BIT? 4 : 2)
|
| 335 |
|
|
|
| 336 |
|
|
/* A couple of shortcuts. */
|
| 337 |
|
|
#define CONST_OK_FOR_J(x) \
|
| 338 |
|
|
CONST_OK_FOR_CONSTRAINT_P((x), 'J', "J")
|
| 339 |
|
|
#define CONST_OK_FOR_K(x) \
|
| 340 |
|
|
CONST_OK_FOR_CONSTRAINT_P((x), 'K', "K")
|
| 341 |
|
|
#define CONST_OK_FOR_Os(x) \
|
| 342 |
|
|
CONST_OK_FOR_CONSTRAINT_P((x), 'O', "Os")
|
| 343 |
|
|
#define CONST_OK_FOR_Op(x) \
|
| 344 |
|
|
CONST_OK_FOR_CONSTRAINT_P((x), 'O', "Op")
|
| 345 |
|
|
#define CONST_OK_FOR_On(x) \
|
| 346 |
|
|
CONST_OK_FOR_CONSTRAINT_P((x), 'O', "On")
|
| 347 |
|
|
|
| 348 |
|
|
#define REGNO_PAIR_OK(REGNO, MODE) \
|
| 349 |
|
|
(HARD_REGNO_NREGS ((REGNO), (MODE)) == 1 || !((REGNO) & 1))
|
| 350 |
|
|
|
| 351 |
|
|
/* That's the read ahead of the dynamic branch prediction unit in
|
| 352 |
|
|
bytes on a z10 CPU. */
|
| 353 |
|
|
#define Z10_PREDICT_DISTANCE 384
|
| 354 |
|
|
|
| 355 |
|
|
static enum machine_mode
|
| 356 |
|
|
s390_libgcc_cmp_return_mode (void)
|
| 357 |
|
|
{
|
| 358 |
|
|
return TARGET_64BIT ? DImode : SImode;
|
| 359 |
|
|
}
|
| 360 |
|
|
|
| 361 |
|
|
static enum machine_mode
|
| 362 |
|
|
s390_libgcc_shift_count_mode (void)
|
| 363 |
|
|
{
|
| 364 |
|
|
return TARGET_64BIT ? DImode : SImode;
|
| 365 |
|
|
}
|
| 366 |
|
|
|
| 367 |
|
|
/* Return true if the back end supports mode MODE. */
|
| 368 |
|
|
static bool
|
| 369 |
|
|
s390_scalar_mode_supported_p (enum machine_mode mode)
|
| 370 |
|
|
{
|
| 371 |
|
|
if (DECIMAL_FLOAT_MODE_P (mode))
|
| 372 |
|
|
return default_decimal_float_supported_p ();
|
| 373 |
|
|
else
|
| 374 |
|
|
return default_scalar_mode_supported_p (mode);
|
| 375 |
|
|
}
|
| 376 |
|
|
|
| 377 |
|
|
/* Set the has_landing_pad_p flag in struct machine_function to VALUE. */
|
| 378 |
|
|
|
| 379 |
|
|
void
|
| 380 |
|
|
s390_set_has_landing_pad_p (bool value)
|
| 381 |
|
|
{
|
| 382 |
|
|
cfun->machine->has_landing_pad_p = value;
|
| 383 |
|
|
}
|
| 384 |
|
|
|
| 385 |
|
|
/* If two condition code modes are compatible, return a condition code
|
| 386 |
|
|
mode which is compatible with both. Otherwise, return
|
| 387 |
|
|
VOIDmode. */
|
| 388 |
|
|
|
| 389 |
|
|
static enum machine_mode
|
| 390 |
|
|
s390_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
|
| 391 |
|
|
{
|
| 392 |
|
|
if (m1 == m2)
|
| 393 |
|
|
return m1;
|
| 394 |
|
|
|
| 395 |
|
|
switch (m1)
|
| 396 |
|
|
{
|
| 397 |
|
|
case CCZmode:
|
| 398 |
|
|
if (m2 == CCUmode || m2 == CCTmode || m2 == CCZ1mode
|
| 399 |
|
|
|| m2 == CCSmode || m2 == CCSRmode || m2 == CCURmode)
|
| 400 |
|
|
return m2;
|
| 401 |
|
|
return VOIDmode;
|
| 402 |
|
|
|
| 403 |
|
|
case CCSmode:
|
| 404 |
|
|
case CCUmode:
|
| 405 |
|
|
case CCTmode:
|
| 406 |
|
|
case CCSRmode:
|
| 407 |
|
|
case CCURmode:
|
| 408 |
|
|
case CCZ1mode:
|
| 409 |
|
|
if (m2 == CCZmode)
|
| 410 |
|
|
return m1;
|
| 411 |
|
|
|
| 412 |
|
|
return VOIDmode;
|
| 413 |
|
|
|
| 414 |
|
|
default:
|
| 415 |
|
|
return VOIDmode;
|
| 416 |
|
|
}
|
| 417 |
|
|
return VOIDmode;
|
| 418 |
|
|
}
|
| 419 |
|
|
|
| 420 |
|
|
/* Return true if SET either doesn't set the CC register, or else
|
| 421 |
|
|
the source and destination have matching CC modes and that
|
| 422 |
|
|
CC mode is at least as constrained as REQ_MODE. */
|
| 423 |
|
|
|
| 424 |
|
|
static bool
|
| 425 |
|
|
s390_match_ccmode_set (rtx set, enum machine_mode req_mode)
|
| 426 |
|
|
{
|
| 427 |
|
|
enum machine_mode set_mode;
|
| 428 |
|
|
|
| 429 |
|
|
gcc_assert (GET_CODE (set) == SET);
|
| 430 |
|
|
|
| 431 |
|
|
if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set))))
|
| 432 |
|
|
return 1;
|
| 433 |
|
|
|
| 434 |
|
|
set_mode = GET_MODE (SET_DEST (set));
|
| 435 |
|
|
switch (set_mode)
|
| 436 |
|
|
{
|
| 437 |
|
|
case CCSmode:
|
| 438 |
|
|
case CCSRmode:
|
| 439 |
|
|
case CCUmode:
|
| 440 |
|
|
case CCURmode:
|
| 441 |
|
|
case CCLmode:
|
| 442 |
|
|
case CCL1mode:
|
| 443 |
|
|
case CCL2mode:
|
| 444 |
|
|
case CCL3mode:
|
| 445 |
|
|
case CCT1mode:
|
| 446 |
|
|
case CCT2mode:
|
| 447 |
|
|
case CCT3mode:
|
| 448 |
|
|
if (req_mode != set_mode)
|
| 449 |
|
|
return 0;
|
| 450 |
|
|
break;
|
| 451 |
|
|
|
| 452 |
|
|
case CCZmode:
|
| 453 |
|
|
if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode
|
| 454 |
|
|
&& req_mode != CCSRmode && req_mode != CCURmode)
|
| 455 |
|
|
return 0;
|
| 456 |
|
|
break;
|
| 457 |
|
|
|
| 458 |
|
|
case CCAPmode:
|
| 459 |
|
|
case CCANmode:
|
| 460 |
|
|
if (req_mode != CCAmode)
|
| 461 |
|
|
return 0;
|
| 462 |
|
|
break;
|
| 463 |
|
|
|
| 464 |
|
|
default:
|
| 465 |
|
|
gcc_unreachable ();
|
| 466 |
|
|
}
|
| 467 |
|
|
|
| 468 |
|
|
return (GET_MODE (SET_SRC (set)) == set_mode);
|
| 469 |
|
|
}
|
| 470 |
|
|
|
| 471 |
|
|
/* Return true if every SET in INSN that sets the CC register
|
| 472 |
|
|
has source and destination with matching CC modes and that
|
| 473 |
|
|
CC mode is at least as constrained as REQ_MODE.
|
| 474 |
|
|
If REQ_MODE is VOIDmode, always return false. */
|
| 475 |
|
|
|
| 476 |
|
|
bool
|
| 477 |
|
|
s390_match_ccmode (rtx insn, enum machine_mode req_mode)
|
| 478 |
|
|
{
|
| 479 |
|
|
int i;
|
| 480 |
|
|
|
| 481 |
|
|
/* s390_tm_ccmode returns VOIDmode to indicate failure. */
|
| 482 |
|
|
if (req_mode == VOIDmode)
|
| 483 |
|
|
return false;
|
| 484 |
|
|
|
| 485 |
|
|
if (GET_CODE (PATTERN (insn)) == SET)
|
| 486 |
|
|
return s390_match_ccmode_set (PATTERN (insn), req_mode);
|
| 487 |
|
|
|
| 488 |
|
|
if (GET_CODE (PATTERN (insn)) == PARALLEL)
|
| 489 |
|
|
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
|
| 490 |
|
|
{
|
| 491 |
|
|
rtx set = XVECEXP (PATTERN (insn), 0, i);
|
| 492 |
|
|
if (GET_CODE (set) == SET)
|
| 493 |
|
|
if (!s390_match_ccmode_set (set, req_mode))
|
| 494 |
|
|
return false;
|
| 495 |
|
|
}
|
| 496 |
|
|
|
| 497 |
|
|
return true;
|
| 498 |
|
|
}
|
| 499 |
|
|
|
| 500 |
|
|
/* If a test-under-mask instruction can be used to implement
|
| 501 |
|
|
(compare (and ... OP1) OP2), return the CC mode required
|
| 502 |
|
|
to do that. Otherwise, return VOIDmode.
|
| 503 |
|
|
MIXED is true if the instruction can distinguish between
|
| 504 |
|
|
CC1 and CC2 for mixed selected bits (TMxx), it is false
|
| 505 |
|
|
if the instruction cannot (TM). */
|
| 506 |
|
|
|
| 507 |
|
|
enum machine_mode
|
| 508 |
|
|
s390_tm_ccmode (rtx op1, rtx op2, bool mixed)
|
| 509 |
|
|
{
|
| 510 |
|
|
int bit0, bit1;
|
| 511 |
|
|
|
| 512 |
|
|
/* ??? Fixme: should work on CONST_DOUBLE as well. */
|
| 513 |
|
|
if (GET_CODE (op1) != CONST_INT || GET_CODE (op2) != CONST_INT)
|
| 514 |
|
|
return VOIDmode;
|
| 515 |
|
|
|
| 516 |
|
|
/* Selected bits all zero: CC0.
|
| 517 |
|
|
e.g.: int a; if ((a & (16 + 128)) == 0) */
|
| 518 |
|
|
if (INTVAL (op2) == 0)
|
| 519 |
|
|
return CCTmode;
|
| 520 |
|
|
|
| 521 |
|
|
/* Selected bits all one: CC3.
|
| 522 |
|
|
e.g.: int a; if ((a & (16 + 128)) == 16 + 128) */
|
| 523 |
|
|
if (INTVAL (op2) == INTVAL (op1))
|
| 524 |
|
|
return CCT3mode;
|
| 525 |
|
|
|
| 526 |
|
|
/* Exactly two bits selected, mixed zeroes and ones: CC1 or CC2. e.g.:
|
| 527 |
|
|
int a;
|
| 528 |
|
|
if ((a & (16 + 128)) == 16) -> CCT1
|
| 529 |
|
|
if ((a & (16 + 128)) == 128) -> CCT2 */
|
| 530 |
|
|
if (mixed)
|
| 531 |
|
|
{
|
| 532 |
|
|
bit1 = exact_log2 (INTVAL (op2));
|
| 533 |
|
|
bit0 = exact_log2 (INTVAL (op1) ^ INTVAL (op2));
|
| 534 |
|
|
if (bit0 != -1 && bit1 != -1)
|
| 535 |
|
|
return bit0 > bit1 ? CCT1mode : CCT2mode;
|
| 536 |
|
|
}
|
| 537 |
|
|
|
| 538 |
|
|
return VOIDmode;
|
| 539 |
|
|
}
|
| 540 |
|
|
|
| 541 |
|
|
/* Given a comparison code OP (EQ, NE, etc.) and the operands
|
| 542 |
|
|
OP0 and OP1 of a COMPARE, return the mode to be used for the
|
| 543 |
|
|
comparison. */
|
| 544 |
|
|
|
| 545 |
|
|
enum machine_mode
|
| 546 |
|
|
s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
|
| 547 |
|
|
{
|
| 548 |
|
|
switch (code)
|
| 549 |
|
|
{
|
| 550 |
|
|
case EQ:
|
| 551 |
|
|
case NE:
|
| 552 |
|
|
if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS)
|
| 553 |
|
|
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
|
| 554 |
|
|
return CCAPmode;
|
| 555 |
|
|
if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
|
| 556 |
|
|
&& CONST_OK_FOR_K (INTVAL (XEXP (op0, 1))))
|
| 557 |
|
|
return CCAPmode;
|
| 558 |
|
|
if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
|
| 559 |
|
|
|| GET_CODE (op1) == NEG)
|
| 560 |
|
|
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
|
| 561 |
|
|
return CCLmode;
|
| 562 |
|
|
|
| 563 |
|
|
if (GET_CODE (op0) == AND)
|
| 564 |
|
|
{
|
| 565 |
|
|
/* Check whether we can potentially do it via TM. */
|
| 566 |
|
|
enum machine_mode ccmode;
|
| 567 |
|
|
ccmode = s390_tm_ccmode (XEXP (op0, 1), op1, 1);
|
| 568 |
|
|
if (ccmode != VOIDmode)
|
| 569 |
|
|
{
|
| 570 |
|
|
/* Relax CCTmode to CCZmode to allow fall-back to AND
|
| 571 |
|
|
if that turns out to be beneficial. */
|
| 572 |
|
|
return ccmode == CCTmode ? CCZmode : ccmode;
|
| 573 |
|
|
}
|
| 574 |
|
|
}
|
| 575 |
|
|
|
| 576 |
|
|
if (register_operand (op0, HImode)
|
| 577 |
|
|
&& GET_CODE (op1) == CONST_INT
|
| 578 |
|
|
&& (INTVAL (op1) == -1 || INTVAL (op1) == 65535))
|
| 579 |
|
|
return CCT3mode;
|
| 580 |
|
|
if (register_operand (op0, QImode)
|
| 581 |
|
|
&& GET_CODE (op1) == CONST_INT
|
| 582 |
|
|
&& (INTVAL (op1) == -1 || INTVAL (op1) == 255))
|
| 583 |
|
|
return CCT3mode;
|
| 584 |
|
|
|
| 585 |
|
|
return CCZmode;
|
| 586 |
|
|
|
| 587 |
|
|
case LE:
|
| 588 |
|
|
case LT:
|
| 589 |
|
|
case GE:
|
| 590 |
|
|
case GT:
|
| 591 |
|
|
/* The only overflow condition of NEG and ABS happens when
|
| 592 |
|
|
-INT_MAX is used as parameter, which stays negative. So
|
| 593 |
|
|
we have an overflow from a positive value to a negative.
|
| 594 |
|
|
Using CCAP mode the resulting cc can be used for comparisons. */
|
| 595 |
|
|
if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS)
|
| 596 |
|
|
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
|
| 597 |
|
|
return CCAPmode;
|
| 598 |
|
|
|
| 599 |
|
|
/* If constants are involved in an add instruction it is possible to use
|
| 600 |
|
|
the resulting cc for comparisons with zero. Knowing the sign of the
|
| 601 |
|
|
constant the overflow behavior gets predictable. e.g.:
|
| 602 |
|
|
int a, b; if ((b = a + c) > 0)
|
| 603 |
|
|
with c as a constant value: c < 0 -> CCAN and c >= 0 -> CCAP */
|
| 604 |
|
|
if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
|
| 605 |
|
|
&& CONST_OK_FOR_K (INTVAL (XEXP (op0, 1))))
|
| 606 |
|
|
{
|
| 607 |
|
|
if (INTVAL (XEXP((op0), 1)) < 0)
|
| 608 |
|
|
return CCANmode;
|
| 609 |
|
|
else
|
| 610 |
|
|
return CCAPmode;
|
| 611 |
|
|
}
|
| 612 |
|
|
/* Fall through. */
|
| 613 |
|
|
case UNORDERED:
|
| 614 |
|
|
case ORDERED:
|
| 615 |
|
|
case UNEQ:
|
| 616 |
|
|
case UNLE:
|
| 617 |
|
|
case UNLT:
|
| 618 |
|
|
case UNGE:
|
| 619 |
|
|
case UNGT:
|
| 620 |
|
|
case LTGT:
|
| 621 |
|
|
if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
|
| 622 |
|
|
&& GET_CODE (op1) != CONST_INT)
|
| 623 |
|
|
return CCSRmode;
|
| 624 |
|
|
return CCSmode;
|
| 625 |
|
|
|
| 626 |
|
|
case LTU:
|
| 627 |
|
|
case GEU:
|
| 628 |
|
|
if (GET_CODE (op0) == PLUS
|
| 629 |
|
|
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
|
| 630 |
|
|
return CCL1mode;
|
| 631 |
|
|
|
| 632 |
|
|
if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
|
| 633 |
|
|
&& GET_CODE (op1) != CONST_INT)
|
| 634 |
|
|
return CCURmode;
|
| 635 |
|
|
return CCUmode;
|
| 636 |
|
|
|
| 637 |
|
|
case LEU:
|
| 638 |
|
|
case GTU:
|
| 639 |
|
|
if (GET_CODE (op0) == MINUS
|
| 640 |
|
|
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
|
| 641 |
|
|
return CCL2mode;
|
| 642 |
|
|
|
| 643 |
|
|
if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
|
| 644 |
|
|
&& GET_CODE (op1) != CONST_INT)
|
| 645 |
|
|
return CCURmode;
|
| 646 |
|
|
return CCUmode;
|
| 647 |
|
|
|
| 648 |
|
|
default:
|
| 649 |
|
|
gcc_unreachable ();
|
| 650 |
|
|
}
|
| 651 |
|
|
}
|
| 652 |
|
|
|
| 653 |
|
|
/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
|
| 654 |
|
|
that we can implement more efficiently. */
|
| 655 |
|
|
|
| 656 |
|
|
void
|
| 657 |
|
|
s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
|
| 658 |
|
|
{
|
| 659 |
|
|
/* Convert ZERO_EXTRACT back to AND to enable TM patterns. */
|
| 660 |
|
|
if ((*code == EQ || *code == NE)
|
| 661 |
|
|
&& *op1 == const0_rtx
|
| 662 |
|
|
&& GET_CODE (*op0) == ZERO_EXTRACT
|
| 663 |
|
|
&& GET_CODE (XEXP (*op0, 1)) == CONST_INT
|
| 664 |
|
|
&& GET_CODE (XEXP (*op0, 2)) == CONST_INT
|
| 665 |
|
|
&& SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))
|
| 666 |
|
|
{
|
| 667 |
|
|
rtx inner = XEXP (*op0, 0);
|
| 668 |
|
|
HOST_WIDE_INT modesize = GET_MODE_BITSIZE (GET_MODE (inner));
|
| 669 |
|
|
HOST_WIDE_INT len = INTVAL (XEXP (*op0, 1));
|
| 670 |
|
|
HOST_WIDE_INT pos = INTVAL (XEXP (*op0, 2));
|
| 671 |
|
|
|
| 672 |
|
|
if (len > 0 && len < modesize
|
| 673 |
|
|
&& pos >= 0 && pos + len <= modesize
|
| 674 |
|
|
&& modesize <= HOST_BITS_PER_WIDE_INT)
|
| 675 |
|
|
{
|
| 676 |
|
|
unsigned HOST_WIDE_INT block;
|
| 677 |
|
|
block = ((unsigned HOST_WIDE_INT) 1 << len) - 1;
|
| 678 |
|
|
block <<= modesize - pos - len;
|
| 679 |
|
|
|
| 680 |
|
|
*op0 = gen_rtx_AND (GET_MODE (inner), inner,
|
| 681 |
|
|
gen_int_mode (block, GET_MODE (inner)));
|
| 682 |
|
|
}
|
| 683 |
|
|
}
|
| 684 |
|
|
|
| 685 |
|
|
/* Narrow AND of memory against immediate to enable TM. */
|
| 686 |
|
|
if ((*code == EQ || *code == NE)
|
| 687 |
|
|
&& *op1 == const0_rtx
|
| 688 |
|
|
&& GET_CODE (*op0) == AND
|
| 689 |
|
|
&& GET_CODE (XEXP (*op0, 1)) == CONST_INT
|
| 690 |
|
|
&& SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))
|
| 691 |
|
|
{
|
| 692 |
|
|
rtx inner = XEXP (*op0, 0);
|
| 693 |
|
|
rtx mask = XEXP (*op0, 1);
|
| 694 |
|
|
|
| 695 |
|
|
/* Ignore paradoxical SUBREGs if all extra bits are masked out. */
|
| 696 |
|
|
if (GET_CODE (inner) == SUBREG
|
| 697 |
|
|
&& SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (inner)))
|
| 698 |
|
|
&& (GET_MODE_SIZE (GET_MODE (inner))
|
| 699 |
|
|
>= GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))
|
| 700 |
|
|
&& ((INTVAL (mask)
|
| 701 |
|
|
& GET_MODE_MASK (GET_MODE (inner))
|
| 702 |
|
|
& ~GET_MODE_MASK (GET_MODE (SUBREG_REG (inner))))
|
| 703 |
|
|
== 0))
|
| 704 |
|
|
inner = SUBREG_REG (inner);
|
| 705 |
|
|
|
| 706 |
|
|
/* Do not change volatile MEMs. */
|
| 707 |
|
|
if (MEM_P (inner) && !MEM_VOLATILE_P (inner))
|
| 708 |
|
|
{
|
| 709 |
|
|
int part = s390_single_part (XEXP (*op0, 1),
|
| 710 |
|
|
GET_MODE (inner), QImode, 0);
|
| 711 |
|
|
if (part >= 0)
|
| 712 |
|
|
{
|
| 713 |
|
|
mask = gen_int_mode (s390_extract_part (mask, QImode, 0), QImode);
|
| 714 |
|
|
inner = adjust_address_nv (inner, QImode, part);
|
| 715 |
|
|
*op0 = gen_rtx_AND (QImode, inner, mask);
|
| 716 |
|
|
}
|
| 717 |
|
|
}
|
| 718 |
|
|
}
|
| 719 |
|
|
|
| 720 |
|
|
/* Narrow comparisons against 0xffff to HImode if possible. */
|
| 721 |
|
|
if ((*code == EQ || *code == NE)
|
| 722 |
|
|
&& GET_CODE (*op1) == CONST_INT
|
| 723 |
|
|
&& INTVAL (*op1) == 0xffff
|
| 724 |
|
|
&& SCALAR_INT_MODE_P (GET_MODE (*op0))
|
| 725 |
|
|
&& (nonzero_bits (*op0, GET_MODE (*op0))
|
| 726 |
|
|
& ~(unsigned HOST_WIDE_INT) 0xffff) == 0)
|
| 727 |
|
|
{
|
| 728 |
|
|
*op0 = gen_lowpart (HImode, *op0);
|
| 729 |
|
|
*op1 = constm1_rtx;
|
| 730 |
|
|
}
|
| 731 |
|
|
|
| 732 |
|
|
/* Remove redundant UNSPEC_CCU_TO_INT conversions if possible. */
|
| 733 |
|
|
if (GET_CODE (*op0) == UNSPEC
|
| 734 |
|
|
&& XINT (*op0, 1) == UNSPEC_CCU_TO_INT
|
| 735 |
|
|
&& XVECLEN (*op0, 0) == 1
|
| 736 |
|
|
&& GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode
|
| 737 |
|
|
&& GET_CODE (XVECEXP (*op0, 0, 0)) == REG
|
| 738 |
|
|
&& REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM
|
| 739 |
|
|
&& *op1 == const0_rtx)
|
| 740 |
|
|
{
|
| 741 |
|
|
enum rtx_code new_code = UNKNOWN;
|
| 742 |
|
|
switch (*code)
|
| 743 |
|
|
{
|
| 744 |
|
|
case EQ: new_code = EQ; break;
|
| 745 |
|
|
case NE: new_code = NE; break;
|
| 746 |
|
|
case LT: new_code = GTU; break;
|
| 747 |
|
|
case GT: new_code = LTU; break;
|
| 748 |
|
|
case LE: new_code = GEU; break;
|
| 749 |
|
|
case GE: new_code = LEU; break;
|
| 750 |
|
|
default: break;
|
| 751 |
|
|
}
|
| 752 |
|
|
|
| 753 |
|
|
if (new_code != UNKNOWN)
|
| 754 |
|
|
{
|
| 755 |
|
|
*op0 = XVECEXP (*op0, 0, 0);
|
| 756 |
|
|
*code = new_code;
|
| 757 |
|
|
}
|
| 758 |
|
|
}
|
| 759 |
|
|
|
| 760 |
|
|
/* Remove redundant UNSPEC_CCZ_TO_INT conversions if possible. */
|
| 761 |
|
|
if (GET_CODE (*op0) == UNSPEC
|
| 762 |
|
|
&& XINT (*op0, 1) == UNSPEC_CCZ_TO_INT
|
| 763 |
|
|
&& XVECLEN (*op0, 0) == 1
|
| 764 |
|
|
&& GET_MODE (XVECEXP (*op0, 0, 0)) == CCZmode
|
| 765 |
|
|
&& GET_CODE (XVECEXP (*op0, 0, 0)) == REG
|
| 766 |
|
|
&& REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM
|
| 767 |
|
|
&& *op1 == const0_rtx)
|
| 768 |
|
|
{
|
| 769 |
|
|
enum rtx_code new_code = UNKNOWN;
|
| 770 |
|
|
switch (*code)
|
| 771 |
|
|
{
|
| 772 |
|
|
case EQ: new_code = EQ; break;
|
| 773 |
|
|
case NE: new_code = NE; break;
|
| 774 |
|
|
default: break;
|
| 775 |
|
|
}
|
| 776 |
|
|
|
| 777 |
|
|
if (new_code != UNKNOWN)
|
| 778 |
|
|
{
|
| 779 |
|
|
*op0 = XVECEXP (*op0, 0, 0);
|
| 780 |
|
|
*code = new_code;
|
| 781 |
|
|
}
|
| 782 |
|
|
}
|
| 783 |
|
|
|
| 784 |
|
|
/* Simplify cascaded EQ, NE with const0_rtx. */
|
| 785 |
|
|
if ((*code == NE || *code == EQ)
|
| 786 |
|
|
&& (GET_CODE (*op0) == EQ || GET_CODE (*op0) == NE)
|
| 787 |
|
|
&& GET_MODE (*op0) == SImode
|
| 788 |
|
|
&& GET_MODE (XEXP (*op0, 0)) == CCZ1mode
|
| 789 |
|
|
&& REG_P (XEXP (*op0, 0))
|
| 790 |
|
|
&& XEXP (*op0, 1) == const0_rtx
|
| 791 |
|
|
&& *op1 == const0_rtx)
|
| 792 |
|
|
{
|
| 793 |
|
|
if ((*code == EQ && GET_CODE (*op0) == NE)
|
| 794 |
|
|
|| (*code == NE && GET_CODE (*op0) == EQ))
|
| 795 |
|
|
*code = EQ;
|
| 796 |
|
|
else
|
| 797 |
|
|
*code = NE;
|
| 798 |
|
|
*op0 = XEXP (*op0, 0);
|
| 799 |
|
|
}
|
| 800 |
|
|
|
| 801 |
|
|
/* Prefer register over memory as first operand. */
|
| 802 |
|
|
if (MEM_P (*op0) && REG_P (*op1))
|
| 803 |
|
|
{
|
| 804 |
|
|
rtx tem = *op0; *op0 = *op1; *op1 = tem;
|
| 805 |
|
|
*code = swap_condition (*code);
|
| 806 |
|
|
}
|
| 807 |
|
|
}
|
| 808 |
|
|
|
| 809 |
|
|
/* Emit a compare instruction suitable to implement the comparison
|
| 810 |
|
|
OP0 CODE OP1. Return the correct condition RTL to be placed in
|
| 811 |
|
|
the IF_THEN_ELSE of the conditional branch testing the result. */
|
| 812 |
|
|
|
| 813 |
|
|
rtx
|
| 814 |
|
|
s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
|
| 815 |
|
|
{
|
| 816 |
|
|
enum machine_mode mode = s390_select_ccmode (code, op0, op1);
|
| 817 |
|
|
rtx cc;
|
| 818 |
|
|
|
| 819 |
|
|
/* Do not output a redundant compare instruction if a compare_and_swap
|
| 820 |
|
|
pattern already computed the result and the machine modes are compatible. */
|
| 821 |
|
|
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
|
| 822 |
|
|
{
|
| 823 |
|
|
gcc_assert (s390_cc_modes_compatible (GET_MODE (op0), mode)
|
| 824 |
|
|
== GET_MODE (op0));
|
| 825 |
|
|
cc = op0;
|
| 826 |
|
|
}
|
| 827 |
|
|
else
|
| 828 |
|
|
{
|
| 829 |
|
|
cc = gen_rtx_REG (mode, CC_REGNUM);
|
| 830 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1)));
|
| 831 |
|
|
}
|
| 832 |
|
|
|
| 833 |
|
|
return gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);
|
| 834 |
|
|
}
|
| 835 |
|
|
|
| 836 |
|
|
/* Emit a SImode compare and swap instruction setting MEM to NEW_RTX if OLD
|
| 837 |
|
|
matches CMP.
|
| 838 |
|
|
Return the correct condition RTL to be placed in the IF_THEN_ELSE of the
|
| 839 |
|
|
conditional branch testing the result. */
|
| 840 |
|
|
|
| 841 |
|
|
static rtx
|
| 842 |
|
|
s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem, rtx cmp, rtx new_rtx)
|
| 843 |
|
|
{
|
| 844 |
|
|
emit_insn (gen_sync_compare_and_swapsi (old, mem, cmp, new_rtx));
|
| 845 |
|
|
return s390_emit_compare (code, gen_rtx_REG (CCZ1mode, CC_REGNUM), const0_rtx);
|
| 846 |
|
|
}
|
| 847 |
|
|
|
| 848 |
|
|
/* Emit a jump instruction to TARGET. If COND is NULL_RTX, emit an
|
| 849 |
|
|
unconditional jump, else a conditional jump under condition COND. */
|
| 850 |
|
|
|
| 851 |
|
|
void
|
| 852 |
|
|
s390_emit_jump (rtx target, rtx cond)
|
| 853 |
|
|
{
|
| 854 |
|
|
rtx insn;
|
| 855 |
|
|
|
| 856 |
|
|
target = gen_rtx_LABEL_REF (VOIDmode, target);
|
| 857 |
|
|
if (cond)
|
| 858 |
|
|
target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx);
|
| 859 |
|
|
|
| 860 |
|
|
insn = gen_rtx_SET (VOIDmode, pc_rtx, target);
|
| 861 |
|
|
emit_jump_insn (insn);
|
| 862 |
|
|
}
|
| 863 |
|
|
|
| 864 |
|
|
/* Return branch condition mask to implement a branch
|
| 865 |
|
|
specified by CODE. Return -1 for invalid comparisons. */
|
| 866 |
|
|
|
| 867 |
|
|
int
|
| 868 |
|
|
s390_branch_condition_mask (rtx code)
|
| 869 |
|
|
{
|
| 870 |
|
|
const int CC0 = 1 << 3;
|
| 871 |
|
|
const int CC1 = 1 << 2;
|
| 872 |
|
|
const int CC2 = 1 << 1;
|
| 873 |
|
|
const int CC3 = 1 << 0;
|
| 874 |
|
|
|
| 875 |
|
|
gcc_assert (GET_CODE (XEXP (code, 0)) == REG);
|
| 876 |
|
|
gcc_assert (REGNO (XEXP (code, 0)) == CC_REGNUM);
|
| 877 |
|
|
gcc_assert (XEXP (code, 1) == const0_rtx);
|
| 878 |
|
|
|
| 879 |
|
|
switch (GET_MODE (XEXP (code, 0)))
|
| 880 |
|
|
{
|
| 881 |
|
|
case CCZmode:
|
| 882 |
|
|
case CCZ1mode:
|
| 883 |
|
|
switch (GET_CODE (code))
|
| 884 |
|
|
{
|
| 885 |
|
|
case EQ: return CC0;
|
| 886 |
|
|
case NE: return CC1 | CC2 | CC3;
|
| 887 |
|
|
default: return -1;
|
| 888 |
|
|
}
|
| 889 |
|
|
break;
|
| 890 |
|
|
|
| 891 |
|
|
case CCT1mode:
|
| 892 |
|
|
switch (GET_CODE (code))
|
| 893 |
|
|
{
|
| 894 |
|
|
case EQ: return CC1;
|
| 895 |
|
|
case NE: return CC0 | CC2 | CC3;
|
| 896 |
|
|
default: return -1;
|
| 897 |
|
|
}
|
| 898 |
|
|
break;
|
| 899 |
|
|
|
| 900 |
|
|
case CCT2mode:
|
| 901 |
|
|
switch (GET_CODE (code))
|
| 902 |
|
|
{
|
| 903 |
|
|
case EQ: return CC2;
|
| 904 |
|
|
case NE: return CC0 | CC1 | CC3;
|
| 905 |
|
|
default: return -1;
|
| 906 |
|
|
}
|
| 907 |
|
|
break;
|
| 908 |
|
|
|
| 909 |
|
|
case CCT3mode:
|
| 910 |
|
|
switch (GET_CODE (code))
|
| 911 |
|
|
{
|
| 912 |
|
|
case EQ: return CC3;
|
| 913 |
|
|
case NE: return CC0 | CC1 | CC2;
|
| 914 |
|
|
default: return -1;
|
| 915 |
|
|
}
|
| 916 |
|
|
break;
|
| 917 |
|
|
|
| 918 |
|
|
case CCLmode:
|
| 919 |
|
|
switch (GET_CODE (code))
|
| 920 |
|
|
{
|
| 921 |
|
|
case EQ: return CC0 | CC2;
|
| 922 |
|
|
case NE: return CC1 | CC3;
|
| 923 |
|
|
default: return -1;
|
| 924 |
|
|
}
|
| 925 |
|
|
break;
|
| 926 |
|
|
|
| 927 |
|
|
case CCL1mode:
|
| 928 |
|
|
switch (GET_CODE (code))
|
| 929 |
|
|
{
|
| 930 |
|
|
case LTU: return CC2 | CC3; /* carry */
|
| 931 |
|
|
case GEU: return CC0 | CC1; /* no carry */
|
| 932 |
|
|
default: return -1;
|
| 933 |
|
|
}
|
| 934 |
|
|
break;
|
| 935 |
|
|
|
| 936 |
|
|
case CCL2mode:
|
| 937 |
|
|
switch (GET_CODE (code))
|
| 938 |
|
|
{
|
| 939 |
|
|
case GTU: return CC0 | CC1; /* borrow */
|
| 940 |
|
|
case LEU: return CC2 | CC3; /* no borrow */
|
| 941 |
|
|
default: return -1;
|
| 942 |
|
|
}
|
| 943 |
|
|
break;
|
| 944 |
|
|
|
| 945 |
|
|
case CCL3mode:
|
| 946 |
|
|
switch (GET_CODE (code))
|
| 947 |
|
|
{
|
| 948 |
|
|
case EQ: return CC0 | CC2;
|
| 949 |
|
|
case NE: return CC1 | CC3;
|
| 950 |
|
|
case LTU: return CC1;
|
| 951 |
|
|
case GTU: return CC3;
|
| 952 |
|
|
case LEU: return CC1 | CC2;
|
| 953 |
|
|
case GEU: return CC2 | CC3;
|
| 954 |
|
|
default: return -1;
|
| 955 |
|
|
}
|
| 956 |
|
|
|
| 957 |
|
|
case CCUmode:
|
| 958 |
|
|
switch (GET_CODE (code))
|
| 959 |
|
|
{
|
| 960 |
|
|
case EQ: return CC0;
|
| 961 |
|
|
case NE: return CC1 | CC2 | CC3;
|
| 962 |
|
|
case LTU: return CC1;
|
| 963 |
|
|
case GTU: return CC2;
|
| 964 |
|
|
case LEU: return CC0 | CC1;
|
| 965 |
|
|
case GEU: return CC0 | CC2;
|
| 966 |
|
|
default: return -1;
|
| 967 |
|
|
}
|
| 968 |
|
|
break;
|
| 969 |
|
|
|
| 970 |
|
|
case CCURmode:
|
| 971 |
|
|
switch (GET_CODE (code))
|
| 972 |
|
|
{
|
| 973 |
|
|
case EQ: return CC0;
|
| 974 |
|
|
case NE: return CC2 | CC1 | CC3;
|
| 975 |
|
|
case LTU: return CC2;
|
| 976 |
|
|
case GTU: return CC1;
|
| 977 |
|
|
case LEU: return CC0 | CC2;
|
| 978 |
|
|
case GEU: return CC0 | CC1;
|
| 979 |
|
|
default: return -1;
|
| 980 |
|
|
}
|
| 981 |
|
|
break;
|
| 982 |
|
|
|
| 983 |
|
|
case CCAPmode:
|
| 984 |
|
|
switch (GET_CODE (code))
|
| 985 |
|
|
{
|
| 986 |
|
|
case EQ: return CC0;
|
| 987 |
|
|
case NE: return CC1 | CC2 | CC3;
|
| 988 |
|
|
case LT: return CC1 | CC3;
|
| 989 |
|
|
case GT: return CC2;
|
| 990 |
|
|
case LE: return CC0 | CC1 | CC3;
|
| 991 |
|
|
case GE: return CC0 | CC2;
|
| 992 |
|
|
default: return -1;
|
| 993 |
|
|
}
|
| 994 |
|
|
break;
|
| 995 |
|
|
|
| 996 |
|
|
case CCANmode:
|
| 997 |
|
|
switch (GET_CODE (code))
|
| 998 |
|
|
{
|
| 999 |
|
|
case EQ: return CC0;
|
| 1000 |
|
|
case NE: return CC1 | CC2 | CC3;
|
| 1001 |
|
|
case LT: return CC1;
|
| 1002 |
|
|
case GT: return CC2 | CC3;
|
| 1003 |
|
|
case LE: return CC0 | CC1;
|
| 1004 |
|
|
case GE: return CC0 | CC2 | CC3;
|
| 1005 |
|
|
default: return -1;
|
| 1006 |
|
|
}
|
| 1007 |
|
|
break;
|
| 1008 |
|
|
|
| 1009 |
|
|
case CCSmode:
|
| 1010 |
|
|
switch (GET_CODE (code))
|
| 1011 |
|
|
{
|
| 1012 |
|
|
case EQ: return CC0;
|
| 1013 |
|
|
case NE: return CC1 | CC2 | CC3;
|
| 1014 |
|
|
case LT: return CC1;
|
| 1015 |
|
|
case GT: return CC2;
|
| 1016 |
|
|
case LE: return CC0 | CC1;
|
| 1017 |
|
|
case GE: return CC0 | CC2;
|
| 1018 |
|
|
case UNORDERED: return CC3;
|
| 1019 |
|
|
case ORDERED: return CC0 | CC1 | CC2;
|
| 1020 |
|
|
case UNEQ: return CC0 | CC3;
|
| 1021 |
|
|
case UNLT: return CC1 | CC3;
|
| 1022 |
|
|
case UNGT: return CC2 | CC3;
|
| 1023 |
|
|
case UNLE: return CC0 | CC1 | CC3;
|
| 1024 |
|
|
case UNGE: return CC0 | CC2 | CC3;
|
| 1025 |
|
|
case LTGT: return CC1 | CC2;
|
| 1026 |
|
|
default: return -1;
|
| 1027 |
|
|
}
|
| 1028 |
|
|
break;
|
| 1029 |
|
|
|
| 1030 |
|
|
case CCSRmode:
|
| 1031 |
|
|
switch (GET_CODE (code))
|
| 1032 |
|
|
{
|
| 1033 |
|
|
case EQ: return CC0;
|
| 1034 |
|
|
case NE: return CC2 | CC1 | CC3;
|
| 1035 |
|
|
case LT: return CC2;
|
| 1036 |
|
|
case GT: return CC1;
|
| 1037 |
|
|
case LE: return CC0 | CC2;
|
| 1038 |
|
|
case GE: return CC0 | CC1;
|
| 1039 |
|
|
case UNORDERED: return CC3;
|
| 1040 |
|
|
case ORDERED: return CC0 | CC2 | CC1;
|
| 1041 |
|
|
case UNEQ: return CC0 | CC3;
|
| 1042 |
|
|
case UNLT: return CC2 | CC3;
|
| 1043 |
|
|
case UNGT: return CC1 | CC3;
|
| 1044 |
|
|
case UNLE: return CC0 | CC2 | CC3;
|
| 1045 |
|
|
case UNGE: return CC0 | CC1 | CC3;
|
| 1046 |
|
|
case LTGT: return CC2 | CC1;
|
| 1047 |
|
|
default: return -1;
|
| 1048 |
|
|
}
|
| 1049 |
|
|
break;
|
| 1050 |
|
|
|
| 1051 |
|
|
default:
|
| 1052 |
|
|
return -1;
|
| 1053 |
|
|
}
|
| 1054 |
|
|
}
|
| 1055 |
|
|
|
| 1056 |
|
|
|
| 1057 |
|
|
/* Return branch condition mask to implement a compare and branch
|
| 1058 |
|
|
specified by CODE. Return -1 for invalid comparisons. */
|
| 1059 |
|
|
|
| 1060 |
|
|
int
|
| 1061 |
|
|
s390_compare_and_branch_condition_mask (rtx code)
|
| 1062 |
|
|
{
|
| 1063 |
|
|
const int CC0 = 1 << 3;
|
| 1064 |
|
|
const int CC1 = 1 << 2;
|
| 1065 |
|
|
const int CC2 = 1 << 1;
|
| 1066 |
|
|
|
| 1067 |
|
|
switch (GET_CODE (code))
|
| 1068 |
|
|
{
|
| 1069 |
|
|
case EQ:
|
| 1070 |
|
|
return CC0;
|
| 1071 |
|
|
case NE:
|
| 1072 |
|
|
return CC1 | CC2;
|
| 1073 |
|
|
case LT:
|
| 1074 |
|
|
case LTU:
|
| 1075 |
|
|
return CC1;
|
| 1076 |
|
|
case GT:
|
| 1077 |
|
|
case GTU:
|
| 1078 |
|
|
return CC2;
|
| 1079 |
|
|
case LE:
|
| 1080 |
|
|
case LEU:
|
| 1081 |
|
|
return CC0 | CC1;
|
| 1082 |
|
|
case GE:
|
| 1083 |
|
|
case GEU:
|
| 1084 |
|
|
return CC0 | CC2;
|
| 1085 |
|
|
default:
|
| 1086 |
|
|
gcc_unreachable ();
|
| 1087 |
|
|
}
|
| 1088 |
|
|
return -1;
|
| 1089 |
|
|
}
|
| 1090 |
|
|
|
| 1091 |
|
|
/* If INV is false, return assembler mnemonic string to implement
|
| 1092 |
|
|
a branch specified by CODE. If INV is true, return mnemonic
|
| 1093 |
|
|
for the corresponding inverted branch. */
|
| 1094 |
|
|
|
| 1095 |
|
|
static const char *
|
| 1096 |
|
|
s390_branch_condition_mnemonic (rtx code, int inv)
|
| 1097 |
|
|
{
|
| 1098 |
|
|
int mask;
|
| 1099 |
|
|
|
| 1100 |
|
|
static const char *const mnemonic[16] =
|
| 1101 |
|
|
{
|
| 1102 |
|
|
NULL, "o", "h", "nle",
|
| 1103 |
|
|
"l", "nhe", "lh", "ne",
|
| 1104 |
|
|
"e", "nlh", "he", "nl",
|
| 1105 |
|
|
"le", "nh", "no", NULL
|
| 1106 |
|
|
};
|
| 1107 |
|
|
|
| 1108 |
|
|
if (GET_CODE (XEXP (code, 0)) == REG
|
| 1109 |
|
|
&& REGNO (XEXP (code, 0)) == CC_REGNUM
|
| 1110 |
|
|
&& XEXP (code, 1) == const0_rtx)
|
| 1111 |
|
|
mask = s390_branch_condition_mask (code);
|
| 1112 |
|
|
else
|
| 1113 |
|
|
mask = s390_compare_and_branch_condition_mask (code);
|
| 1114 |
|
|
|
| 1115 |
|
|
gcc_assert (mask >= 0);
|
| 1116 |
|
|
|
| 1117 |
|
|
if (inv)
|
| 1118 |
|
|
mask ^= 15;
|
| 1119 |
|
|
|
| 1120 |
|
|
gcc_assert (mask >= 1 && mask <= 14);
|
| 1121 |
|
|
|
| 1122 |
|
|
return mnemonic[mask];
|
| 1123 |
|
|
}
|
| 1124 |
|
|
|
| 1125 |
|
|
/* Return the part of op which has a value different from def.
|
| 1126 |
|
|
The size of the part is determined by mode.
|
| 1127 |
|
|
Use this function only if you already know that op really
|
| 1128 |
|
|
contains such a part. */
|
| 1129 |
|
|
|
| 1130 |
|
|
unsigned HOST_WIDE_INT
|
| 1131 |
|
|
s390_extract_part (rtx op, enum machine_mode mode, int def)
|
| 1132 |
|
|
{
|
| 1133 |
|
|
unsigned HOST_WIDE_INT value = 0;
|
| 1134 |
|
|
int max_parts = HOST_BITS_PER_WIDE_INT / GET_MODE_BITSIZE (mode);
|
| 1135 |
|
|
int part_bits = GET_MODE_BITSIZE (mode);
|
| 1136 |
|
|
unsigned HOST_WIDE_INT part_mask
|
| 1137 |
|
|
= ((unsigned HOST_WIDE_INT)1 << part_bits) - 1;
|
| 1138 |
|
|
int i;
|
| 1139 |
|
|
|
| 1140 |
|
|
for (i = 0; i < max_parts; i++)
|
| 1141 |
|
|
{
|
| 1142 |
|
|
if (i == 0)
|
| 1143 |
|
|
value = (unsigned HOST_WIDE_INT) INTVAL (op);
|
| 1144 |
|
|
else
|
| 1145 |
|
|
value >>= part_bits;
|
| 1146 |
|
|
|
| 1147 |
|
|
if ((value & part_mask) != (def & part_mask))
|
| 1148 |
|
|
return value & part_mask;
|
| 1149 |
|
|
}
|
| 1150 |
|
|
|
| 1151 |
|
|
gcc_unreachable ();
|
| 1152 |
|
|
}
|
| 1153 |
|
|
|
| 1154 |
|
|
/* If OP is an integer constant of mode MODE with exactly one
|
| 1155 |
|
|
part of mode PART_MODE unequal to DEF, return the number of that
|
| 1156 |
|
|
part. Otherwise, return -1. */
|
| 1157 |
|
|
|
| 1158 |
|
|
int
|
| 1159 |
|
|
s390_single_part (rtx op,
|
| 1160 |
|
|
enum machine_mode mode,
|
| 1161 |
|
|
enum machine_mode part_mode,
|
| 1162 |
|
|
int def)
|
| 1163 |
|
|
{
|
| 1164 |
|
|
unsigned HOST_WIDE_INT value = 0;
|
| 1165 |
|
|
int n_parts = GET_MODE_SIZE (mode) / GET_MODE_SIZE (part_mode);
|
| 1166 |
|
|
unsigned HOST_WIDE_INT part_mask
|
| 1167 |
|
|
= ((unsigned HOST_WIDE_INT)1 << GET_MODE_BITSIZE (part_mode)) - 1;
|
| 1168 |
|
|
int i, part = -1;
|
| 1169 |
|
|
|
| 1170 |
|
|
if (GET_CODE (op) != CONST_INT)
|
| 1171 |
|
|
return -1;
|
| 1172 |
|
|
|
| 1173 |
|
|
for (i = 0; i < n_parts; i++)
|
| 1174 |
|
|
{
|
| 1175 |
|
|
if (i == 0)
|
| 1176 |
|
|
value = (unsigned HOST_WIDE_INT) INTVAL (op);
|
| 1177 |
|
|
else
|
| 1178 |
|
|
value >>= GET_MODE_BITSIZE (part_mode);
|
| 1179 |
|
|
|
| 1180 |
|
|
if ((value & part_mask) != (def & part_mask))
|
| 1181 |
|
|
{
|
| 1182 |
|
|
if (part != -1)
|
| 1183 |
|
|
return -1;
|
| 1184 |
|
|
else
|
| 1185 |
|
|
part = i;
|
| 1186 |
|
|
}
|
| 1187 |
|
|
}
|
| 1188 |
|
|
return part == -1 ? -1 : n_parts - 1 - part;
|
| 1189 |
|
|
}
|
| 1190 |
|
|
|
| 1191 |
|
|
/* Return true if IN contains a contiguous bitfield in the lower SIZE
|
| 1192 |
|
|
bits and no other bits are set in IN. POS and LENGTH can be used
|
| 1193 |
|
|
to obtain the start position and the length of the bitfield.
|
| 1194 |
|
|
|
| 1195 |
|
|
POS gives the position of the first bit of the bitfield counting
|
| 1196 |
|
|
from the lowest order bit starting with zero. In order to use this
|
| 1197 |
|
|
value for S/390 instructions this has to be converted to "bits big
|
| 1198 |
|
|
endian" style. */
|
| 1199 |
|
|
|
| 1200 |
|
|
bool
|
| 1201 |
|
|
s390_contiguous_bitmask_p (unsigned HOST_WIDE_INT in, int size,
|
| 1202 |
|
|
int *pos, int *length)
|
| 1203 |
|
|
{
|
| 1204 |
|
|
int tmp_pos = 0;
|
| 1205 |
|
|
int tmp_length = 0;
|
| 1206 |
|
|
int i;
|
| 1207 |
|
|
unsigned HOST_WIDE_INT mask = 1ULL;
|
| 1208 |
|
|
bool contiguous = false;
|
| 1209 |
|
|
|
| 1210 |
|
|
for (i = 0; i < size; mask <<= 1, i++)
|
| 1211 |
|
|
{
|
| 1212 |
|
|
if (contiguous)
|
| 1213 |
|
|
{
|
| 1214 |
|
|
if (mask & in)
|
| 1215 |
|
|
tmp_length++;
|
| 1216 |
|
|
else
|
| 1217 |
|
|
break;
|
| 1218 |
|
|
}
|
| 1219 |
|
|
else
|
| 1220 |
|
|
{
|
| 1221 |
|
|
if (mask & in)
|
| 1222 |
|
|
{
|
| 1223 |
|
|
contiguous = true;
|
| 1224 |
|
|
tmp_length++;
|
| 1225 |
|
|
}
|
| 1226 |
|
|
else
|
| 1227 |
|
|
tmp_pos++;
|
| 1228 |
|
|
}
|
| 1229 |
|
|
}
|
| 1230 |
|
|
|
| 1231 |
|
|
if (!tmp_length)
|
| 1232 |
|
|
return false;
|
| 1233 |
|
|
|
| 1234 |
|
|
/* Calculate a mask for all bits beyond the contiguous bits. */
|
| 1235 |
|
|
mask = (-1LL & ~(((1ULL << (tmp_length + tmp_pos - 1)) << 1) - 1));
|
| 1236 |
|
|
|
| 1237 |
|
|
if (mask & in)
|
| 1238 |
|
|
return false;
|
| 1239 |
|
|
|
| 1240 |
|
|
if (tmp_length + tmp_pos - 1 > size)
|
| 1241 |
|
|
return false;
|
| 1242 |
|
|
|
| 1243 |
|
|
if (length)
|
| 1244 |
|
|
*length = tmp_length;
|
| 1245 |
|
|
|
| 1246 |
|
|
if (pos)
|
| 1247 |
|
|
*pos = tmp_pos;
|
| 1248 |
|
|
|
| 1249 |
|
|
return true;
|
| 1250 |
|
|
}
|
| 1251 |
|
|
|
| 1252 |
|
|
/* Check whether we can (and want to) split a double-word
|
| 1253 |
|
|
move in mode MODE from SRC to DST into two single-word
|
| 1254 |
|
|
moves, moving the subword FIRST_SUBWORD first. */
|
| 1255 |
|
|
|
| 1256 |
|
|
bool
|
| 1257 |
|
|
s390_split_ok_p (rtx dst, rtx src, enum machine_mode mode, int first_subword)
|
| 1258 |
|
|
{
|
| 1259 |
|
|
/* Floating point registers cannot be split. */
|
| 1260 |
|
|
if (FP_REG_P (src) || FP_REG_P (dst))
|
| 1261 |
|
|
return false;
|
| 1262 |
|
|
|
| 1263 |
|
|
/* We don't need to split if operands are directly accessible. */
|
| 1264 |
|
|
if (s_operand (src, mode) || s_operand (dst, mode))
|
| 1265 |
|
|
return false;
|
| 1266 |
|
|
|
| 1267 |
|
|
/* Non-offsettable memory references cannot be split. */
|
| 1268 |
|
|
if ((GET_CODE (src) == MEM && !offsettable_memref_p (src))
|
| 1269 |
|
|
|| (GET_CODE (dst) == MEM && !offsettable_memref_p (dst)))
|
| 1270 |
|
|
return false;
|
| 1271 |
|
|
|
| 1272 |
|
|
/* Moving the first subword must not clobber a register
|
| 1273 |
|
|
needed to move the second subword. */
|
| 1274 |
|
|
if (register_operand (dst, mode))
|
| 1275 |
|
|
{
|
| 1276 |
|
|
rtx subreg = operand_subword (dst, first_subword, 0, mode);
|
| 1277 |
|
|
if (reg_overlap_mentioned_p (subreg, src))
|
| 1278 |
|
|
return false;
|
| 1279 |
|
|
}
|
| 1280 |
|
|
|
| 1281 |
|
|
return true;
|
| 1282 |
|
|
}
|
| 1283 |
|
|
|
| 1284 |
|
|
/* Return true if it can be proven that [MEM1, MEM1 + SIZE]
|
| 1285 |
|
|
and [MEM2, MEM2 + SIZE] do overlap and false
|
| 1286 |
|
|
otherwise. */
|
| 1287 |
|
|
|
| 1288 |
|
|
bool
|
| 1289 |
|
|
s390_overlap_p (rtx mem1, rtx mem2, HOST_WIDE_INT size)
|
| 1290 |
|
|
{
|
| 1291 |
|
|
rtx addr1, addr2, addr_delta;
|
| 1292 |
|
|
HOST_WIDE_INT delta;
|
| 1293 |
|
|
|
| 1294 |
|
|
if (GET_CODE (mem1) != MEM || GET_CODE (mem2) != MEM)
|
| 1295 |
|
|
return true;
|
| 1296 |
|
|
|
| 1297 |
|
|
if (size == 0)
|
| 1298 |
|
|
return false;
|
| 1299 |
|
|
|
| 1300 |
|
|
addr1 = XEXP (mem1, 0);
|
| 1301 |
|
|
addr2 = XEXP (mem2, 0);
|
| 1302 |
|
|
|
| 1303 |
|
|
addr_delta = simplify_binary_operation (MINUS, Pmode, addr2, addr1);
|
| 1304 |
|
|
|
| 1305 |
|
|
/* This overlapping check is used by peepholes merging memory block operations.
|
| 1306 |
|
|
Overlapping operations would otherwise be recognized by the S/390 hardware
|
| 1307 |
|
|
and would fall back to a slower implementation. Allowing overlapping
|
| 1308 |
|
|
operations would lead to slow code but not to wrong code. Therefore we are
|
| 1309 |
|
|
somewhat optimistic if we cannot prove that the memory blocks are
|
| 1310 |
|
|
overlapping.
|
| 1311 |
|
|
That's why we return false here although this may accept operations on
|
| 1312 |
|
|
overlapping memory areas. */
|
| 1313 |
|
|
if (!addr_delta || GET_CODE (addr_delta) != CONST_INT)
|
| 1314 |
|
|
return false;
|
| 1315 |
|
|
|
| 1316 |
|
|
delta = INTVAL (addr_delta);
|
| 1317 |
|
|
|
| 1318 |
|
|
if (delta == 0
|
| 1319 |
|
|
|| (delta > 0 && delta < size)
|
| 1320 |
|
|
|| (delta < 0 && -delta < size))
|
| 1321 |
|
|
return true;
|
| 1322 |
|
|
|
| 1323 |
|
|
return false;
|
| 1324 |
|
|
}
|
| 1325 |
|
|
|
| 1326 |
|
|
/* Check whether the address of memory reference MEM2 equals exactly
|
| 1327 |
|
|
the address of memory reference MEM1 plus DELTA. Return true if
|
| 1328 |
|
|
we can prove this to be the case, false otherwise. */
|
| 1329 |
|
|
|
| 1330 |
|
|
bool
|
| 1331 |
|
|
s390_offset_p (rtx mem1, rtx mem2, rtx delta)
|
| 1332 |
|
|
{
|
| 1333 |
|
|
rtx addr1, addr2, addr_delta;
|
| 1334 |
|
|
|
| 1335 |
|
|
if (GET_CODE (mem1) != MEM || GET_CODE (mem2) != MEM)
|
| 1336 |
|
|
return false;
|
| 1337 |
|
|
|
| 1338 |
|
|
addr1 = XEXP (mem1, 0);
|
| 1339 |
|
|
addr2 = XEXP (mem2, 0);
|
| 1340 |
|
|
|
| 1341 |
|
|
addr_delta = simplify_binary_operation (MINUS, Pmode, addr2, addr1);
|
| 1342 |
|
|
if (!addr_delta || !rtx_equal_p (addr_delta, delta))
|
| 1343 |
|
|
return false;
|
| 1344 |
|
|
|
| 1345 |
|
|
return true;
|
| 1346 |
|
|
}
|
| 1347 |
|
|
|
| 1348 |
|
|
/* Expand logical operator CODE in mode MODE with operands OPERANDS. */
|
| 1349 |
|
|
|
| 1350 |
|
|
void
|
| 1351 |
|
|
s390_expand_logical_operator (enum rtx_code code, enum machine_mode mode,
|
| 1352 |
|
|
rtx *operands)
|
| 1353 |
|
|
{
|
| 1354 |
|
|
enum machine_mode wmode = mode;
|
| 1355 |
|
|
rtx dst = operands[0];
|
| 1356 |
|
|
rtx src1 = operands[1];
|
| 1357 |
|
|
rtx src2 = operands[2];
|
| 1358 |
|
|
rtx op, clob, tem;
|
| 1359 |
|
|
|
| 1360 |
|
|
/* If we cannot handle the operation directly, use a temp register. */
|
| 1361 |
|
|
if (!s390_logical_operator_ok_p (operands))
|
| 1362 |
|
|
dst = gen_reg_rtx (mode);
|
| 1363 |
|
|
|
| 1364 |
|
|
/* QImode and HImode patterns make sense only if we have a destination
|
| 1365 |
|
|
in memory. Otherwise perform the operation in SImode. */
|
| 1366 |
|
|
if ((mode == QImode || mode == HImode) && GET_CODE (dst) != MEM)
|
| 1367 |
|
|
wmode = SImode;
|
| 1368 |
|
|
|
| 1369 |
|
|
/* Widen operands if required. */
|
| 1370 |
|
|
if (mode != wmode)
|
| 1371 |
|
|
{
|
| 1372 |
|
|
if (GET_CODE (dst) == SUBREG
|
| 1373 |
|
|
&& (tem = simplify_subreg (wmode, dst, mode, 0)) != 0)
|
| 1374 |
|
|
dst = tem;
|
| 1375 |
|
|
else if (REG_P (dst))
|
| 1376 |
|
|
dst = gen_rtx_SUBREG (wmode, dst, 0);
|
| 1377 |
|
|
else
|
| 1378 |
|
|
dst = gen_reg_rtx (wmode);
|
| 1379 |
|
|
|
| 1380 |
|
|
if (GET_CODE (src1) == SUBREG
|
| 1381 |
|
|
&& (tem = simplify_subreg (wmode, src1, mode, 0)) != 0)
|
| 1382 |
|
|
src1 = tem;
|
| 1383 |
|
|
else if (GET_MODE (src1) != VOIDmode)
|
| 1384 |
|
|
src1 = gen_rtx_SUBREG (wmode, force_reg (mode, src1), 0);
|
| 1385 |
|
|
|
| 1386 |
|
|
if (GET_CODE (src2) == SUBREG
|
| 1387 |
|
|
&& (tem = simplify_subreg (wmode, src2, mode, 0)) != 0)
|
| 1388 |
|
|
src2 = tem;
|
| 1389 |
|
|
else if (GET_MODE (src2) != VOIDmode)
|
| 1390 |
|
|
src2 = gen_rtx_SUBREG (wmode, force_reg (mode, src2), 0);
|
| 1391 |
|
|
}
|
| 1392 |
|
|
|
| 1393 |
|
|
/* Emit the instruction. */
|
| 1394 |
|
|
op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, wmode, src1, src2));
|
| 1395 |
|
|
clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
|
| 1396 |
|
|
emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
|
| 1397 |
|
|
|
| 1398 |
|
|
/* Fix up the destination if needed. */
|
| 1399 |
|
|
if (dst != operands[0])
|
| 1400 |
|
|
emit_move_insn (operands[0], gen_lowpart (mode, dst));
|
| 1401 |
|
|
}
|
| 1402 |
|
|
|
| 1403 |
|
|
/* Check whether OPERANDS are OK for a logical operation (AND, IOR, XOR). */
|
| 1404 |
|
|
|
| 1405 |
|
|
bool
|
| 1406 |
|
|
s390_logical_operator_ok_p (rtx *operands)
|
| 1407 |
|
|
{
|
| 1408 |
|
|
/* If the destination operand is in memory, it needs to coincide
|
| 1409 |
|
|
with one of the source operands. After reload, it has to be
|
| 1410 |
|
|
the first source operand. */
|
| 1411 |
|
|
if (GET_CODE (operands[0]) == MEM)
|
| 1412 |
|
|
return rtx_equal_p (operands[0], operands[1])
|
| 1413 |
|
|
|| (!reload_completed && rtx_equal_p (operands[0], operands[2]));
|
| 1414 |
|
|
|
| 1415 |
|
|
return true;
|
| 1416 |
|
|
}
|
| 1417 |
|
|
|
| 1418 |
|
|
/* Narrow logical operation CODE of memory operand MEMOP with immediate
|
| 1419 |
|
|
operand IMMOP to switch from SS to SI type instructions. */
|
| 1420 |
|
|
|
| 1421 |
|
|
void
|
| 1422 |
|
|
s390_narrow_logical_operator (enum rtx_code code, rtx *memop, rtx *immop)
|
| 1423 |
|
|
{
|
| 1424 |
|
|
int def = code == AND ? -1 : 0;
|
| 1425 |
|
|
HOST_WIDE_INT mask;
|
| 1426 |
|
|
int part;
|
| 1427 |
|
|
|
| 1428 |
|
|
gcc_assert (GET_CODE (*memop) == MEM);
|
| 1429 |
|
|
gcc_assert (!MEM_VOLATILE_P (*memop));
|
| 1430 |
|
|
|
| 1431 |
|
|
mask = s390_extract_part (*immop, QImode, def);
|
| 1432 |
|
|
part = s390_single_part (*immop, GET_MODE (*memop), QImode, def);
|
| 1433 |
|
|
gcc_assert (part >= 0);
|
| 1434 |
|
|
|
| 1435 |
|
|
*memop = adjust_address (*memop, QImode, part);
|
| 1436 |
|
|
*immop = gen_int_mode (mask, QImode);
|
| 1437 |
|
|
}
|
| 1438 |
|
|
|
| 1439 |
|
|
|
| 1440 |
|
|
/* How to allocate a 'struct machine_function'. */
|
| 1441 |
|
|
|
| 1442 |
|
|
static struct machine_function *
|
| 1443 |
|
|
s390_init_machine_status (void)
|
| 1444 |
|
|
{
|
| 1445 |
|
|
return GGC_CNEW (struct machine_function);
|
| 1446 |
|
|
}
|
| 1447 |
|
|
|
| 1448 |
|
|
/* Change optimizations to be performed, depending on the
|
| 1449 |
|
|
optimization level.
|
| 1450 |
|
|
|
| 1451 |
|
|
LEVEL is the optimization level specified; 2 if `-O2' is
|
| 1452 |
|
|
specified, 1 if `-O' is specified, and 0 if neither is specified.
|
| 1453 |
|
|
|
| 1454 |
|
|
SIZE is nonzero if `-Os' is specified and zero otherwise. */
|
| 1455 |
|
|
|
| 1456 |
|
|
void
|
| 1457 |
|
|
optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
|
| 1458 |
|
|
{
|
| 1459 |
|
|
/* ??? There are apparently still problems with -fcaller-saves. */
|
| 1460 |
|
|
flag_caller_saves = 0;
|
| 1461 |
|
|
|
| 1462 |
|
|
/* By default, always emit DWARF-2 unwind info. This allows debugging
|
| 1463 |
|
|
without maintaining a stack frame back-chain. */
|
| 1464 |
|
|
flag_asynchronous_unwind_tables = 1;
|
| 1465 |
|
|
|
| 1466 |
|
|
/* Use MVCLE instructions to decrease code size if requested. */
|
| 1467 |
|
|
if (size != 0)
|
| 1468 |
|
|
target_flags |= MASK_MVCLE;
|
| 1469 |
|
|
}
|
| 1470 |
|
|
|
| 1471 |
|
|
/* Return true if ARG is the name of a processor. Set *TYPE and *FLAGS
|
| 1472 |
|
|
to the associated processor_type and processor_flags if so. */
|
| 1473 |
|
|
|
| 1474 |
|
|
static bool
|
| 1475 |
|
|
s390_handle_arch_option (const char *arg,
|
| 1476 |
|
|
enum processor_type *type,
|
| 1477 |
|
|
int *flags)
|
| 1478 |
|
|
{
|
| 1479 |
|
|
static struct pta
|
| 1480 |
|
|
{
|
| 1481 |
|
|
const char *const name; /* processor name or nickname. */
|
| 1482 |
|
|
const enum processor_type processor;
|
| 1483 |
|
|
const int flags; /* From enum processor_flags. */
|
| 1484 |
|
|
}
|
| 1485 |
|
|
const processor_alias_table[] =
|
| 1486 |
|
|
{
|
| 1487 |
|
|
{"g5", PROCESSOR_9672_G5, PF_IEEE_FLOAT},
|
| 1488 |
|
|
{"g6", PROCESSOR_9672_G6, PF_IEEE_FLOAT},
|
| 1489 |
|
|
{"z900", PROCESSOR_2064_Z900, PF_IEEE_FLOAT | PF_ZARCH},
|
| 1490 |
|
|
{"z990", PROCESSOR_2084_Z990, PF_IEEE_FLOAT | PF_ZARCH
|
| 1491 |
|
|
| PF_LONG_DISPLACEMENT},
|
| 1492 |
|
|
{"z9-109", PROCESSOR_2094_Z9_109, PF_IEEE_FLOAT | PF_ZARCH
|
| 1493 |
|
|
| PF_LONG_DISPLACEMENT | PF_EXTIMM},
|
| 1494 |
|
|
{"z9-ec", PROCESSOR_2094_Z9_109, PF_IEEE_FLOAT | PF_ZARCH
|
| 1495 |
|
|
| PF_LONG_DISPLACEMENT | PF_EXTIMM | PF_DFP },
|
| 1496 |
|
|
{"z10", PROCESSOR_2097_Z10, PF_IEEE_FLOAT | PF_ZARCH
|
| 1497 |
|
|
| PF_LONG_DISPLACEMENT | PF_EXTIMM | PF_DFP | PF_Z10},
|
| 1498 |
|
|
};
|
| 1499 |
|
|
size_t i;
|
| 1500 |
|
|
|
| 1501 |
|
|
for (i = 0; i < ARRAY_SIZE (processor_alias_table); i++)
|
| 1502 |
|
|
if (strcmp (arg, processor_alias_table[i].name) == 0)
|
| 1503 |
|
|
{
|
| 1504 |
|
|
*type = processor_alias_table[i].processor;
|
| 1505 |
|
|
*flags = processor_alias_table[i].flags;
|
| 1506 |
|
|
return true;
|
| 1507 |
|
|
}
|
| 1508 |
|
|
return false;
|
| 1509 |
|
|
}
|
| 1510 |
|
|
|
| 1511 |
|
|
/* Implement TARGET_HANDLE_OPTION. */
|
| 1512 |
|
|
|
| 1513 |
|
|
static bool
|
| 1514 |
|
|
s390_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
|
| 1515 |
|
|
{
|
| 1516 |
|
|
switch (code)
|
| 1517 |
|
|
{
|
| 1518 |
|
|
case OPT_march_:
|
| 1519 |
|
|
return s390_handle_arch_option (arg, &s390_arch, &s390_arch_flags);
|
| 1520 |
|
|
|
| 1521 |
|
|
case OPT_mstack_guard_:
|
| 1522 |
|
|
if (sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_stack_guard) != 1)
|
| 1523 |
|
|
return false;
|
| 1524 |
|
|
if (exact_log2 (s390_stack_guard) == -1)
|
| 1525 |
|
|
error ("stack guard value must be an exact power of 2");
|
| 1526 |
|
|
return true;
|
| 1527 |
|
|
|
| 1528 |
|
|
case OPT_mstack_size_:
|
| 1529 |
|
|
if (sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_stack_size) != 1)
|
| 1530 |
|
|
return false;
|
| 1531 |
|
|
if (exact_log2 (s390_stack_size) == -1)
|
| 1532 |
|
|
error ("stack size must be an exact power of 2");
|
| 1533 |
|
|
return true;
|
| 1534 |
|
|
|
| 1535 |
|
|
case OPT_mtune_:
|
| 1536 |
|
|
return s390_handle_arch_option (arg, &s390_tune, &s390_tune_flags);
|
| 1537 |
|
|
|
| 1538 |
|
|
case OPT_mwarn_framesize_:
|
| 1539 |
|
|
return sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_warn_framesize) == 1;
|
| 1540 |
|
|
|
| 1541 |
|
|
default:
|
| 1542 |
|
|
return true;
|
| 1543 |
|
|
}
|
| 1544 |
|
|
}
|
| 1545 |
|
|
|
| 1546 |
|
|
void
|
| 1547 |
|
|
override_options (void)
|
| 1548 |
|
|
{
|
| 1549 |
|
|
/* Set up function hooks. */
|
| 1550 |
|
|
init_machine_status = s390_init_machine_status;
|
| 1551 |
|
|
|
| 1552 |
|
|
/* Architecture mode defaults according to ABI. */
|
| 1553 |
|
|
if (!(target_flags_explicit & MASK_ZARCH))
|
| 1554 |
|
|
{
|
| 1555 |
|
|
if (TARGET_64BIT)
|
| 1556 |
|
|
target_flags |= MASK_ZARCH;
|
| 1557 |
|
|
else
|
| 1558 |
|
|
target_flags &= ~MASK_ZARCH;
|
| 1559 |
|
|
}
|
| 1560 |
|
|
|
| 1561 |
|
|
/* Determine processor architectural level. */
|
| 1562 |
|
|
if (!s390_arch_string)
|
| 1563 |
|
|
{
|
| 1564 |
|
|
s390_arch_string = TARGET_ZARCH? "z900" : "g5";
|
| 1565 |
|
|
s390_handle_arch_option (s390_arch_string, &s390_arch, &s390_arch_flags);
|
| 1566 |
|
|
}
|
| 1567 |
|
|
|
| 1568 |
|
|
/* Determine processor to tune for. */
|
| 1569 |
|
|
if (s390_tune == PROCESSOR_max)
|
| 1570 |
|
|
{
|
| 1571 |
|
|
s390_tune = s390_arch;
|
| 1572 |
|
|
s390_tune_flags = s390_arch_flags;
|
| 1573 |
|
|
}
|
| 1574 |
|
|
|
| 1575 |
|
|
/* Sanity checks. */
|
| 1576 |
|
|
if (TARGET_ZARCH && !TARGET_CPU_ZARCH)
|
| 1577 |
|
|
error ("z/Architecture mode not supported on %s", s390_arch_string);
|
| 1578 |
|
|
if (TARGET_64BIT && !TARGET_ZARCH)
|
| 1579 |
|
|
error ("64-bit ABI not supported in ESA/390 mode");
|
| 1580 |
|
|
|
| 1581 |
|
|
if (TARGET_HARD_DFP && !TARGET_DFP)
|
| 1582 |
|
|
{
|
| 1583 |
|
|
if (target_flags_explicit & MASK_HARD_DFP)
|
| 1584 |
|
|
{
|
| 1585 |
|
|
if (!TARGET_CPU_DFP)
|
| 1586 |
|
|
error ("Hardware decimal floating point instructions"
|
| 1587 |
|
|
" not available on %s", s390_arch_string);
|
| 1588 |
|
|
if (!TARGET_ZARCH)
|
| 1589 |
|
|
error ("Hardware decimal floating point instructions"
|
| 1590 |
|
|
" not available in ESA/390 mode");
|
| 1591 |
|
|
}
|
| 1592 |
|
|
else
|
| 1593 |
|
|
target_flags &= ~MASK_HARD_DFP;
|
| 1594 |
|
|
}
|
| 1595 |
|
|
|
| 1596 |
|
|
if ((target_flags_explicit & MASK_SOFT_FLOAT) && TARGET_SOFT_FLOAT)
|
| 1597 |
|
|
{
|
| 1598 |
|
|
if ((target_flags_explicit & MASK_HARD_DFP) && TARGET_HARD_DFP)
|
| 1599 |
|
|
error ("-mhard-dfp can't be used in conjunction with -msoft-float");
|
| 1600 |
|
|
|
| 1601 |
|
|
target_flags &= ~MASK_HARD_DFP;
|
| 1602 |
|
|
}
|
| 1603 |
|
|
|
| 1604 |
|
|
/* Set processor cost function. */
|
| 1605 |
|
|
switch (s390_tune)
|
| 1606 |
|
|
{
|
| 1607 |
|
|
case PROCESSOR_2084_Z990:
|
| 1608 |
|
|
s390_cost = &z990_cost;
|
| 1609 |
|
|
break;
|
| 1610 |
|
|
case PROCESSOR_2094_Z9_109:
|
| 1611 |
|
|
s390_cost = &z9_109_cost;
|
| 1612 |
|
|
break;
|
| 1613 |
|
|
case PROCESSOR_2097_Z10:
|
| 1614 |
|
|
s390_cost = &z10_cost;
|
| 1615 |
|
|
break;
|
| 1616 |
|
|
default:
|
| 1617 |
|
|
s390_cost = &z900_cost;
|
| 1618 |
|
|
}
|
| 1619 |
|
|
|
| 1620 |
|
|
if (TARGET_BACKCHAIN && TARGET_PACKED_STACK && TARGET_HARD_FLOAT)
|
| 1621 |
|
|
error ("-mbackchain -mpacked-stack -mhard-float are not supported "
|
| 1622 |
|
|
"in combination");
|
| 1623 |
|
|
|
| 1624 |
|
|
if (s390_stack_size)
|
| 1625 |
|
|
{
|
| 1626 |
|
|
if (s390_stack_guard >= s390_stack_size)
|
| 1627 |
|
|
error ("stack size must be greater than the stack guard value");
|
| 1628 |
|
|
else if (s390_stack_size > 1 << 16)
|
| 1629 |
|
|
error ("stack size must not be greater than 64k");
|
| 1630 |
|
|
}
|
| 1631 |
|
|
else if (s390_stack_guard)
|
| 1632 |
|
|
error ("-mstack-guard implies use of -mstack-size");
|
| 1633 |
|
|
|
| 1634 |
|
|
#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
|
| 1635 |
|
|
if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
|
| 1636 |
|
|
target_flags |= MASK_LONG_DOUBLE_128;
|
| 1637 |
|
|
#endif
|
| 1638 |
|
|
|
| 1639 |
|
|
if (s390_tune == PROCESSOR_2097_Z10)
|
| 1640 |
|
|
{
|
| 1641 |
|
|
if (!PARAM_SET_P (PARAM_MAX_UNROLLED_INSNS))
|
| 1642 |
|
|
set_param_value ("max-unrolled-insns", 100);
|
| 1643 |
|
|
if (!PARAM_SET_P (PARAM_MAX_UNROLL_TIMES))
|
| 1644 |
|
|
set_param_value ("max-unroll-times", 32);
|
| 1645 |
|
|
if (!PARAM_SET_P (PARAM_MAX_COMPLETELY_PEELED_INSNS))
|
| 1646 |
|
|
set_param_value ("max-completely-peeled-insns", 2000);
|
| 1647 |
|
|
if (!PARAM_SET_P (PARAM_MAX_COMPLETELY_PEEL_TIMES))
|
| 1648 |
|
|
set_param_value ("max-completely-peel-times", 64);
|
| 1649 |
|
|
}
|
| 1650 |
|
|
|
| 1651 |
|
|
set_param_value ("max-pending-list-length", 256);
|
| 1652 |
|
|
}
|
| 1653 |
|
|
|
| 1654 |
|
|
/* Map for smallest class containing reg regno. */
|
| 1655 |
|
|
|
| 1656 |
|
|
const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
|
| 1657 |
|
|
{ GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
|
| 1658 |
|
|
ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
|
| 1659 |
|
|
ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
|
| 1660 |
|
|
ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
|
| 1661 |
|
|
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
| 1662 |
|
|
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
| 1663 |
|
|
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
| 1664 |
|
|
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
| 1665 |
|
|
ADDR_REGS, CC_REGS, ADDR_REGS, ADDR_REGS,
|
| 1666 |
|
|
ACCESS_REGS, ACCESS_REGS
|
| 1667 |
|
|
};
|
| 1668 |
|
|
|
| 1669 |
|
|
/* Return attribute type of insn. */
|
| 1670 |
|
|
|
| 1671 |
|
|
static enum attr_type
|
| 1672 |
|
|
s390_safe_attr_type (rtx insn)
|
| 1673 |
|
|
{
|
| 1674 |
|
|
if (recog_memoized (insn) >= 0)
|
| 1675 |
|
|
return get_attr_type (insn);
|
| 1676 |
|
|
else
|
| 1677 |
|
|
return TYPE_NONE;
|
| 1678 |
|
|
}
|
| 1679 |
|
|
|
| 1680 |
|
|
/* Return true if DISP is a valid short displacement. */
|
| 1681 |
|
|
|
| 1682 |
|
|
static bool
|
| 1683 |
|
|
s390_short_displacement (rtx disp)
|
| 1684 |
|
|
{
|
| 1685 |
|
|
/* No displacement is OK. */
|
| 1686 |
|
|
if (!disp)
|
| 1687 |
|
|
return true;
|
| 1688 |
|
|
|
| 1689 |
|
|
/* Without the long displacement facility we don't need to
|
| 1690 |
|
|
distingiush between long and short displacement. */
|
| 1691 |
|
|
if (!TARGET_LONG_DISPLACEMENT)
|
| 1692 |
|
|
return true;
|
| 1693 |
|
|
|
| 1694 |
|
|
/* Integer displacement in range. */
|
| 1695 |
|
|
if (GET_CODE (disp) == CONST_INT)
|
| 1696 |
|
|
return INTVAL (disp) >= 0 && INTVAL (disp) < 4096;
|
| 1697 |
|
|
|
| 1698 |
|
|
/* GOT offset is not OK, the GOT can be large. */
|
| 1699 |
|
|
if (GET_CODE (disp) == CONST
|
| 1700 |
|
|
&& GET_CODE (XEXP (disp, 0)) == UNSPEC
|
| 1701 |
|
|
&& (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT
|
| 1702 |
|
|
|| XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF))
|
| 1703 |
|
|
return false;
|
| 1704 |
|
|
|
| 1705 |
|
|
/* All other symbolic constants are literal pool references,
|
| 1706 |
|
|
which are OK as the literal pool must be small. */
|
| 1707 |
|
|
if (GET_CODE (disp) == CONST)
|
| 1708 |
|
|
return true;
|
| 1709 |
|
|
|
| 1710 |
|
|
return false;
|
| 1711 |
|
|
}
|
| 1712 |
|
|
|
| 1713 |
|
|
/* Decompose a RTL expression ADDR for a memory address into
|
| 1714 |
|
|
its components, returned in OUT.
|
| 1715 |
|
|
|
| 1716 |
|
|
Returns false if ADDR is not a valid memory address, true
|
| 1717 |
|
|
otherwise. If OUT is NULL, don't return the components,
|
| 1718 |
|
|
but check for validity only.
|
| 1719 |
|
|
|
| 1720 |
|
|
Note: Only addresses in canonical form are recognized.
|
| 1721 |
|
|
LEGITIMIZE_ADDRESS should convert non-canonical forms to the
|
| 1722 |
|
|
canonical form so that they will be recognized. */
|
| 1723 |
|
|
|
| 1724 |
|
|
static int
|
| 1725 |
|
|
s390_decompose_address (rtx addr, struct s390_address *out)
|
| 1726 |
|
|
{
|
| 1727 |
|
|
HOST_WIDE_INT offset = 0;
|
| 1728 |
|
|
rtx base = NULL_RTX;
|
| 1729 |
|
|
rtx indx = NULL_RTX;
|
| 1730 |
|
|
rtx disp = NULL_RTX;
|
| 1731 |
|
|
rtx orig_disp;
|
| 1732 |
|
|
bool pointer = false;
|
| 1733 |
|
|
bool base_ptr = false;
|
| 1734 |
|
|
bool indx_ptr = false;
|
| 1735 |
|
|
bool literal_pool = false;
|
| 1736 |
|
|
|
| 1737 |
|
|
/* We may need to substitute the literal pool base register into the address
|
| 1738 |
|
|
below. However, at this point we do not know which register is going to
|
| 1739 |
|
|
be used as base, so we substitute the arg pointer register. This is going
|
| 1740 |
|
|
to be treated as holding a pointer below -- it shouldn't be used for any
|
| 1741 |
|
|
other purpose. */
|
| 1742 |
|
|
rtx fake_pool_base = gen_rtx_REG (Pmode, ARG_POINTER_REGNUM);
|
| 1743 |
|
|
|
| 1744 |
|
|
/* Decompose address into base + index + displacement. */
|
| 1745 |
|
|
|
| 1746 |
|
|
if (GET_CODE (addr) == REG || GET_CODE (addr) == UNSPEC)
|
| 1747 |
|
|
base = addr;
|
| 1748 |
|
|
|
| 1749 |
|
|
else if (GET_CODE (addr) == PLUS)
|
| 1750 |
|
|
{
|
| 1751 |
|
|
rtx op0 = XEXP (addr, 0);
|
| 1752 |
|
|
rtx op1 = XEXP (addr, 1);
|
| 1753 |
|
|
enum rtx_code code0 = GET_CODE (op0);
|
| 1754 |
|
|
enum rtx_code code1 = GET_CODE (op1);
|
| 1755 |
|
|
|
| 1756 |
|
|
if (code0 == REG || code0 == UNSPEC)
|
| 1757 |
|
|
{
|
| 1758 |
|
|
if (code1 == REG || code1 == UNSPEC)
|
| 1759 |
|
|
{
|
| 1760 |
|
|
indx = op0; /* index + base */
|
| 1761 |
|
|
base = op1;
|
| 1762 |
|
|
}
|
| 1763 |
|
|
|
| 1764 |
|
|
else
|
| 1765 |
|
|
{
|
| 1766 |
|
|
base = op0; /* base + displacement */
|
| 1767 |
|
|
disp = op1;
|
| 1768 |
|
|
}
|
| 1769 |
|
|
}
|
| 1770 |
|
|
|
| 1771 |
|
|
else if (code0 == PLUS)
|
| 1772 |
|
|
{
|
| 1773 |
|
|
indx = XEXP (op0, 0); /* index + base + disp */
|
| 1774 |
|
|
base = XEXP (op0, 1);
|
| 1775 |
|
|
disp = op1;
|
| 1776 |
|
|
}
|
| 1777 |
|
|
|
| 1778 |
|
|
else
|
| 1779 |
|
|
{
|
| 1780 |
|
|
return false;
|
| 1781 |
|
|
}
|
| 1782 |
|
|
}
|
| 1783 |
|
|
|
| 1784 |
|
|
else
|
| 1785 |
|
|
disp = addr; /* displacement */
|
| 1786 |
|
|
|
| 1787 |
|
|
/* Extract integer part of displacement. */
|
| 1788 |
|
|
orig_disp = disp;
|
| 1789 |
|
|
if (disp)
|
| 1790 |
|
|
{
|
| 1791 |
|
|
if (GET_CODE (disp) == CONST_INT)
|
| 1792 |
|
|
{
|
| 1793 |
|
|
offset = INTVAL (disp);
|
| 1794 |
|
|
disp = NULL_RTX;
|
| 1795 |
|
|
}
|
| 1796 |
|
|
else if (GET_CODE (disp) == CONST
|
| 1797 |
|
|
&& GET_CODE (XEXP (disp, 0)) == PLUS
|
| 1798 |
|
|
&& GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
|
| 1799 |
|
|
{
|
| 1800 |
|
|
offset = INTVAL (XEXP (XEXP (disp, 0), 1));
|
| 1801 |
|
|
disp = XEXP (XEXP (disp, 0), 0);
|
| 1802 |
|
|
}
|
| 1803 |
|
|
}
|
| 1804 |
|
|
|
| 1805 |
|
|
/* Strip off CONST here to avoid special case tests later. */
|
| 1806 |
|
|
if (disp && GET_CODE (disp) == CONST)
|
| 1807 |
|
|
disp = XEXP (disp, 0);
|
| 1808 |
|
|
|
| 1809 |
|
|
/* We can convert literal pool addresses to
|
| 1810 |
|
|
displacements by basing them off the base register. */
|
| 1811 |
|
|
if (disp && GET_CODE (disp) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (disp))
|
| 1812 |
|
|
{
|
| 1813 |
|
|
/* Either base or index must be free to hold the base register. */
|
| 1814 |
|
|
if (!base)
|
| 1815 |
|
|
base = fake_pool_base, literal_pool = true;
|
| 1816 |
|
|
else if (!indx)
|
| 1817 |
|
|
indx = fake_pool_base, literal_pool = true;
|
| 1818 |
|
|
else
|
| 1819 |
|
|
return false;
|
| 1820 |
|
|
|
| 1821 |
|
|
/* Mark up the displacement. */
|
| 1822 |
|
|
disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
|
| 1823 |
|
|
UNSPEC_LTREL_OFFSET);
|
| 1824 |
|
|
}
|
| 1825 |
|
|
|
| 1826 |
|
|
/* Validate base register. */
|
| 1827 |
|
|
if (base)
|
| 1828 |
|
|
{
|
| 1829 |
|
|
if (GET_CODE (base) == UNSPEC)
|
| 1830 |
|
|
switch (XINT (base, 1))
|
| 1831 |
|
|
{
|
| 1832 |
|
|
case UNSPEC_LTREF:
|
| 1833 |
|
|
if (!disp)
|
| 1834 |
|
|
disp = gen_rtx_UNSPEC (Pmode,
|
| 1835 |
|
|
gen_rtvec (1, XVECEXP (base, 0, 0)),
|
| 1836 |
|
|
UNSPEC_LTREL_OFFSET);
|
| 1837 |
|
|
else
|
| 1838 |
|
|
return false;
|
| 1839 |
|
|
|
| 1840 |
|
|
base = XVECEXP (base, 0, 1);
|
| 1841 |
|
|
break;
|
| 1842 |
|
|
|
| 1843 |
|
|
case UNSPEC_LTREL_BASE:
|
| 1844 |
|
|
if (XVECLEN (base, 0) == 1)
|
| 1845 |
|
|
base = fake_pool_base, literal_pool = true;
|
| 1846 |
|
|
else
|
| 1847 |
|
|
base = XVECEXP (base, 0, 1);
|
| 1848 |
|
|
break;
|
| 1849 |
|
|
|
| 1850 |
|
|
default:
|
| 1851 |
|
|
return false;
|
| 1852 |
|
|
}
|
| 1853 |
|
|
|
| 1854 |
|
|
if (!REG_P (base)
|
| 1855 |
|
|
|| (GET_MODE (base) != SImode
|
| 1856 |
|
|
&& GET_MODE (base) != Pmode))
|
| 1857 |
|
|
return false;
|
| 1858 |
|
|
|
| 1859 |
|
|
if (REGNO (base) == STACK_POINTER_REGNUM
|
| 1860 |
|
|
|| REGNO (base) == FRAME_POINTER_REGNUM
|
| 1861 |
|
|
|| ((reload_completed || reload_in_progress)
|
| 1862 |
|
|
&& frame_pointer_needed
|
| 1863 |
|
|
&& REGNO (base) == HARD_FRAME_POINTER_REGNUM)
|
| 1864 |
|
|
|| REGNO (base) == ARG_POINTER_REGNUM
|
| 1865 |
|
|
|| (flag_pic
|
| 1866 |
|
|
&& REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
|
| 1867 |
|
|
pointer = base_ptr = true;
|
| 1868 |
|
|
|
| 1869 |
|
|
if ((reload_completed || reload_in_progress)
|
| 1870 |
|
|
&& base == cfun->machine->base_reg)
|
| 1871 |
|
|
pointer = base_ptr = literal_pool = true;
|
| 1872 |
|
|
}
|
| 1873 |
|
|
|
| 1874 |
|
|
/* Validate index register. */
|
| 1875 |
|
|
if (indx)
|
| 1876 |
|
|
{
|
| 1877 |
|
|
if (GET_CODE (indx) == UNSPEC)
|
| 1878 |
|
|
switch (XINT (indx, 1))
|
| 1879 |
|
|
{
|
| 1880 |
|
|
case UNSPEC_LTREF:
|
| 1881 |
|
|
if (!disp)
|
| 1882 |
|
|
disp = gen_rtx_UNSPEC (Pmode,
|
| 1883 |
|
|
gen_rtvec (1, XVECEXP (indx, 0, 0)),
|
| 1884 |
|
|
UNSPEC_LTREL_OFFSET);
|
| 1885 |
|
|
else
|
| 1886 |
|
|
return false;
|
| 1887 |
|
|
|
| 1888 |
|
|
indx = XVECEXP (indx, 0, 1);
|
| 1889 |
|
|
break;
|
| 1890 |
|
|
|
| 1891 |
|
|
case UNSPEC_LTREL_BASE:
|
| 1892 |
|
|
if (XVECLEN (indx, 0) == 1)
|
| 1893 |
|
|
indx = fake_pool_base, literal_pool = true;
|
| 1894 |
|
|
else
|
| 1895 |
|
|
indx = XVECEXP (indx, 0, 1);
|
| 1896 |
|
|
break;
|
| 1897 |
|
|
|
| 1898 |
|
|
default:
|
| 1899 |
|
|
return false;
|
| 1900 |
|
|
}
|
| 1901 |
|
|
|
| 1902 |
|
|
if (!REG_P (indx)
|
| 1903 |
|
|
|| (GET_MODE (indx) != SImode
|
| 1904 |
|
|
&& GET_MODE (indx) != Pmode))
|
| 1905 |
|
|
return false;
|
| 1906 |
|
|
|
| 1907 |
|
|
if (REGNO (indx) == STACK_POINTER_REGNUM
|
| 1908 |
|
|
|| REGNO (indx) == FRAME_POINTER_REGNUM
|
| 1909 |
|
|
|| ((reload_completed || reload_in_progress)
|
| 1910 |
|
|
&& frame_pointer_needed
|
| 1911 |
|
|
&& REGNO (indx) == HARD_FRAME_POINTER_REGNUM)
|
| 1912 |
|
|
|| REGNO (indx) == ARG_POINTER_REGNUM
|
| 1913 |
|
|
|| (flag_pic
|
| 1914 |
|
|
&& REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
|
| 1915 |
|
|
pointer = indx_ptr = true;
|
| 1916 |
|
|
|
| 1917 |
|
|
if ((reload_completed || reload_in_progress)
|
| 1918 |
|
|
&& indx == cfun->machine->base_reg)
|
| 1919 |
|
|
pointer = indx_ptr = literal_pool = true;
|
| 1920 |
|
|
}
|
| 1921 |
|
|
|
| 1922 |
|
|
/* Prefer to use pointer as base, not index. */
|
| 1923 |
|
|
if (base && indx && !base_ptr
|
| 1924 |
|
|
&& (indx_ptr || (!REG_POINTER (base) && REG_POINTER (indx))))
|
| 1925 |
|
|
{
|
| 1926 |
|
|
rtx tmp = base;
|
| 1927 |
|
|
base = indx;
|
| 1928 |
|
|
indx = tmp;
|
| 1929 |
|
|
}
|
| 1930 |
|
|
|
| 1931 |
|
|
/* Validate displacement. */
|
| 1932 |
|
|
if (!disp)
|
| 1933 |
|
|
{
|
| 1934 |
|
|
/* If virtual registers are involved, the displacement will change later
|
| 1935 |
|
|
anyway as the virtual registers get eliminated. This could make a
|
| 1936 |
|
|
valid displacement invalid, but it is more likely to make an invalid
|
| 1937 |
|
|
displacement valid, because we sometimes access the register save area
|
| 1938 |
|
|
via negative offsets to one of those registers.
|
| 1939 |
|
|
Thus we don't check the displacement for validity here. If after
|
| 1940 |
|
|
elimination the displacement turns out to be invalid after all,
|
| 1941 |
|
|
this is fixed up by reload in any case. */
|
| 1942 |
|
|
if (base != arg_pointer_rtx
|
| 1943 |
|
|
&& indx != arg_pointer_rtx
|
| 1944 |
|
|
&& base != return_address_pointer_rtx
|
| 1945 |
|
|
&& indx != return_address_pointer_rtx
|
| 1946 |
|
|
&& base != frame_pointer_rtx
|
| 1947 |
|
|
&& indx != frame_pointer_rtx
|
| 1948 |
|
|
&& base != virtual_stack_vars_rtx
|
| 1949 |
|
|
&& indx != virtual_stack_vars_rtx)
|
| 1950 |
|
|
if (!DISP_IN_RANGE (offset))
|
| 1951 |
|
|
return false;
|
| 1952 |
|
|
}
|
| 1953 |
|
|
else
|
| 1954 |
|
|
{
|
| 1955 |
|
|
/* All the special cases are pointers. */
|
| 1956 |
|
|
pointer = true;
|
| 1957 |
|
|
|
| 1958 |
|
|
/* In the small-PIC case, the linker converts @GOT
|
| 1959 |
|
|
and @GOTNTPOFF offsets to possible displacements. */
|
| 1960 |
|
|
if (GET_CODE (disp) == UNSPEC
|
| 1961 |
|
|
&& (XINT (disp, 1) == UNSPEC_GOT
|
| 1962 |
|
|
|| XINT (disp, 1) == UNSPEC_GOTNTPOFF)
|
| 1963 |
|
|
&& flag_pic == 1)
|
| 1964 |
|
|
{
|
| 1965 |
|
|
;
|
| 1966 |
|
|
}
|
| 1967 |
|
|
|
| 1968 |
|
|
/* Accept pool label offsets. */
|
| 1969 |
|
|
else if (GET_CODE (disp) == UNSPEC
|
| 1970 |
|
|
&& XINT (disp, 1) == UNSPEC_POOL_OFFSET)
|
| 1971 |
|
|
;
|
| 1972 |
|
|
|
| 1973 |
|
|
/* Accept literal pool references. */
|
| 1974 |
|
|
else if (GET_CODE (disp) == UNSPEC
|
| 1975 |
|
|
&& XINT (disp, 1) == UNSPEC_LTREL_OFFSET)
|
| 1976 |
|
|
{
|
| 1977 |
|
|
orig_disp = gen_rtx_CONST (Pmode, disp);
|
| 1978 |
|
|
if (offset)
|
| 1979 |
|
|
{
|
| 1980 |
|
|
/* If we have an offset, make sure it does not
|
| 1981 |
|
|
exceed the size of the constant pool entry. */
|
| 1982 |
|
|
rtx sym = XVECEXP (disp, 0, 0);
|
| 1983 |
|
|
if (offset >= GET_MODE_SIZE (get_pool_mode (sym)))
|
| 1984 |
|
|
return false;
|
| 1985 |
|
|
|
| 1986 |
|
|
orig_disp = plus_constant (orig_disp, offset);
|
| 1987 |
|
|
}
|
| 1988 |
|
|
}
|
| 1989 |
|
|
|
| 1990 |
|
|
else
|
| 1991 |
|
|
return false;
|
| 1992 |
|
|
}
|
| 1993 |
|
|
|
| 1994 |
|
|
if (!base && !indx)
|
| 1995 |
|
|
pointer = true;
|
| 1996 |
|
|
|
| 1997 |
|
|
if (out)
|
| 1998 |
|
|
{
|
| 1999 |
|
|
out->base = base;
|
| 2000 |
|
|
out->indx = indx;
|
| 2001 |
|
|
out->disp = orig_disp;
|
| 2002 |
|
|
out->pointer = pointer;
|
| 2003 |
|
|
out->literal_pool = literal_pool;
|
| 2004 |
|
|
}
|
| 2005 |
|
|
|
| 2006 |
|
|
return true;
|
| 2007 |
|
|
}
|
| 2008 |
|
|
|
| 2009 |
|
|
/* Decompose a RTL expression OP for a shift count into its components,
|
| 2010 |
|
|
and return the base register in BASE and the offset in OFFSET.
|
| 2011 |
|
|
|
| 2012 |
|
|
Return true if OP is a valid shift count, false if not. */
|
| 2013 |
|
|
|
| 2014 |
|
|
bool
|
| 2015 |
|
|
s390_decompose_shift_count (rtx op, rtx *base, HOST_WIDE_INT *offset)
|
| 2016 |
|
|
{
|
| 2017 |
|
|
HOST_WIDE_INT off = 0;
|
| 2018 |
|
|
|
| 2019 |
|
|
/* We can have an integer constant, an address register,
|
| 2020 |
|
|
or a sum of the two. */
|
| 2021 |
|
|
if (GET_CODE (op) == CONST_INT)
|
| 2022 |
|
|
{
|
| 2023 |
|
|
off = INTVAL (op);
|
| 2024 |
|
|
op = NULL_RTX;
|
| 2025 |
|
|
}
|
| 2026 |
|
|
if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
|
| 2027 |
|
|
{
|
| 2028 |
|
|
off = INTVAL (XEXP (op, 1));
|
| 2029 |
|
|
op = XEXP (op, 0);
|
| 2030 |
|
|
}
|
| 2031 |
|
|
while (op && GET_CODE (op) == SUBREG)
|
| 2032 |
|
|
op = SUBREG_REG (op);
|
| 2033 |
|
|
|
| 2034 |
|
|
if (op && GET_CODE (op) != REG)
|
| 2035 |
|
|
return false;
|
| 2036 |
|
|
|
| 2037 |
|
|
if (offset)
|
| 2038 |
|
|
*offset = off;
|
| 2039 |
|
|
if (base)
|
| 2040 |
|
|
*base = op;
|
| 2041 |
|
|
|
| 2042 |
|
|
return true;
|
| 2043 |
|
|
}
|
| 2044 |
|
|
|
| 2045 |
|
|
|
| 2046 |
|
|
/* Return true if CODE is a valid address without index. */
|
| 2047 |
|
|
|
| 2048 |
|
|
bool
|
| 2049 |
|
|
s390_legitimate_address_without_index_p (rtx op)
|
| 2050 |
|
|
{
|
| 2051 |
|
|
struct s390_address addr;
|
| 2052 |
|
|
|
| 2053 |
|
|
if (!s390_decompose_address (XEXP (op, 0), &addr))
|
| 2054 |
|
|
return false;
|
| 2055 |
|
|
if (addr.indx)
|
| 2056 |
|
|
return false;
|
| 2057 |
|
|
|
| 2058 |
|
|
return true;
|
| 2059 |
|
|
}
|
| 2060 |
|
|
|
| 2061 |
|
|
|
| 2062 |
|
|
/* Return true if ADDR is of kind symbol_ref or symbol_ref + const_int
|
| 2063 |
|
|
and return these parts in SYMREF and ADDEND. You can pass NULL in
|
| 2064 |
|
|
SYMREF and/or ADDEND if you are not interested in these values. */
|
| 2065 |
|
|
|
| 2066 |
|
|
static bool
|
| 2067 |
|
|
s390_symref_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend)
|
| 2068 |
|
|
{
|
| 2069 |
|
|
HOST_WIDE_INT tmpaddend = 0;
|
| 2070 |
|
|
|
| 2071 |
|
|
if (GET_CODE (addr) == CONST)
|
| 2072 |
|
|
addr = XEXP (addr, 0);
|
| 2073 |
|
|
|
| 2074 |
|
|
if (GET_CODE (addr) == PLUS)
|
| 2075 |
|
|
{
|
| 2076 |
|
|
if (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF
|
| 2077 |
|
|
&& CONST_INT_P (XEXP (addr, 1)))
|
| 2078 |
|
|
{
|
| 2079 |
|
|
tmpaddend = INTVAL (XEXP (addr, 1));
|
| 2080 |
|
|
addr = XEXP (addr, 0);
|
| 2081 |
|
|
}
|
| 2082 |
|
|
else
|
| 2083 |
|
|
return false;
|
| 2084 |
|
|
}
|
| 2085 |
|
|
else
|
| 2086 |
|
|
if (GET_CODE (addr) != SYMBOL_REF)
|
| 2087 |
|
|
return false;
|
| 2088 |
|
|
|
| 2089 |
|
|
if (symref)
|
| 2090 |
|
|
*symref = addr;
|
| 2091 |
|
|
if (addend)
|
| 2092 |
|
|
*addend = tmpaddend;
|
| 2093 |
|
|
|
| 2094 |
|
|
return true;
|
| 2095 |
|
|
}
|
| 2096 |
|
|
|
| 2097 |
|
|
|
| 2098 |
|
|
/* Return true if the address in OP is valid for constraint letter C
|
| 2099 |
|
|
if wrapped in a MEM rtx. Set LIT_POOL_OK to true if it literal
|
| 2100 |
|
|
pool MEMs should be accepted. Only the Q, R, S, T constraint
|
| 2101 |
|
|
letters are allowed for C. */
|
| 2102 |
|
|
|
| 2103 |
|
|
static int
|
| 2104 |
|
|
s390_check_qrst_address (char c, rtx op, bool lit_pool_ok)
|
| 2105 |
|
|
{
|
| 2106 |
|
|
struct s390_address addr;
|
| 2107 |
|
|
bool decomposed = false;
|
| 2108 |
|
|
|
| 2109 |
|
|
/* This check makes sure that no symbolic address (except literal
|
| 2110 |
|
|
pool references) are accepted by the R or T constraints. */
|
| 2111 |
|
|
if (s390_symref_operand_p (op, NULL, NULL))
|
| 2112 |
|
|
{
|
| 2113 |
|
|
if (!lit_pool_ok)
|
| 2114 |
|
|
return 0;
|
| 2115 |
|
|
if (!s390_decompose_address (op, &addr))
|
| 2116 |
|
|
return 0;
|
| 2117 |
|
|
if (!addr.literal_pool)
|
| 2118 |
|
|
return 0;
|
| 2119 |
|
|
decomposed = true;
|
| 2120 |
|
|
}
|
| 2121 |
|
|
|
| 2122 |
|
|
switch (c)
|
| 2123 |
|
|
{
|
| 2124 |
|
|
case 'Q': /* no index short displacement */
|
| 2125 |
|
|
if (!decomposed && !s390_decompose_address (op, &addr))
|
| 2126 |
|
|
return 0;
|
| 2127 |
|
|
if (addr.indx)
|
| 2128 |
|
|
return 0;
|
| 2129 |
|
|
if (!s390_short_displacement (addr.disp))
|
| 2130 |
|
|
return 0;
|
| 2131 |
|
|
break;
|
| 2132 |
|
|
|
| 2133 |
|
|
case 'R': /* with index short displacement */
|
| 2134 |
|
|
if (TARGET_LONG_DISPLACEMENT)
|
| 2135 |
|
|
{
|
| 2136 |
|
|
if (!decomposed && !s390_decompose_address (op, &addr))
|
| 2137 |
|
|
return 0;
|
| 2138 |
|
|
if (!s390_short_displacement (addr.disp))
|
| 2139 |
|
|
return 0;
|
| 2140 |
|
|
}
|
| 2141 |
|
|
/* Any invalid address here will be fixed up by reload,
|
| 2142 |
|
|
so accept it for the most generic constraint. */
|
| 2143 |
|
|
break;
|
| 2144 |
|
|
|
| 2145 |
|
|
case 'S': /* no index long displacement */
|
| 2146 |
|
|
if (!TARGET_LONG_DISPLACEMENT)
|
| 2147 |
|
|
return 0;
|
| 2148 |
|
|
if (!decomposed && !s390_decompose_address (op, &addr))
|
| 2149 |
|
|
return 0;
|
| 2150 |
|
|
if (addr.indx)
|
| 2151 |
|
|
return 0;
|
| 2152 |
|
|
if (s390_short_displacement (addr.disp))
|
| 2153 |
|
|
return 0;
|
| 2154 |
|
|
break;
|
| 2155 |
|
|
|
| 2156 |
|
|
case 'T': /* with index long displacement */
|
| 2157 |
|
|
if (!TARGET_LONG_DISPLACEMENT)
|
| 2158 |
|
|
return 0;
|
| 2159 |
|
|
/* Any invalid address here will be fixed up by reload,
|
| 2160 |
|
|
so accept it for the most generic constraint. */
|
| 2161 |
|
|
if ((decomposed || s390_decompose_address (op, &addr))
|
| 2162 |
|
|
&& s390_short_displacement (addr.disp))
|
| 2163 |
|
|
return 0;
|
| 2164 |
|
|
break;
|
| 2165 |
|
|
default:
|
| 2166 |
|
|
return 0;
|
| 2167 |
|
|
}
|
| 2168 |
|
|
return 1;
|
| 2169 |
|
|
}
|
| 2170 |
|
|
|
| 2171 |
|
|
|
| 2172 |
|
|
/* Evaluates constraint strings described by the regular expression
|
| 2173 |
|
|
([A|B|Z](Q|R|S|T))|U|W|Y and returns 1 if OP is a valid operand for
|
| 2174 |
|
|
the constraint given in STR, or 0 else. */
|
| 2175 |
|
|
|
| 2176 |
|
|
int
|
| 2177 |
|
|
s390_mem_constraint (const char *str, rtx op)
|
| 2178 |
|
|
{
|
| 2179 |
|
|
char c = str[0];
|
| 2180 |
|
|
|
| 2181 |
|
|
switch (c)
|
| 2182 |
|
|
{
|
| 2183 |
|
|
case 'A':
|
| 2184 |
|
|
/* Check for offsettable variants of memory constraints. */
|
| 2185 |
|
|
if (!MEM_P (op) || MEM_VOLATILE_P (op))
|
| 2186 |
|
|
return 0;
|
| 2187 |
|
|
if ((reload_completed || reload_in_progress)
|
| 2188 |
|
|
? !offsettable_memref_p (op) : !offsettable_nonstrict_memref_p (op))
|
| 2189 |
|
|
return 0;
|
| 2190 |
|
|
return s390_check_qrst_address (str[1], XEXP (op, 0), true);
|
| 2191 |
|
|
case 'B':
|
| 2192 |
|
|
/* Check for non-literal-pool variants of memory constraints. */
|
| 2193 |
|
|
if (!MEM_P (op))
|
| 2194 |
|
|
return 0;
|
| 2195 |
|
|
return s390_check_qrst_address (str[1], XEXP (op, 0), false);
|
| 2196 |
|
|
case 'Q':
|
| 2197 |
|
|
case 'R':
|
| 2198 |
|
|
case 'S':
|
| 2199 |
|
|
case 'T':
|
| 2200 |
|
|
if (GET_CODE (op) != MEM)
|
| 2201 |
|
|
return 0;
|
| 2202 |
|
|
return s390_check_qrst_address (c, XEXP (op, 0), true);
|
| 2203 |
|
|
case 'U':
|
| 2204 |
|
|
return (s390_check_qrst_address ('Q', op, true)
|
| 2205 |
|
|
|| s390_check_qrst_address ('R', op, true));
|
| 2206 |
|
|
case 'W':
|
| 2207 |
|
|
return (s390_check_qrst_address ('S', op, true)
|
| 2208 |
|
|
|| s390_check_qrst_address ('T', op, true));
|
| 2209 |
|
|
case 'Y':
|
| 2210 |
|
|
/* Simply check for the basic form of a shift count. Reload will
|
| 2211 |
|
|
take care of making sure we have a proper base register. */
|
| 2212 |
|
|
if (!s390_decompose_shift_count (op, NULL, NULL))
|
| 2213 |
|
|
return 0;
|
| 2214 |
|
|
break;
|
| 2215 |
|
|
case 'Z':
|
| 2216 |
|
|
return s390_check_qrst_address (str[1], op, true);
|
| 2217 |
|
|
default:
|
| 2218 |
|
|
return 0;
|
| 2219 |
|
|
}
|
| 2220 |
|
|
return 1;
|
| 2221 |
|
|
}
|
| 2222 |
|
|
|
| 2223 |
|
|
|
| 2224 |
|
|
/* Evaluates constraint strings starting with letter O. Input
|
| 2225 |
|
|
parameter C is the second letter following the "O" in the constraint
|
| 2226 |
|
|
string. Returns 1 if VALUE meets the respective constraint and 0
|
| 2227 |
|
|
otherwise. */
|
| 2228 |
|
|
|
| 2229 |
|
|
int
|
| 2230 |
|
|
s390_O_constraint_str (const char c, HOST_WIDE_INT value)
|
| 2231 |
|
|
{
|
| 2232 |
|
|
if (!TARGET_EXTIMM)
|
| 2233 |
|
|
return 0;
|
| 2234 |
|
|
|
| 2235 |
|
|
switch (c)
|
| 2236 |
|
|
{
|
| 2237 |
|
|
case 's':
|
| 2238 |
|
|
return trunc_int_for_mode (value, SImode) == value;
|
| 2239 |
|
|
|
| 2240 |
|
|
case 'p':
|
| 2241 |
|
|
return value == 0
|
| 2242 |
|
|
|| s390_single_part (GEN_INT (value), DImode, SImode, 0) == 1;
|
| 2243 |
|
|
|
| 2244 |
|
|
case 'n':
|
| 2245 |
|
|
return s390_single_part (GEN_INT (value - 1), DImode, SImode, -1) == 1;
|
| 2246 |
|
|
|
| 2247 |
|
|
default:
|
| 2248 |
|
|
gcc_unreachable ();
|
| 2249 |
|
|
}
|
| 2250 |
|
|
}
|
| 2251 |
|
|
|
| 2252 |
|
|
|
| 2253 |
|
|
/* Evaluates constraint strings starting with letter N. Parameter STR
|
| 2254 |
|
|
contains the letters following letter "N" in the constraint string.
|
| 2255 |
|
|
Returns true if VALUE matches the constraint. */
|
| 2256 |
|
|
|
| 2257 |
|
|
int
|
| 2258 |
|
|
s390_N_constraint_str (const char *str, HOST_WIDE_INT value)
|
| 2259 |
|
|
{
|
| 2260 |
|
|
enum machine_mode mode, part_mode;
|
| 2261 |
|
|
int def;
|
| 2262 |
|
|
int part, part_goal;
|
| 2263 |
|
|
|
| 2264 |
|
|
|
| 2265 |
|
|
if (str[0] == 'x')
|
| 2266 |
|
|
part_goal = -1;
|
| 2267 |
|
|
else
|
| 2268 |
|
|
part_goal = str[0] - '0';
|
| 2269 |
|
|
|
| 2270 |
|
|
switch (str[1])
|
| 2271 |
|
|
{
|
| 2272 |
|
|
case 'Q':
|
| 2273 |
|
|
part_mode = QImode;
|
| 2274 |
|
|
break;
|
| 2275 |
|
|
case 'H':
|
| 2276 |
|
|
part_mode = HImode;
|
| 2277 |
|
|
break;
|
| 2278 |
|
|
case 'S':
|
| 2279 |
|
|
part_mode = SImode;
|
| 2280 |
|
|
break;
|
| 2281 |
|
|
default:
|
| 2282 |
|
|
return 0;
|
| 2283 |
|
|
}
|
| 2284 |
|
|
|
| 2285 |
|
|
switch (str[2])
|
| 2286 |
|
|
{
|
| 2287 |
|
|
case 'H':
|
| 2288 |
|
|
mode = HImode;
|
| 2289 |
|
|
break;
|
| 2290 |
|
|
case 'S':
|
| 2291 |
|
|
mode = SImode;
|
| 2292 |
|
|
break;
|
| 2293 |
|
|
case 'D':
|
| 2294 |
|
|
mode = DImode;
|
| 2295 |
|
|
break;
|
| 2296 |
|
|
default:
|
| 2297 |
|
|
return 0;
|
| 2298 |
|
|
}
|
| 2299 |
|
|
|
| 2300 |
|
|
switch (str[3])
|
| 2301 |
|
|
{
|
| 2302 |
|
|
case '0':
|
| 2303 |
|
|
def = 0;
|
| 2304 |
|
|
break;
|
| 2305 |
|
|
case 'F':
|
| 2306 |
|
|
def = -1;
|
| 2307 |
|
|
break;
|
| 2308 |
|
|
default:
|
| 2309 |
|
|
return 0;
|
| 2310 |
|
|
}
|
| 2311 |
|
|
|
| 2312 |
|
|
if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (part_mode))
|
| 2313 |
|
|
return 0;
|
| 2314 |
|
|
|
| 2315 |
|
|
part = s390_single_part (GEN_INT (value), mode, part_mode, def);
|
| 2316 |
|
|
if (part < 0)
|
| 2317 |
|
|
return 0;
|
| 2318 |
|
|
if (part_goal != -1 && part_goal != part)
|
| 2319 |
|
|
return 0;
|
| 2320 |
|
|
|
| 2321 |
|
|
return 1;
|
| 2322 |
|
|
}
|
| 2323 |
|
|
|
| 2324 |
|
|
|
| 2325 |
|
|
/* Returns true if the input parameter VALUE is a float zero. */
|
| 2326 |
|
|
|
| 2327 |
|
|
int
|
| 2328 |
|
|
s390_float_const_zero_p (rtx value)
|
| 2329 |
|
|
{
|
| 2330 |
|
|
return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT
|
| 2331 |
|
|
&& value == CONST0_RTX (GET_MODE (value)));
|
| 2332 |
|
|
}
|
| 2333 |
|
|
|
| 2334 |
|
|
|
| 2335 |
|
|
/* Compute a (partial) cost for rtx X. Return true if the complete
|
| 2336 |
|
|
cost has been computed, and false if subexpressions should be
|
| 2337 |
|
|
scanned. In either case, *TOTAL contains the cost result.
|
| 2338 |
|
|
CODE contains GET_CODE (x), OUTER_CODE contains the code
|
| 2339 |
|
|
of the superexpression of x. */
|
| 2340 |
|
|
|
| 2341 |
|
|
static bool
|
| 2342 |
|
|
s390_rtx_costs (rtx x, int code, int outer_code, int *total,
|
| 2343 |
|
|
bool speed ATTRIBUTE_UNUSED)
|
| 2344 |
|
|
{
|
| 2345 |
|
|
switch (code)
|
| 2346 |
|
|
{
|
| 2347 |
|
|
case CONST:
|
| 2348 |
|
|
case CONST_INT:
|
| 2349 |
|
|
case LABEL_REF:
|
| 2350 |
|
|
case SYMBOL_REF:
|
| 2351 |
|
|
case CONST_DOUBLE:
|
| 2352 |
|
|
case MEM:
|
| 2353 |
|
|
*total = 0;
|
| 2354 |
|
|
return true;
|
| 2355 |
|
|
|
| 2356 |
|
|
case ASHIFT:
|
| 2357 |
|
|
case ASHIFTRT:
|
| 2358 |
|
|
case LSHIFTRT:
|
| 2359 |
|
|
case ROTATE:
|
| 2360 |
|
|
case ROTATERT:
|
| 2361 |
|
|
case AND:
|
| 2362 |
|
|
case IOR:
|
| 2363 |
|
|
case XOR:
|
| 2364 |
|
|
case NEG:
|
| 2365 |
|
|
case NOT:
|
| 2366 |
|
|
*total = COSTS_N_INSNS (1);
|
| 2367 |
|
|
return false;
|
| 2368 |
|
|
|
| 2369 |
|
|
case PLUS:
|
| 2370 |
|
|
case MINUS:
|
| 2371 |
|
|
/* Check for multiply and add. */
|
| 2372 |
|
|
if ((GET_MODE (x) == DFmode || GET_MODE (x) == SFmode)
|
| 2373 |
|
|
&& GET_CODE (XEXP (x, 0)) == MULT
|
| 2374 |
|
|
&& TARGET_HARD_FLOAT && TARGET_FUSED_MADD)
|
| 2375 |
|
|
{
|
| 2376 |
|
|
/* This is the multiply and add case. */
|
| 2377 |
|
|
if (GET_MODE (x) == DFmode)
|
| 2378 |
|
|
*total = s390_cost->madbr;
|
| 2379 |
|
|
else
|
| 2380 |
|
|
*total = s390_cost->maebr;
|
| 2381 |
|
|
*total += (rtx_cost (XEXP (XEXP (x, 0), 0), MULT, speed)
|
| 2382 |
|
|
+ rtx_cost (XEXP (XEXP (x, 0), 1), MULT, speed)
|
| 2383 |
|
|
+ rtx_cost (XEXP (x, 1), (enum rtx_code) code, speed));
|
| 2384 |
|
|
return true; /* Do not do an additional recursive descent. */
|
| 2385 |
|
|
}
|
| 2386 |
|
|
*total = COSTS_N_INSNS (1);
|
| 2387 |
|
|
return false;
|
| 2388 |
|
|
|
| 2389 |
|
|
case MULT:
|
| 2390 |
|
|
switch (GET_MODE (x))
|
| 2391 |
|
|
{
|
| 2392 |
|
|
case SImode:
|
| 2393 |
|
|
{
|
| 2394 |
|
|
rtx left = XEXP (x, 0);
|
| 2395 |
|
|
rtx right = XEXP (x, 1);
|
| 2396 |
|
|
if (GET_CODE (right) == CONST_INT
|
| 2397 |
|
|
&& CONST_OK_FOR_K (INTVAL (right)))
|
| 2398 |
|
|
*total = s390_cost->mhi;
|
| 2399 |
|
|
else if (GET_CODE (left) == SIGN_EXTEND)
|
| 2400 |
|
|
*total = s390_cost->mh;
|
| 2401 |
|
|
else
|
| 2402 |
|
|
*total = s390_cost->ms; /* msr, ms, msy */
|
| 2403 |
|
|
break;
|
| 2404 |
|
|
}
|
| 2405 |
|
|
case DImode:
|
| 2406 |
|
|
{
|
| 2407 |
|
|
rtx left = XEXP (x, 0);
|
| 2408 |
|
|
rtx right = XEXP (x, 1);
|
| 2409 |
|
|
if (TARGET_64BIT)
|
| 2410 |
|
|
{
|
| 2411 |
|
|
if (GET_CODE (right) == CONST_INT
|
| 2412 |
|
|
&& CONST_OK_FOR_K (INTVAL (right)))
|
| 2413 |
|
|
*total = s390_cost->mghi;
|
| 2414 |
|
|
else if (GET_CODE (left) == SIGN_EXTEND)
|
| 2415 |
|
|
*total = s390_cost->msgf;
|
| 2416 |
|
|
else
|
| 2417 |
|
|
*total = s390_cost->msg; /* msgr, msg */
|
| 2418 |
|
|
}
|
| 2419 |
|
|
else /* TARGET_31BIT */
|
| 2420 |
|
|
{
|
| 2421 |
|
|
if (GET_CODE (left) == SIGN_EXTEND
|
| 2422 |
|
|
&& GET_CODE (right) == SIGN_EXTEND)
|
| 2423 |
|
|
/* mulsidi case: mr, m */
|
| 2424 |
|
|
*total = s390_cost->m;
|
| 2425 |
|
|
else if (GET_CODE (left) == ZERO_EXTEND
|
| 2426 |
|
|
&& GET_CODE (right) == ZERO_EXTEND
|
| 2427 |
|
|
&& TARGET_CPU_ZARCH)
|
| 2428 |
|
|
/* umulsidi case: ml, mlr */
|
| 2429 |
|
|
*total = s390_cost->ml;
|
| 2430 |
|
|
else
|
| 2431 |
|
|
/* Complex calculation is required. */
|
| 2432 |
|
|
*total = COSTS_N_INSNS (40);
|
| 2433 |
|
|
}
|
| 2434 |
|
|
break;
|
| 2435 |
|
|
}
|
| 2436 |
|
|
case SFmode:
|
| 2437 |
|
|
case DFmode:
|
| 2438 |
|
|
*total = s390_cost->mult_df;
|
| 2439 |
|
|
break;
|
| 2440 |
|
|
case TFmode:
|
| 2441 |
|
|
*total = s390_cost->mxbr;
|
| 2442 |
|
|
break;
|
| 2443 |
|
|
default:
|
| 2444 |
|
|
return false;
|
| 2445 |
|
|
}
|
| 2446 |
|
|
return false;
|
| 2447 |
|
|
|
| 2448 |
|
|
case UDIV:
|
| 2449 |
|
|
case UMOD:
|
| 2450 |
|
|
if (GET_MODE (x) == TImode) /* 128 bit division */
|
| 2451 |
|
|
*total = s390_cost->dlgr;
|
| 2452 |
|
|
else if (GET_MODE (x) == DImode)
|
| 2453 |
|
|
{
|
| 2454 |
|
|
rtx right = XEXP (x, 1);
|
| 2455 |
|
|
if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */
|
| 2456 |
|
|
*total = s390_cost->dlr;
|
| 2457 |
|
|
else /* 64 by 64 bit division */
|
| 2458 |
|
|
*total = s390_cost->dlgr;
|
| 2459 |
|
|
}
|
| 2460 |
|
|
else if (GET_MODE (x) == SImode) /* 32 bit division */
|
| 2461 |
|
|
*total = s390_cost->dlr;
|
| 2462 |
|
|
return false;
|
| 2463 |
|
|
|
| 2464 |
|
|
case DIV:
|
| 2465 |
|
|
case MOD:
|
| 2466 |
|
|
if (GET_MODE (x) == DImode)
|
| 2467 |
|
|
{
|
| 2468 |
|
|
rtx right = XEXP (x, 1);
|
| 2469 |
|
|
if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */
|
| 2470 |
|
|
if (TARGET_64BIT)
|
| 2471 |
|
|
*total = s390_cost->dsgfr;
|
| 2472 |
|
|
else
|
| 2473 |
|
|
*total = s390_cost->dr;
|
| 2474 |
|
|
else /* 64 by 64 bit division */
|
| 2475 |
|
|
*total = s390_cost->dsgr;
|
| 2476 |
|
|
}
|
| 2477 |
|
|
else if (GET_MODE (x) == SImode) /* 32 bit division */
|
| 2478 |
|
|
*total = s390_cost->dlr;
|
| 2479 |
|
|
else if (GET_MODE (x) == SFmode)
|
| 2480 |
|
|
{
|
| 2481 |
|
|
*total = s390_cost->debr;
|
| 2482 |
|
|
}
|
| 2483 |
|
|
else if (GET_MODE (x) == DFmode)
|
| 2484 |
|
|
{
|
| 2485 |
|
|
*total = s390_cost->ddbr;
|
| 2486 |
|
|
}
|
| 2487 |
|
|
else if (GET_MODE (x) == TFmode)
|
| 2488 |
|
|
{
|
| 2489 |
|
|
*total = s390_cost->dxbr;
|
| 2490 |
|
|
}
|
| 2491 |
|
|
return false;
|
| 2492 |
|
|
|
| 2493 |
|
|
case SQRT:
|
| 2494 |
|
|
if (GET_MODE (x) == SFmode)
|
| 2495 |
|
|
*total = s390_cost->sqebr;
|
| 2496 |
|
|
else if (GET_MODE (x) == DFmode)
|
| 2497 |
|
|
*total = s390_cost->sqdbr;
|
| 2498 |
|
|
else /* TFmode */
|
| 2499 |
|
|
*total = s390_cost->sqxbr;
|
| 2500 |
|
|
return false;
|
| 2501 |
|
|
|
| 2502 |
|
|
case SIGN_EXTEND:
|
| 2503 |
|
|
case ZERO_EXTEND:
|
| 2504 |
|
|
if (outer_code == MULT || outer_code == DIV || outer_code == MOD
|
| 2505 |
|
|
|| outer_code == PLUS || outer_code == MINUS
|
| 2506 |
|
|
|| outer_code == COMPARE)
|
| 2507 |
|
|
*total = 0;
|
| 2508 |
|
|
return false;
|
| 2509 |
|
|
|
| 2510 |
|
|
case COMPARE:
|
| 2511 |
|
|
*total = COSTS_N_INSNS (1);
|
| 2512 |
|
|
if (GET_CODE (XEXP (x, 0)) == AND
|
| 2513 |
|
|
&& GET_CODE (XEXP (x, 1)) == CONST_INT
|
| 2514 |
|
|
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
|
| 2515 |
|
|
{
|
| 2516 |
|
|
rtx op0 = XEXP (XEXP (x, 0), 0);
|
| 2517 |
|
|
rtx op1 = XEXP (XEXP (x, 0), 1);
|
| 2518 |
|
|
rtx op2 = XEXP (x, 1);
|
| 2519 |
|
|
|
| 2520 |
|
|
if (memory_operand (op0, GET_MODE (op0))
|
| 2521 |
|
|
&& s390_tm_ccmode (op1, op2, 0) != VOIDmode)
|
| 2522 |
|
|
return true;
|
| 2523 |
|
|
if (register_operand (op0, GET_MODE (op0))
|
| 2524 |
|
|
&& s390_tm_ccmode (op1, op2, 1) != VOIDmode)
|
| 2525 |
|
|
return true;
|
| 2526 |
|
|
}
|
| 2527 |
|
|
return false;
|
| 2528 |
|
|
|
| 2529 |
|
|
default:
|
| 2530 |
|
|
return false;
|
| 2531 |
|
|
}
|
| 2532 |
|
|
}
|
| 2533 |
|
|
|
| 2534 |
|
|
/* Return the cost of an address rtx ADDR. */
|
| 2535 |
|
|
|
| 2536 |
|
|
static int
|
| 2537 |
|
|
s390_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
|
| 2538 |
|
|
{
|
| 2539 |
|
|
struct s390_address ad;
|
| 2540 |
|
|
if (!s390_decompose_address (addr, &ad))
|
| 2541 |
|
|
return 1000;
|
| 2542 |
|
|
|
| 2543 |
|
|
return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1);
|
| 2544 |
|
|
}
|
| 2545 |
|
|
|
| 2546 |
|
|
/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
|
| 2547 |
|
|
otherwise return 0. */
|
| 2548 |
|
|
|
| 2549 |
|
|
int
|
| 2550 |
|
|
tls_symbolic_operand (rtx op)
|
| 2551 |
|
|
{
|
| 2552 |
|
|
if (GET_CODE (op) != SYMBOL_REF)
|
| 2553 |
|
|
return 0;
|
| 2554 |
|
|
return SYMBOL_REF_TLS_MODEL (op);
|
| 2555 |
|
|
}
|
| 2556 |
|
|
|
| 2557 |
|
|
/* Split DImode access register reference REG (on 64-bit) into its constituent
|
| 2558 |
|
|
low and high parts, and store them into LO and HI. Note that gen_lowpart/
|
| 2559 |
|
|
gen_highpart cannot be used as they assume all registers are word-sized,
|
| 2560 |
|
|
while our access registers have only half that size. */
|
| 2561 |
|
|
|
| 2562 |
|
|
void
|
| 2563 |
|
|
s390_split_access_reg (rtx reg, rtx *lo, rtx *hi)
|
| 2564 |
|
|
{
|
| 2565 |
|
|
gcc_assert (TARGET_64BIT);
|
| 2566 |
|
|
gcc_assert (ACCESS_REG_P (reg));
|
| 2567 |
|
|
gcc_assert (GET_MODE (reg) == DImode);
|
| 2568 |
|
|
gcc_assert (!(REGNO (reg) & 1));
|
| 2569 |
|
|
|
| 2570 |
|
|
*lo = gen_rtx_REG (SImode, REGNO (reg) + 1);
|
| 2571 |
|
|
*hi = gen_rtx_REG (SImode, REGNO (reg));
|
| 2572 |
|
|
}
|
| 2573 |
|
|
|
| 2574 |
|
|
/* Return true if OP contains a symbol reference */
|
| 2575 |
|
|
|
| 2576 |
|
|
bool
|
| 2577 |
|
|
symbolic_reference_mentioned_p (rtx op)
|
| 2578 |
|
|
{
|
| 2579 |
|
|
const char *fmt;
|
| 2580 |
|
|
int i;
|
| 2581 |
|
|
|
| 2582 |
|
|
if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
|
| 2583 |
|
|
return 1;
|
| 2584 |
|
|
|
| 2585 |
|
|
fmt = GET_RTX_FORMAT (GET_CODE (op));
|
| 2586 |
|
|
for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
|
| 2587 |
|
|
{
|
| 2588 |
|
|
if (fmt[i] == 'E')
|
| 2589 |
|
|
{
|
| 2590 |
|
|
int j;
|
| 2591 |
|
|
|
| 2592 |
|
|
for (j = XVECLEN (op, i) - 1; j >= 0; j--)
|
| 2593 |
|
|
if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
|
| 2594 |
|
|
return 1;
|
| 2595 |
|
|
}
|
| 2596 |
|
|
|
| 2597 |
|
|
else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
|
| 2598 |
|
|
return 1;
|
| 2599 |
|
|
}
|
| 2600 |
|
|
|
| 2601 |
|
|
return 0;
|
| 2602 |
|
|
}
|
| 2603 |
|
|
|
| 2604 |
|
|
/* Return true if OP contains a reference to a thread-local symbol. */
|
| 2605 |
|
|
|
| 2606 |
|
|
bool
|
| 2607 |
|
|
tls_symbolic_reference_mentioned_p (rtx op)
|
| 2608 |
|
|
{
|
| 2609 |
|
|
const char *fmt;
|
| 2610 |
|
|
int i;
|
| 2611 |
|
|
|
| 2612 |
|
|
if (GET_CODE (op) == SYMBOL_REF)
|
| 2613 |
|
|
return tls_symbolic_operand (op);
|
| 2614 |
|
|
|
| 2615 |
|
|
fmt = GET_RTX_FORMAT (GET_CODE (op));
|
| 2616 |
|
|
for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
|
| 2617 |
|
|
{
|
| 2618 |
|
|
if (fmt[i] == 'E')
|
| 2619 |
|
|
{
|
| 2620 |
|
|
int j;
|
| 2621 |
|
|
|
| 2622 |
|
|
for (j = XVECLEN (op, i) - 1; j >= 0; j--)
|
| 2623 |
|
|
if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
|
| 2624 |
|
|
return true;
|
| 2625 |
|
|
}
|
| 2626 |
|
|
|
| 2627 |
|
|
else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i)))
|
| 2628 |
|
|
return true;
|
| 2629 |
|
|
}
|
| 2630 |
|
|
|
| 2631 |
|
|
return false;
|
| 2632 |
|
|
}
|
| 2633 |
|
|
|
| 2634 |
|
|
|
| 2635 |
|
|
/* Return true if OP is a legitimate general operand when
|
| 2636 |
|
|
generating PIC code. It is given that flag_pic is on
|
| 2637 |
|
|
and that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */
|
| 2638 |
|
|
|
| 2639 |
|
|
int
|
| 2640 |
|
|
legitimate_pic_operand_p (rtx op)
|
| 2641 |
|
|
{
|
| 2642 |
|
|
/* Accept all non-symbolic constants. */
|
| 2643 |
|
|
if (!SYMBOLIC_CONST (op))
|
| 2644 |
|
|
return 1;
|
| 2645 |
|
|
|
| 2646 |
|
|
/* Reject everything else; must be handled
|
| 2647 |
|
|
via emit_symbolic_move. */
|
| 2648 |
|
|
return 0;
|
| 2649 |
|
|
}
|
| 2650 |
|
|
|
| 2651 |
|
|
/* Returns true if the constant value OP is a legitimate general operand.
|
| 2652 |
|
|
It is given that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */
|
| 2653 |
|
|
|
| 2654 |
|
|
int
|
| 2655 |
|
|
legitimate_constant_p (rtx op)
|
| 2656 |
|
|
{
|
| 2657 |
|
|
/* Accept all non-symbolic constants. */
|
| 2658 |
|
|
if (!SYMBOLIC_CONST (op))
|
| 2659 |
|
|
return 1;
|
| 2660 |
|
|
|
| 2661 |
|
|
/* Accept immediate LARL operands. */
|
| 2662 |
|
|
if (TARGET_CPU_ZARCH && larl_operand (op, VOIDmode))
|
| 2663 |
|
|
return 1;
|
| 2664 |
|
|
|
| 2665 |
|
|
/* Thread-local symbols are never legal constants. This is
|
| 2666 |
|
|
so that emit_call knows that computing such addresses
|
| 2667 |
|
|
might require a function call. */
|
| 2668 |
|
|
if (TLS_SYMBOLIC_CONST (op))
|
| 2669 |
|
|
return 0;
|
| 2670 |
|
|
|
| 2671 |
|
|
/* In the PIC case, symbolic constants must *not* be
|
| 2672 |
|
|
forced into the literal pool. We accept them here,
|
| 2673 |
|
|
so that they will be handled by emit_symbolic_move. */
|
| 2674 |
|
|
if (flag_pic)
|
| 2675 |
|
|
return 1;
|
| 2676 |
|
|
|
| 2677 |
|
|
/* All remaining non-PIC symbolic constants are
|
| 2678 |
|
|
forced into the literal pool. */
|
| 2679 |
|
|
return 0;
|
| 2680 |
|
|
}
|
| 2681 |
|
|
|
| 2682 |
|
|
/* Determine if it's legal to put X into the constant pool. This
|
| 2683 |
|
|
is not possible if X contains the address of a symbol that is
|
| 2684 |
|
|
not constant (TLS) or not known at final link time (PIC). */
|
| 2685 |
|
|
|
| 2686 |
|
|
static bool
|
| 2687 |
|
|
s390_cannot_force_const_mem (rtx x)
|
| 2688 |
|
|
{
|
| 2689 |
|
|
switch (GET_CODE (x))
|
| 2690 |
|
|
{
|
| 2691 |
|
|
case CONST_INT:
|
| 2692 |
|
|
case CONST_DOUBLE:
|
| 2693 |
|
|
/* Accept all non-symbolic constants. */
|
| 2694 |
|
|
return false;
|
| 2695 |
|
|
|
| 2696 |
|
|
case LABEL_REF:
|
| 2697 |
|
|
/* Labels are OK iff we are non-PIC. */
|
| 2698 |
|
|
return flag_pic != 0;
|
| 2699 |
|
|
|
| 2700 |
|
|
case SYMBOL_REF:
|
| 2701 |
|
|
/* 'Naked' TLS symbol references are never OK,
|
| 2702 |
|
|
non-TLS symbols are OK iff we are non-PIC. */
|
| 2703 |
|
|
if (tls_symbolic_operand (x))
|
| 2704 |
|
|
return true;
|
| 2705 |
|
|
else
|
| 2706 |
|
|
return flag_pic != 0;
|
| 2707 |
|
|
|
| 2708 |
|
|
case CONST:
|
| 2709 |
|
|
return s390_cannot_force_const_mem (XEXP (x, 0));
|
| 2710 |
|
|
case PLUS:
|
| 2711 |
|
|
case MINUS:
|
| 2712 |
|
|
return s390_cannot_force_const_mem (XEXP (x, 0))
|
| 2713 |
|
|
|| s390_cannot_force_const_mem (XEXP (x, 1));
|
| 2714 |
|
|
|
| 2715 |
|
|
case UNSPEC:
|
| 2716 |
|
|
switch (XINT (x, 1))
|
| 2717 |
|
|
{
|
| 2718 |
|
|
/* Only lt-relative or GOT-relative UNSPECs are OK. */
|
| 2719 |
|
|
case UNSPEC_LTREL_OFFSET:
|
| 2720 |
|
|
case UNSPEC_GOT:
|
| 2721 |
|
|
case UNSPEC_GOTOFF:
|
| 2722 |
|
|
case UNSPEC_PLTOFF:
|
| 2723 |
|
|
case UNSPEC_TLSGD:
|
| 2724 |
|
|
case UNSPEC_TLSLDM:
|
| 2725 |
|
|
case UNSPEC_NTPOFF:
|
| 2726 |
|
|
case UNSPEC_DTPOFF:
|
| 2727 |
|
|
case UNSPEC_GOTNTPOFF:
|
| 2728 |
|
|
case UNSPEC_INDNTPOFF:
|
| 2729 |
|
|
return false;
|
| 2730 |
|
|
|
| 2731 |
|
|
/* If the literal pool shares the code section, be put
|
| 2732 |
|
|
execute template placeholders into the pool as well. */
|
| 2733 |
|
|
case UNSPEC_INSN:
|
| 2734 |
|
|
return TARGET_CPU_ZARCH;
|
| 2735 |
|
|
|
| 2736 |
|
|
default:
|
| 2737 |
|
|
return true;
|
| 2738 |
|
|
}
|
| 2739 |
|
|
break;
|
| 2740 |
|
|
|
| 2741 |
|
|
default:
|
| 2742 |
|
|
gcc_unreachable ();
|
| 2743 |
|
|
}
|
| 2744 |
|
|
}
|
| 2745 |
|
|
|
| 2746 |
|
|
/* Returns true if the constant value OP is a legitimate general
|
| 2747 |
|
|
operand during and after reload. The difference to
|
| 2748 |
|
|
legitimate_constant_p is that this function will not accept
|
| 2749 |
|
|
a constant that would need to be forced to the literal pool
|
| 2750 |
|
|
before it can be used as operand. */
|
| 2751 |
|
|
|
| 2752 |
|
|
bool
|
| 2753 |
|
|
legitimate_reload_constant_p (rtx op)
|
| 2754 |
|
|
{
|
| 2755 |
|
|
/* Accept la(y) operands. */
|
| 2756 |
|
|
if (GET_CODE (op) == CONST_INT
|
| 2757 |
|
|
&& DISP_IN_RANGE (INTVAL (op)))
|
| 2758 |
|
|
return true;
|
| 2759 |
|
|
|
| 2760 |
|
|
/* Accept l(g)hi/l(g)fi operands. */
|
| 2761 |
|
|
if (GET_CODE (op) == CONST_INT
|
| 2762 |
|
|
&& (CONST_OK_FOR_K (INTVAL (op)) || CONST_OK_FOR_Os (INTVAL (op))))
|
| 2763 |
|
|
return true;
|
| 2764 |
|
|
|
| 2765 |
|
|
/* Accept lliXX operands. */
|
| 2766 |
|
|
if (TARGET_ZARCH
|
| 2767 |
|
|
&& GET_CODE (op) == CONST_INT
|
| 2768 |
|
|
&& trunc_int_for_mode (INTVAL (op), word_mode) == INTVAL (op)
|
| 2769 |
|
|
&& s390_single_part (op, word_mode, HImode, 0) >= 0)
|
| 2770 |
|
|
return true;
|
| 2771 |
|
|
|
| 2772 |
|
|
if (TARGET_EXTIMM
|
| 2773 |
|
|
&& GET_CODE (op) == CONST_INT
|
| 2774 |
|
|
&& trunc_int_for_mode (INTVAL (op), word_mode) == INTVAL (op)
|
| 2775 |
|
|
&& s390_single_part (op, word_mode, SImode, 0) >= 0)
|
| 2776 |
|
|
return true;
|
| 2777 |
|
|
|
| 2778 |
|
|
/* Accept larl operands. */
|
| 2779 |
|
|
if (TARGET_CPU_ZARCH
|
| 2780 |
|
|
&& larl_operand (op, VOIDmode))
|
| 2781 |
|
|
return true;
|
| 2782 |
|
|
|
| 2783 |
|
|
/* Accept double-word operands that can be split. */
|
| 2784 |
|
|
if (GET_CODE (op) == CONST_INT
|
| 2785 |
|
|
&& trunc_int_for_mode (INTVAL (op), word_mode) != INTVAL (op))
|
| 2786 |
|
|
{
|
| 2787 |
|
|
enum machine_mode dword_mode = word_mode == SImode ? DImode : TImode;
|
| 2788 |
|
|
rtx hi = operand_subword (op, 0, 0, dword_mode);
|
| 2789 |
|
|
rtx lo = operand_subword (op, 1, 0, dword_mode);
|
| 2790 |
|
|
return legitimate_reload_constant_p (hi)
|
| 2791 |
|
|
&& legitimate_reload_constant_p (lo);
|
| 2792 |
|
|
}
|
| 2793 |
|
|
|
| 2794 |
|
|
/* Everything else cannot be handled without reload. */
|
| 2795 |
|
|
return false;
|
| 2796 |
|
|
}
|
| 2797 |
|
|
|
| 2798 |
|
|
/* Given an rtx OP being reloaded into a reg required to be in class RCLASS,
|
| 2799 |
|
|
return the class of reg to actually use. */
|
| 2800 |
|
|
|
| 2801 |
|
|
enum reg_class
|
| 2802 |
|
|
s390_preferred_reload_class (rtx op, enum reg_class rclass)
|
| 2803 |
|
|
{
|
| 2804 |
|
|
switch (GET_CODE (op))
|
| 2805 |
|
|
{
|
| 2806 |
|
|
/* Constants we cannot reload must be forced into the
|
| 2807 |
|
|
literal pool. */
|
| 2808 |
|
|
|
| 2809 |
|
|
case CONST_DOUBLE:
|
| 2810 |
|
|
case CONST_INT:
|
| 2811 |
|
|
if (legitimate_reload_constant_p (op))
|
| 2812 |
|
|
return rclass;
|
| 2813 |
|
|
else
|
| 2814 |
|
|
return NO_REGS;
|
| 2815 |
|
|
|
| 2816 |
|
|
/* If a symbolic constant or a PLUS is reloaded,
|
| 2817 |
|
|
it is most likely being used as an address, so
|
| 2818 |
|
|
prefer ADDR_REGS. If 'class' is not a superset
|
| 2819 |
|
|
of ADDR_REGS, e.g. FP_REGS, reject this reload. */
|
| 2820 |
|
|
case PLUS:
|
| 2821 |
|
|
case LABEL_REF:
|
| 2822 |
|
|
case SYMBOL_REF:
|
| 2823 |
|
|
case CONST:
|
| 2824 |
|
|
if (reg_class_subset_p (ADDR_REGS, rclass))
|
| 2825 |
|
|
return ADDR_REGS;
|
| 2826 |
|
|
else
|
| 2827 |
|
|
return NO_REGS;
|
| 2828 |
|
|
|
| 2829 |
|
|
default:
|
| 2830 |
|
|
break;
|
| 2831 |
|
|
}
|
| 2832 |
|
|
|
| 2833 |
|
|
return rclass;
|
| 2834 |
|
|
}
|
| 2835 |
|
|
|
| 2836 |
|
|
/* Return true if ADDR is SYMBOL_REF + addend with addend being a
|
| 2837 |
|
|
multiple of ALIGNMENT and the SYMBOL_REF being naturally
|
| 2838 |
|
|
aligned. */
|
| 2839 |
|
|
|
| 2840 |
|
|
bool
|
| 2841 |
|
|
s390_check_symref_alignment (rtx addr, HOST_WIDE_INT alignment)
|
| 2842 |
|
|
{
|
| 2843 |
|
|
HOST_WIDE_INT addend;
|
| 2844 |
|
|
rtx symref;
|
| 2845 |
|
|
|
| 2846 |
|
|
if (!s390_symref_operand_p (addr, &symref, &addend))
|
| 2847 |
|
|
return false;
|
| 2848 |
|
|
|
| 2849 |
|
|
return (!SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref)
|
| 2850 |
|
|
&& !(addend & (alignment - 1)));
|
| 2851 |
|
|
}
|
| 2852 |
|
|
|
| 2853 |
|
|
/* ADDR is moved into REG using larl. If ADDR isn't a valid larl
|
| 2854 |
|
|
operand SCRATCH is used to reload the even part of the address and
|
| 2855 |
|
|
adding one. */
|
| 2856 |
|
|
|
| 2857 |
|
|
void
|
| 2858 |
|
|
s390_reload_larl_operand (rtx reg, rtx addr, rtx scratch)
|
| 2859 |
|
|
{
|
| 2860 |
|
|
HOST_WIDE_INT addend;
|
| 2861 |
|
|
rtx symref;
|
| 2862 |
|
|
|
| 2863 |
|
|
if (!s390_symref_operand_p (addr, &symref, &addend))
|
| 2864 |
|
|
gcc_unreachable ();
|
| 2865 |
|
|
|
| 2866 |
|
|
if (!(addend & 1))
|
| 2867 |
|
|
/* Easy case. The addend is even so larl will do fine. */
|
| 2868 |
|
|
emit_move_insn (reg, addr);
|
| 2869 |
|
|
else
|
| 2870 |
|
|
{
|
| 2871 |
|
|
/* We can leave the scratch register untouched if the target
|
| 2872 |
|
|
register is a valid base register. */
|
| 2873 |
|
|
if (REGNO (reg) < FIRST_PSEUDO_REGISTER
|
| 2874 |
|
|
&& REGNO_REG_CLASS (REGNO (reg)) == ADDR_REGS)
|
| 2875 |
|
|
scratch = reg;
|
| 2876 |
|
|
|
| 2877 |
|
|
gcc_assert (REGNO (scratch) < FIRST_PSEUDO_REGISTER);
|
| 2878 |
|
|
gcc_assert (REGNO_REG_CLASS (REGNO (scratch)) == ADDR_REGS);
|
| 2879 |
|
|
|
| 2880 |
|
|
if (addend != 1)
|
| 2881 |
|
|
emit_move_insn (scratch,
|
| 2882 |
|
|
gen_rtx_CONST (Pmode,
|
| 2883 |
|
|
gen_rtx_PLUS (Pmode, symref,
|
| 2884 |
|
|
GEN_INT (addend - 1))));
|
| 2885 |
|
|
else
|
| 2886 |
|
|
emit_move_insn (scratch, symref);
|
| 2887 |
|
|
|
| 2888 |
|
|
/* Increment the address using la in order to avoid clobbering cc. */
|
| 2889 |
|
|
emit_move_insn (reg, gen_rtx_PLUS (Pmode, scratch, const1_rtx));
|
| 2890 |
|
|
}
|
| 2891 |
|
|
}
|
| 2892 |
|
|
|
| 2893 |
|
|
/* Generate what is necessary to move between REG and MEM using
|
| 2894 |
|
|
SCRATCH. The direction is given by TOMEM. */
|
| 2895 |
|
|
|
| 2896 |
|
|
void
|
| 2897 |
|
|
s390_reload_symref_address (rtx reg, rtx mem, rtx scratch, bool tomem)
|
| 2898 |
|
|
{
|
| 2899 |
|
|
/* Reload might have pulled a constant out of the literal pool.
|
| 2900 |
|
|
Force it back in. */
|
| 2901 |
|
|
if (CONST_INT_P (mem) || GET_CODE (mem) == CONST_DOUBLE
|
| 2902 |
|
|
|| GET_CODE (mem) == CONST)
|
| 2903 |
|
|
mem = force_const_mem (GET_MODE (reg), mem);
|
| 2904 |
|
|
|
| 2905 |
|
|
gcc_assert (MEM_P (mem));
|
| 2906 |
|
|
|
| 2907 |
|
|
/* For a load from memory we can leave the scratch register
|
| 2908 |
|
|
untouched if the target register is a valid base register. */
|
| 2909 |
|
|
if (!tomem
|
| 2910 |
|
|
&& REGNO (reg) < FIRST_PSEUDO_REGISTER
|
| 2911 |
|
|
&& REGNO_REG_CLASS (REGNO (reg)) == ADDR_REGS
|
| 2912 |
|
|
&& GET_MODE (reg) == GET_MODE (scratch))
|
| 2913 |
|
|
scratch = reg;
|
| 2914 |
|
|
|
| 2915 |
|
|
/* Load address into scratch register. Since we can't have a
|
| 2916 |
|
|
secondary reload for a secondary reload we have to cover the case
|
| 2917 |
|
|
where larl would need a secondary reload here as well. */
|
| 2918 |
|
|
s390_reload_larl_operand (scratch, XEXP (mem, 0), scratch);
|
| 2919 |
|
|
|
| 2920 |
|
|
/* Now we can use a standard load/store to do the move. */
|
| 2921 |
|
|
if (tomem)
|
| 2922 |
|
|
emit_move_insn (replace_equiv_address (mem, scratch), reg);
|
| 2923 |
|
|
else
|
| 2924 |
|
|
emit_move_insn (reg, replace_equiv_address (mem, scratch));
|
| 2925 |
|
|
}
|
| 2926 |
|
|
|
| 2927 |
|
|
/* Inform reload about cases where moving X with a mode MODE to a register in
|
| 2928 |
|
|
RCLASS requires an extra scratch or immediate register. Return the class
|
| 2929 |
|
|
needed for the immediate register. */
|
| 2930 |
|
|
|
| 2931 |
|
|
static enum reg_class
|
| 2932 |
|
|
s390_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
|
| 2933 |
|
|
enum machine_mode mode, secondary_reload_info *sri)
|
| 2934 |
|
|
{
|
| 2935 |
|
|
/* Intermediate register needed. */
|
| 2936 |
|
|
if (reg_classes_intersect_p (CC_REGS, rclass))
|
| 2937 |
|
|
return GENERAL_REGS;
|
| 2938 |
|
|
|
| 2939 |
|
|
if (TARGET_Z10)
|
| 2940 |
|
|
{
|
| 2941 |
|
|
/* On z10 several optimizer steps may generate larl operands with
|
| 2942 |
|
|
an odd addend. */
|
| 2943 |
|
|
if (in_p
|
| 2944 |
|
|
&& s390_symref_operand_p (x, NULL, NULL)
|
| 2945 |
|
|
&& mode == Pmode
|
| 2946 |
|
|
&& !s390_check_symref_alignment (x, 2))
|
| 2947 |
|
|
sri->icode = ((mode == DImode) ? CODE_FOR_reloaddi_larl_odd_addend_z10
|
| 2948 |
|
|
: CODE_FOR_reloadsi_larl_odd_addend_z10);
|
| 2949 |
|
|
|
| 2950 |
|
|
/* On z10 we need a scratch register when moving QI, TI or floating
|
| 2951 |
|
|
point mode values from or to a memory location with a SYMBOL_REF
|
| 2952 |
|
|
or if the symref addend of a SI or DI move is not aligned to the
|
| 2953 |
|
|
width of the access. */
|
| 2954 |
|
|
if (MEM_P (x)
|
| 2955 |
|
|
&& s390_symref_operand_p (XEXP (x, 0), NULL, NULL)
|
| 2956 |
|
|
&& (mode == QImode || mode == TImode || FLOAT_MODE_P (mode)
|
| 2957 |
|
|
|| (!TARGET_64BIT && mode == DImode)
|
| 2958 |
|
|
|| ((mode == HImode || mode == SImode || mode == DImode)
|
| 2959 |
|
|
&& (!s390_check_symref_alignment (XEXP (x, 0),
|
| 2960 |
|
|
GET_MODE_SIZE (mode))))))
|
| 2961 |
|
|
{
|
| 2962 |
|
|
#define __SECONDARY_RELOAD_CASE(M,m) \
|
| 2963 |
|
|
case M##mode: \
|
| 2964 |
|
|
if (TARGET_64BIT) \
|
| 2965 |
|
|
sri->icode = in_p ? CODE_FOR_reload##m##di_toreg_z10 : \
|
| 2966 |
|
|
CODE_FOR_reload##m##di_tomem_z10; \
|
| 2967 |
|
|
else \
|
| 2968 |
|
|
sri->icode = in_p ? CODE_FOR_reload##m##si_toreg_z10 : \
|
| 2969 |
|
|
CODE_FOR_reload##m##si_tomem_z10; \
|
| 2970 |
|
|
break;
|
| 2971 |
|
|
|
| 2972 |
|
|
switch (GET_MODE (x))
|
| 2973 |
|
|
{
|
| 2974 |
|
|
__SECONDARY_RELOAD_CASE (QI, qi);
|
| 2975 |
|
|
__SECONDARY_RELOAD_CASE (HI, hi);
|
| 2976 |
|
|
__SECONDARY_RELOAD_CASE (SI, si);
|
| 2977 |
|
|
__SECONDARY_RELOAD_CASE (DI, di);
|
| 2978 |
|
|
__SECONDARY_RELOAD_CASE (TI, ti);
|
| 2979 |
|
|
__SECONDARY_RELOAD_CASE (SF, sf);
|
| 2980 |
|
|
__SECONDARY_RELOAD_CASE (DF, df);
|
| 2981 |
|
|
__SECONDARY_RELOAD_CASE (TF, tf);
|
| 2982 |
|
|
__SECONDARY_RELOAD_CASE (SD, sd);
|
| 2983 |
|
|
__SECONDARY_RELOAD_CASE (DD, dd);
|
| 2984 |
|
|
__SECONDARY_RELOAD_CASE (TD, td);
|
| 2985 |
|
|
|
| 2986 |
|
|
default:
|
| 2987 |
|
|
gcc_unreachable ();
|
| 2988 |
|
|
}
|
| 2989 |
|
|
#undef __SECONDARY_RELOAD_CASE
|
| 2990 |
|
|
}
|
| 2991 |
|
|
}
|
| 2992 |
|
|
|
| 2993 |
|
|
/* We need a scratch register when loading a PLUS expression which
|
| 2994 |
|
|
is not a legitimate operand of the LOAD ADDRESS instruction. */
|
| 2995 |
|
|
if (in_p && s390_plus_operand (x, mode))
|
| 2996 |
|
|
sri->icode = (TARGET_64BIT ?
|
| 2997 |
|
|
CODE_FOR_reloaddi_plus : CODE_FOR_reloadsi_plus);
|
| 2998 |
|
|
|
| 2999 |
|
|
/* Performing a multiword move from or to memory we have to make sure the
|
| 3000 |
|
|
second chunk in memory is addressable without causing a displacement
|
| 3001 |
|
|
overflow. If that would be the case we calculate the address in
|
| 3002 |
|
|
a scratch register. */
|
| 3003 |
|
|
if (MEM_P (x)
|
| 3004 |
|
|
&& GET_CODE (XEXP (x, 0)) == PLUS
|
| 3005 |
|
|
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
|
| 3006 |
|
|
&& !DISP_IN_RANGE (INTVAL (XEXP (XEXP (x, 0), 1))
|
| 3007 |
|
|
+ GET_MODE_SIZE (mode) - 1))
|
| 3008 |
|
|
{
|
| 3009 |
|
|
/* For GENERAL_REGS a displacement overflow is no problem if occurring
|
| 3010 |
|
|
in a s_operand address since we may fallback to lm/stm. So we only
|
| 3011 |
|
|
have to care about overflows in the b+i+d case. */
|
| 3012 |
|
|
if ((reg_classes_intersect_p (GENERAL_REGS, rclass)
|
| 3013 |
|
|
&& s390_class_max_nregs (GENERAL_REGS, mode) > 1
|
| 3014 |
|
|
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS)
|
| 3015 |
|
|
/* For FP_REGS no lm/stm is available so this check is triggered
|
| 3016 |
|
|
for displacement overflows in b+i+d and b+d like addresses. */
|
| 3017 |
|
|
|| (reg_classes_intersect_p (FP_REGS, rclass)
|
| 3018 |
|
|
&& s390_class_max_nregs (FP_REGS, mode) > 1))
|
| 3019 |
|
|
{
|
| 3020 |
|
|
if (in_p)
|
| 3021 |
|
|
sri->icode = (TARGET_64BIT ?
|
| 3022 |
|
|
CODE_FOR_reloaddi_nonoffmem_in :
|
| 3023 |
|
|
CODE_FOR_reloadsi_nonoffmem_in);
|
| 3024 |
|
|
else
|
| 3025 |
|
|
sri->icode = (TARGET_64BIT ?
|
| 3026 |
|
|
CODE_FOR_reloaddi_nonoffmem_out :
|
| 3027 |
|
|
CODE_FOR_reloadsi_nonoffmem_out);
|
| 3028 |
|
|
}
|
| 3029 |
|
|
}
|
| 3030 |
|
|
|
| 3031 |
|
|
/* A scratch address register is needed when a symbolic constant is
|
| 3032 |
|
|
copied to r0 compiling with -fPIC. In other cases the target
|
| 3033 |
|
|
register might be used as temporary (see legitimize_pic_address). */
|
| 3034 |
|
|
if (in_p && SYMBOLIC_CONST (x) && flag_pic == 2 && rclass != ADDR_REGS)
|
| 3035 |
|
|
sri->icode = (TARGET_64BIT ?
|
| 3036 |
|
|
CODE_FOR_reloaddi_PIC_addr :
|
| 3037 |
|
|
CODE_FOR_reloadsi_PIC_addr);
|
| 3038 |
|
|
|
| 3039 |
|
|
/* Either scratch or no register needed. */
|
| 3040 |
|
|
return NO_REGS;
|
| 3041 |
|
|
}
|
| 3042 |
|
|
|
| 3043 |
|
|
/* Generate code to load SRC, which is PLUS that is not a
|
| 3044 |
|
|
legitimate operand for the LA instruction, into TARGET.
|
| 3045 |
|
|
SCRATCH may be used as scratch register. */
|
| 3046 |
|
|
|
| 3047 |
|
|
void
|
| 3048 |
|
|
s390_expand_plus_operand (rtx target, rtx src,
|
| 3049 |
|
|
rtx scratch)
|
| 3050 |
|
|
{
|
| 3051 |
|
|
rtx sum1, sum2;
|
| 3052 |
|
|
struct s390_address ad;
|
| 3053 |
|
|
|
| 3054 |
|
|
/* src must be a PLUS; get its two operands. */
|
| 3055 |
|
|
gcc_assert (GET_CODE (src) == PLUS);
|
| 3056 |
|
|
gcc_assert (GET_MODE (src) == Pmode);
|
| 3057 |
|
|
|
| 3058 |
|
|
/* Check if any of the two operands is already scheduled
|
| 3059 |
|
|
for replacement by reload. This can happen e.g. when
|
| 3060 |
|
|
float registers occur in an address. */
|
| 3061 |
|
|
sum1 = find_replacement (&XEXP (src, 0));
|
| 3062 |
|
|
sum2 = find_replacement (&XEXP (src, 1));
|
| 3063 |
|
|
src = gen_rtx_PLUS (Pmode, sum1, sum2);
|
| 3064 |
|
|
|
| 3065 |
|
|
/* If the address is already strictly valid, there's nothing to do. */
|
| 3066 |
|
|
if (!s390_decompose_address (src, &ad)
|
| 3067 |
|
|
|| (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base)))
|
| 3068 |
|
|
|| (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx))))
|
| 3069 |
|
|
{
|
| 3070 |
|
|
/* Otherwise, one of the operands cannot be an address register;
|
| 3071 |
|
|
we reload its value into the scratch register. */
|
| 3072 |
|
|
if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15)
|
| 3073 |
|
|
{
|
| 3074 |
|
|
emit_move_insn (scratch, sum1);
|
| 3075 |
|
|
sum1 = scratch;
|
| 3076 |
|
|
}
|
| 3077 |
|
|
if (true_regnum (sum2) < 1 || true_regnum (sum2) > 15)
|
| 3078 |
|
|
{
|
| 3079 |
|
|
emit_move_insn (scratch, sum2);
|
| 3080 |
|
|
sum2 = scratch;
|
| 3081 |
|
|
}
|
| 3082 |
|
|
|
| 3083 |
|
|
/* According to the way these invalid addresses are generated
|
| 3084 |
|
|
in reload.c, it should never happen (at least on s390) that
|
| 3085 |
|
|
*neither* of the PLUS components, after find_replacements
|
| 3086 |
|
|
was applied, is an address register. */
|
| 3087 |
|
|
if (sum1 == scratch && sum2 == scratch)
|
| 3088 |
|
|
{
|
| 3089 |
|
|
debug_rtx (src);
|
| 3090 |
|
|
gcc_unreachable ();
|
| 3091 |
|
|
}
|
| 3092 |
|
|
|
| 3093 |
|
|
src = gen_rtx_PLUS (Pmode, sum1, sum2);
|
| 3094 |
|
|
}
|
| 3095 |
|
|
|
| 3096 |
|
|
/* Emit the LOAD ADDRESS pattern. Note that reload of PLUS
|
| 3097 |
|
|
is only ever performed on addresses, so we can mark the
|
| 3098 |
|
|
sum as legitimate for LA in any case. */
|
| 3099 |
|
|
s390_load_address (target, src);
|
| 3100 |
|
|
}
|
| 3101 |
|
|
|
| 3102 |
|
|
|
| 3103 |
|
|
/* Return true if ADDR is a valid memory address.
|
| 3104 |
|
|
STRICT specifies whether strict register checking applies. */
|
| 3105 |
|
|
|
| 3106 |
|
|
static bool
|
| 3107 |
|
|
s390_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
|
| 3108 |
|
|
{
|
| 3109 |
|
|
struct s390_address ad;
|
| 3110 |
|
|
|
| 3111 |
|
|
if (TARGET_Z10
|
| 3112 |
|
|
&& larl_operand (addr, VOIDmode)
|
| 3113 |
|
|
&& (mode == VOIDmode
|
| 3114 |
|
|
|| s390_check_symref_alignment (addr, GET_MODE_SIZE (mode))))
|
| 3115 |
|
|
return true;
|
| 3116 |
|
|
|
| 3117 |
|
|
if (!s390_decompose_address (addr, &ad))
|
| 3118 |
|
|
return false;
|
| 3119 |
|
|
|
| 3120 |
|
|
if (strict)
|
| 3121 |
|
|
{
|
| 3122 |
|
|
if (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base)))
|
| 3123 |
|
|
return false;
|
| 3124 |
|
|
|
| 3125 |
|
|
if (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx)))
|
| 3126 |
|
|
return false;
|
| 3127 |
|
|
}
|
| 3128 |
|
|
else
|
| 3129 |
|
|
{
|
| 3130 |
|
|
if (ad.base
|
| 3131 |
|
|
&& !(REGNO (ad.base) >= FIRST_PSEUDO_REGISTER
|
| 3132 |
|
|
|| REGNO_REG_CLASS (REGNO (ad.base)) == ADDR_REGS))
|
| 3133 |
|
|
return false;
|
| 3134 |
|
|
|
| 3135 |
|
|
if (ad.indx
|
| 3136 |
|
|
&& !(REGNO (ad.indx) >= FIRST_PSEUDO_REGISTER
|
| 3137 |
|
|
|| REGNO_REG_CLASS (REGNO (ad.indx)) == ADDR_REGS))
|
| 3138 |
|
|
return false;
|
| 3139 |
|
|
}
|
| 3140 |
|
|
return true;
|
| 3141 |
|
|
}
|
| 3142 |
|
|
|
| 3143 |
|
|
/* Return true if OP is a valid operand for the LA instruction.
|
| 3144 |
|
|
In 31-bit, we need to prove that the result is used as an
|
| 3145 |
|
|
address, as LA performs only a 31-bit addition. */
|
| 3146 |
|
|
|
| 3147 |
|
|
bool
|
| 3148 |
|
|
legitimate_la_operand_p (rtx op)
|
| 3149 |
|
|
{
|
| 3150 |
|
|
struct s390_address addr;
|
| 3151 |
|
|
if (!s390_decompose_address (op, &addr))
|
| 3152 |
|
|
return false;
|
| 3153 |
|
|
|
| 3154 |
|
|
return (TARGET_64BIT || addr.pointer);
|
| 3155 |
|
|
}
|
| 3156 |
|
|
|
| 3157 |
|
|
/* Return true if it is valid *and* preferable to use LA to
|
| 3158 |
|
|
compute the sum of OP1 and OP2. */
|
| 3159 |
|
|
|
| 3160 |
|
|
bool
|
| 3161 |
|
|
preferred_la_operand_p (rtx op1, rtx op2)
|
| 3162 |
|
|
{
|
| 3163 |
|
|
struct s390_address addr;
|
| 3164 |
|
|
|
| 3165 |
|
|
if (op2 != const0_rtx)
|
| 3166 |
|
|
op1 = gen_rtx_PLUS (Pmode, op1, op2);
|
| 3167 |
|
|
|
| 3168 |
|
|
if (!s390_decompose_address (op1, &addr))
|
| 3169 |
|
|
return false;
|
| 3170 |
|
|
if (addr.base && !REGNO_OK_FOR_BASE_P (REGNO (addr.base)))
|
| 3171 |
|
|
return false;
|
| 3172 |
|
|
if (addr.indx && !REGNO_OK_FOR_INDEX_P (REGNO (addr.indx)))
|
| 3173 |
|
|
return false;
|
| 3174 |
|
|
|
| 3175 |
|
|
if (!TARGET_64BIT && !addr.pointer)
|
| 3176 |
|
|
return false;
|
| 3177 |
|
|
|
| 3178 |
|
|
if (addr.pointer)
|
| 3179 |
|
|
return true;
|
| 3180 |
|
|
|
| 3181 |
|
|
if ((addr.base && REG_P (addr.base) && REG_POINTER (addr.base))
|
| 3182 |
|
|
|| (addr.indx && REG_P (addr.indx) && REG_POINTER (addr.indx)))
|
| 3183 |
|
|
return true;
|
| 3184 |
|
|
|
| 3185 |
|
|
return false;
|
| 3186 |
|
|
}
|
| 3187 |
|
|
|
| 3188 |
|
|
/* Emit a forced load-address operation to load SRC into DST.
|
| 3189 |
|
|
This will use the LOAD ADDRESS instruction even in situations
|
| 3190 |
|
|
where legitimate_la_operand_p (SRC) returns false. */
|
| 3191 |
|
|
|
| 3192 |
|
|
void
|
| 3193 |
|
|
s390_load_address (rtx dst, rtx src)
|
| 3194 |
|
|
{
|
| 3195 |
|
|
if (TARGET_64BIT)
|
| 3196 |
|
|
emit_move_insn (dst, src);
|
| 3197 |
|
|
else
|
| 3198 |
|
|
emit_insn (gen_force_la_31 (dst, src));
|
| 3199 |
|
|
}
|
| 3200 |
|
|
|
| 3201 |
|
|
/* Return a legitimate reference for ORIG (an address) using the
|
| 3202 |
|
|
register REG. If REG is 0, a new pseudo is generated.
|
| 3203 |
|
|
|
| 3204 |
|
|
There are two types of references that must be handled:
|
| 3205 |
|
|
|
| 3206 |
|
|
1. Global data references must load the address from the GOT, via
|
| 3207 |
|
|
the PIC reg. An insn is emitted to do this load, and the reg is
|
| 3208 |
|
|
returned.
|
| 3209 |
|
|
|
| 3210 |
|
|
2. Static data references, constant pool addresses, and code labels
|
| 3211 |
|
|
compute the address as an offset from the GOT, whose base is in
|
| 3212 |
|
|
the PIC reg. Static data objects have SYMBOL_FLAG_LOCAL set to
|
| 3213 |
|
|
differentiate them from global data objects. The returned
|
| 3214 |
|
|
address is the PIC reg + an unspec constant.
|
| 3215 |
|
|
|
| 3216 |
|
|
TARGET_LEGITIMIZE_ADDRESS_P rejects symbolic references unless the PIC
|
| 3217 |
|
|
reg also appears in the address. */
|
| 3218 |
|
|
|
| 3219 |
|
|
rtx
|
| 3220 |
|
|
legitimize_pic_address (rtx orig, rtx reg)
|
| 3221 |
|
|
{
|
| 3222 |
|
|
rtx addr = orig;
|
| 3223 |
|
|
rtx new_rtx = orig;
|
| 3224 |
|
|
rtx base;
|
| 3225 |
|
|
|
| 3226 |
|
|
gcc_assert (!TLS_SYMBOLIC_CONST (addr));
|
| 3227 |
|
|
|
| 3228 |
|
|
if (GET_CODE (addr) == LABEL_REF
|
| 3229 |
|
|
|| (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr)))
|
| 3230 |
|
|
{
|
| 3231 |
|
|
/* This is a local symbol. */
|
| 3232 |
|
|
if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode))
|
| 3233 |
|
|
{
|
| 3234 |
|
|
/* Access local symbols PC-relative via LARL.
|
| 3235 |
|
|
This is the same as in the non-PIC case, so it is
|
| 3236 |
|
|
handled automatically ... */
|
| 3237 |
|
|
}
|
| 3238 |
|
|
else
|
| 3239 |
|
|
{
|
| 3240 |
|
|
/* Access local symbols relative to the GOT. */
|
| 3241 |
|
|
|
| 3242 |
|
|
rtx temp = reg? reg : gen_reg_rtx (Pmode);
|
| 3243 |
|
|
|
| 3244 |
|
|
if (reload_in_progress || reload_completed)
|
| 3245 |
|
|
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
|
| 3246 |
|
|
|
| 3247 |
|
|
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
|
| 3248 |
|
|
addr = gen_rtx_CONST (Pmode, addr);
|
| 3249 |
|
|
addr = force_const_mem (Pmode, addr);
|
| 3250 |
|
|
emit_move_insn (temp, addr);
|
| 3251 |
|
|
|
| 3252 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
|
| 3253 |
|
|
if (reg != 0)
|
| 3254 |
|
|
{
|
| 3255 |
|
|
s390_load_address (reg, new_rtx);
|
| 3256 |
|
|
new_rtx = reg;
|
| 3257 |
|
|
}
|
| 3258 |
|
|
}
|
| 3259 |
|
|
}
|
| 3260 |
|
|
else if (GET_CODE (addr) == SYMBOL_REF)
|
| 3261 |
|
|
{
|
| 3262 |
|
|
if (reg == 0)
|
| 3263 |
|
|
reg = gen_reg_rtx (Pmode);
|
| 3264 |
|
|
|
| 3265 |
|
|
if (flag_pic == 1)
|
| 3266 |
|
|
{
|
| 3267 |
|
|
/* Assume GOT offset < 4k. This is handled the same way
|
| 3268 |
|
|
in both 31- and 64-bit code (@GOT). */
|
| 3269 |
|
|
|
| 3270 |
|
|
if (reload_in_progress || reload_completed)
|
| 3271 |
|
|
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
|
| 3272 |
|
|
|
| 3273 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
|
| 3274 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3275 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new_rtx);
|
| 3276 |
|
|
new_rtx = gen_const_mem (Pmode, new_rtx);
|
| 3277 |
|
|
emit_move_insn (reg, new_rtx);
|
| 3278 |
|
|
new_rtx = reg;
|
| 3279 |
|
|
}
|
| 3280 |
|
|
else if (TARGET_CPU_ZARCH)
|
| 3281 |
|
|
{
|
| 3282 |
|
|
/* If the GOT offset might be >= 4k, we determine the position
|
| 3283 |
|
|
of the GOT entry via a PC-relative LARL (@GOTENT). */
|
| 3284 |
|
|
|
| 3285 |
|
|
rtx temp = reg ? reg : gen_reg_rtx (Pmode);
|
| 3286 |
|
|
|
| 3287 |
|
|
gcc_assert (REGNO (temp) >= FIRST_PSEUDO_REGISTER
|
| 3288 |
|
|
|| REGNO_REG_CLASS (REGNO (temp)) == ADDR_REGS);
|
| 3289 |
|
|
|
| 3290 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
|
| 3291 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3292 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3293 |
|
|
|
| 3294 |
|
|
new_rtx = gen_const_mem (Pmode, temp);
|
| 3295 |
|
|
emit_move_insn (reg, new_rtx);
|
| 3296 |
|
|
new_rtx = reg;
|
| 3297 |
|
|
}
|
| 3298 |
|
|
else
|
| 3299 |
|
|
{
|
| 3300 |
|
|
/* If the GOT offset might be >= 4k, we have to load it
|
| 3301 |
|
|
from the literal pool (@GOT). */
|
| 3302 |
|
|
|
| 3303 |
|
|
rtx temp = reg ? reg : gen_reg_rtx (Pmode);
|
| 3304 |
|
|
|
| 3305 |
|
|
gcc_assert (REGNO (temp) >= FIRST_PSEUDO_REGISTER
|
| 3306 |
|
|
|| REGNO_REG_CLASS (REGNO (temp)) == ADDR_REGS);
|
| 3307 |
|
|
|
| 3308 |
|
|
if (reload_in_progress || reload_completed)
|
| 3309 |
|
|
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
|
| 3310 |
|
|
|
| 3311 |
|
|
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
|
| 3312 |
|
|
addr = gen_rtx_CONST (Pmode, addr);
|
| 3313 |
|
|
addr = force_const_mem (Pmode, addr);
|
| 3314 |
|
|
emit_move_insn (temp, addr);
|
| 3315 |
|
|
|
| 3316 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
|
| 3317 |
|
|
new_rtx = gen_const_mem (Pmode, new_rtx);
|
| 3318 |
|
|
emit_move_insn (reg, new_rtx);
|
| 3319 |
|
|
new_rtx = reg;
|
| 3320 |
|
|
}
|
| 3321 |
|
|
}
|
| 3322 |
|
|
else
|
| 3323 |
|
|
{
|
| 3324 |
|
|
if (GET_CODE (addr) == CONST)
|
| 3325 |
|
|
{
|
| 3326 |
|
|
addr = XEXP (addr, 0);
|
| 3327 |
|
|
if (GET_CODE (addr) == UNSPEC)
|
| 3328 |
|
|
{
|
| 3329 |
|
|
gcc_assert (XVECLEN (addr, 0) == 1);
|
| 3330 |
|
|
switch (XINT (addr, 1))
|
| 3331 |
|
|
{
|
| 3332 |
|
|
/* If someone moved a GOT-relative UNSPEC
|
| 3333 |
|
|
out of the literal pool, force them back in. */
|
| 3334 |
|
|
case UNSPEC_GOTOFF:
|
| 3335 |
|
|
case UNSPEC_PLTOFF:
|
| 3336 |
|
|
new_rtx = force_const_mem (Pmode, orig);
|
| 3337 |
|
|
break;
|
| 3338 |
|
|
|
| 3339 |
|
|
/* @GOT is OK as is if small. */
|
| 3340 |
|
|
case UNSPEC_GOT:
|
| 3341 |
|
|
if (flag_pic == 2)
|
| 3342 |
|
|
new_rtx = force_const_mem (Pmode, orig);
|
| 3343 |
|
|
break;
|
| 3344 |
|
|
|
| 3345 |
|
|
/* @GOTENT is OK as is. */
|
| 3346 |
|
|
case UNSPEC_GOTENT:
|
| 3347 |
|
|
break;
|
| 3348 |
|
|
|
| 3349 |
|
|
/* @PLT is OK as is on 64-bit, must be converted to
|
| 3350 |
|
|
GOT-relative @PLTOFF on 31-bit. */
|
| 3351 |
|
|
case UNSPEC_PLT:
|
| 3352 |
|
|
if (!TARGET_CPU_ZARCH)
|
| 3353 |
|
|
{
|
| 3354 |
|
|
rtx temp = reg? reg : gen_reg_rtx (Pmode);
|
| 3355 |
|
|
|
| 3356 |
|
|
if (reload_in_progress || reload_completed)
|
| 3357 |
|
|
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
|
| 3358 |
|
|
|
| 3359 |
|
|
addr = XVECEXP (addr, 0, 0);
|
| 3360 |
|
|
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
|
| 3361 |
|
|
UNSPEC_PLTOFF);
|
| 3362 |
|
|
addr = gen_rtx_CONST (Pmode, addr);
|
| 3363 |
|
|
addr = force_const_mem (Pmode, addr);
|
| 3364 |
|
|
emit_move_insn (temp, addr);
|
| 3365 |
|
|
|
| 3366 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
|
| 3367 |
|
|
if (reg != 0)
|
| 3368 |
|
|
{
|
| 3369 |
|
|
s390_load_address (reg, new_rtx);
|
| 3370 |
|
|
new_rtx = reg;
|
| 3371 |
|
|
}
|
| 3372 |
|
|
}
|
| 3373 |
|
|
break;
|
| 3374 |
|
|
|
| 3375 |
|
|
/* Everything else cannot happen. */
|
| 3376 |
|
|
default:
|
| 3377 |
|
|
gcc_unreachable ();
|
| 3378 |
|
|
}
|
| 3379 |
|
|
}
|
| 3380 |
|
|
else
|
| 3381 |
|
|
gcc_assert (GET_CODE (addr) == PLUS);
|
| 3382 |
|
|
}
|
| 3383 |
|
|
if (GET_CODE (addr) == PLUS)
|
| 3384 |
|
|
{
|
| 3385 |
|
|
rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
|
| 3386 |
|
|
|
| 3387 |
|
|
gcc_assert (!TLS_SYMBOLIC_CONST (op0));
|
| 3388 |
|
|
gcc_assert (!TLS_SYMBOLIC_CONST (op1));
|
| 3389 |
|
|
|
| 3390 |
|
|
/* Check first to see if this is a constant offset
|
| 3391 |
|
|
from a local symbol reference. */
|
| 3392 |
|
|
if ((GET_CODE (op0) == LABEL_REF
|
| 3393 |
|
|
|| (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0)))
|
| 3394 |
|
|
&& GET_CODE (op1) == CONST_INT)
|
| 3395 |
|
|
{
|
| 3396 |
|
|
if (TARGET_CPU_ZARCH
|
| 3397 |
|
|
&& larl_operand (op0, VOIDmode)
|
| 3398 |
|
|
&& INTVAL (op1) < (HOST_WIDE_INT)1 << 31
|
| 3399 |
|
|
&& INTVAL (op1) >= -((HOST_WIDE_INT)1 << 31))
|
| 3400 |
|
|
{
|
| 3401 |
|
|
if (INTVAL (op1) & 1)
|
| 3402 |
|
|
{
|
| 3403 |
|
|
/* LARL can't handle odd offsets, so emit a
|
| 3404 |
|
|
pair of LARL and LA. */
|
| 3405 |
|
|
rtx temp = reg? reg : gen_reg_rtx (Pmode);
|
| 3406 |
|
|
|
| 3407 |
|
|
if (!DISP_IN_RANGE (INTVAL (op1)))
|
| 3408 |
|
|
{
|
| 3409 |
|
|
HOST_WIDE_INT even = INTVAL (op1) - 1;
|
| 3410 |
|
|
op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even));
|
| 3411 |
|
|
op0 = gen_rtx_CONST (Pmode, op0);
|
| 3412 |
|
|
op1 = const1_rtx;
|
| 3413 |
|
|
}
|
| 3414 |
|
|
|
| 3415 |
|
|
emit_move_insn (temp, op0);
|
| 3416 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, temp, op1);
|
| 3417 |
|
|
|
| 3418 |
|
|
if (reg != 0)
|
| 3419 |
|
|
{
|
| 3420 |
|
|
s390_load_address (reg, new_rtx);
|
| 3421 |
|
|
new_rtx = reg;
|
| 3422 |
|
|
}
|
| 3423 |
|
|
}
|
| 3424 |
|
|
else
|
| 3425 |
|
|
{
|
| 3426 |
|
|
/* If the offset is even, we can just use LARL.
|
| 3427 |
|
|
This will happen automatically. */
|
| 3428 |
|
|
}
|
| 3429 |
|
|
}
|
| 3430 |
|
|
else
|
| 3431 |
|
|
{
|
| 3432 |
|
|
/* Access local symbols relative to the GOT. */
|
| 3433 |
|
|
|
| 3434 |
|
|
rtx temp = reg? reg : gen_reg_rtx (Pmode);
|
| 3435 |
|
|
|
| 3436 |
|
|
if (reload_in_progress || reload_completed)
|
| 3437 |
|
|
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
|
| 3438 |
|
|
|
| 3439 |
|
|
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
|
| 3440 |
|
|
UNSPEC_GOTOFF);
|
| 3441 |
|
|
addr = gen_rtx_PLUS (Pmode, addr, op1);
|
| 3442 |
|
|
addr = gen_rtx_CONST (Pmode, addr);
|
| 3443 |
|
|
addr = force_const_mem (Pmode, addr);
|
| 3444 |
|
|
emit_move_insn (temp, addr);
|
| 3445 |
|
|
|
| 3446 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
|
| 3447 |
|
|
if (reg != 0)
|
| 3448 |
|
|
{
|
| 3449 |
|
|
s390_load_address (reg, new_rtx);
|
| 3450 |
|
|
new_rtx = reg;
|
| 3451 |
|
|
}
|
| 3452 |
|
|
}
|
| 3453 |
|
|
}
|
| 3454 |
|
|
|
| 3455 |
|
|
/* Now, check whether it is a GOT relative symbol plus offset
|
| 3456 |
|
|
that was pulled out of the literal pool. Force it back in. */
|
| 3457 |
|
|
|
| 3458 |
|
|
else if (GET_CODE (op0) == UNSPEC
|
| 3459 |
|
|
&& GET_CODE (op1) == CONST_INT
|
| 3460 |
|
|
&& XINT (op0, 1) == UNSPEC_GOTOFF)
|
| 3461 |
|
|
{
|
| 3462 |
|
|
gcc_assert (XVECLEN (op0, 0) == 1);
|
| 3463 |
|
|
|
| 3464 |
|
|
new_rtx = force_const_mem (Pmode, orig);
|
| 3465 |
|
|
}
|
| 3466 |
|
|
|
| 3467 |
|
|
/* Otherwise, compute the sum. */
|
| 3468 |
|
|
else
|
| 3469 |
|
|
{
|
| 3470 |
|
|
base = legitimize_pic_address (XEXP (addr, 0), reg);
|
| 3471 |
|
|
new_rtx = legitimize_pic_address (XEXP (addr, 1),
|
| 3472 |
|
|
base == reg ? NULL_RTX : reg);
|
| 3473 |
|
|
if (GET_CODE (new_rtx) == CONST_INT)
|
| 3474 |
|
|
new_rtx = plus_constant (base, INTVAL (new_rtx));
|
| 3475 |
|
|
else
|
| 3476 |
|
|
{
|
| 3477 |
|
|
if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1)))
|
| 3478 |
|
|
{
|
| 3479 |
|
|
base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0));
|
| 3480 |
|
|
new_rtx = XEXP (new_rtx, 1);
|
| 3481 |
|
|
}
|
| 3482 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx);
|
| 3483 |
|
|
}
|
| 3484 |
|
|
|
| 3485 |
|
|
if (GET_CODE (new_rtx) == CONST)
|
| 3486 |
|
|
new_rtx = XEXP (new_rtx, 0);
|
| 3487 |
|
|
new_rtx = force_operand (new_rtx, 0);
|
| 3488 |
|
|
}
|
| 3489 |
|
|
}
|
| 3490 |
|
|
}
|
| 3491 |
|
|
return new_rtx;
|
| 3492 |
|
|
}
|
| 3493 |
|
|
|
| 3494 |
|
|
/* Load the thread pointer into a register. */
|
| 3495 |
|
|
|
| 3496 |
|
|
rtx
|
| 3497 |
|
|
s390_get_thread_pointer (void)
|
| 3498 |
|
|
{
|
| 3499 |
|
|
rtx tp = gen_reg_rtx (Pmode);
|
| 3500 |
|
|
|
| 3501 |
|
|
emit_move_insn (tp, gen_rtx_REG (Pmode, TP_REGNUM));
|
| 3502 |
|
|
mark_reg_pointer (tp, BITS_PER_WORD);
|
| 3503 |
|
|
|
| 3504 |
|
|
return tp;
|
| 3505 |
|
|
}
|
| 3506 |
|
|
|
| 3507 |
|
|
/* Emit a tls call insn. The call target is the SYMBOL_REF stored
|
| 3508 |
|
|
in s390_tls_symbol which always refers to __tls_get_offset.
|
| 3509 |
|
|
The returned offset is written to RESULT_REG and an USE rtx is
|
| 3510 |
|
|
generated for TLS_CALL. */
|
| 3511 |
|
|
|
| 3512 |
|
|
static GTY(()) rtx s390_tls_symbol;
|
| 3513 |
|
|
|
| 3514 |
|
|
static void
|
| 3515 |
|
|
s390_emit_tls_call_insn (rtx result_reg, rtx tls_call)
|
| 3516 |
|
|
{
|
| 3517 |
|
|
rtx insn;
|
| 3518 |
|
|
|
| 3519 |
|
|
gcc_assert (flag_pic);
|
| 3520 |
|
|
|
| 3521 |
|
|
if (!s390_tls_symbol)
|
| 3522 |
|
|
s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
|
| 3523 |
|
|
|
| 3524 |
|
|
insn = s390_emit_call (s390_tls_symbol, tls_call, result_reg,
|
| 3525 |
|
|
gen_rtx_REG (Pmode, RETURN_REGNUM));
|
| 3526 |
|
|
|
| 3527 |
|
|
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), result_reg);
|
| 3528 |
|
|
RTL_CONST_CALL_P (insn) = 1;
|
| 3529 |
|
|
}
|
| 3530 |
|
|
|
| 3531 |
|
|
/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
|
| 3532 |
|
|
this (thread-local) address. REG may be used as temporary. */
|
| 3533 |
|
|
|
| 3534 |
|
|
static rtx
|
| 3535 |
|
|
legitimize_tls_address (rtx addr, rtx reg)
|
| 3536 |
|
|
{
|
| 3537 |
|
|
rtx new_rtx, tls_call, temp, base, r2, insn;
|
| 3538 |
|
|
|
| 3539 |
|
|
if (GET_CODE (addr) == SYMBOL_REF)
|
| 3540 |
|
|
switch (tls_symbolic_operand (addr))
|
| 3541 |
|
|
{
|
| 3542 |
|
|
case TLS_MODEL_GLOBAL_DYNAMIC:
|
| 3543 |
|
|
start_sequence ();
|
| 3544 |
|
|
r2 = gen_rtx_REG (Pmode, 2);
|
| 3545 |
|
|
tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_TLSGD);
|
| 3546 |
|
|
new_rtx = gen_rtx_CONST (Pmode, tls_call);
|
| 3547 |
|
|
new_rtx = force_const_mem (Pmode, new_rtx);
|
| 3548 |
|
|
emit_move_insn (r2, new_rtx);
|
| 3549 |
|
|
s390_emit_tls_call_insn (r2, tls_call);
|
| 3550 |
|
|
insn = get_insns ();
|
| 3551 |
|
|
end_sequence ();
|
| 3552 |
|
|
|
| 3553 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF);
|
| 3554 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3555 |
|
|
emit_libcall_block (insn, temp, r2, new_rtx);
|
| 3556 |
|
|
|
| 3557 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
|
| 3558 |
|
|
if (reg != 0)
|
| 3559 |
|
|
{
|
| 3560 |
|
|
s390_load_address (reg, new_rtx);
|
| 3561 |
|
|
new_rtx = reg;
|
| 3562 |
|
|
}
|
| 3563 |
|
|
break;
|
| 3564 |
|
|
|
| 3565 |
|
|
case TLS_MODEL_LOCAL_DYNAMIC:
|
| 3566 |
|
|
start_sequence ();
|
| 3567 |
|
|
r2 = gen_rtx_REG (Pmode, 2);
|
| 3568 |
|
|
tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM);
|
| 3569 |
|
|
new_rtx = gen_rtx_CONST (Pmode, tls_call);
|
| 3570 |
|
|
new_rtx = force_const_mem (Pmode, new_rtx);
|
| 3571 |
|
|
emit_move_insn (r2, new_rtx);
|
| 3572 |
|
|
s390_emit_tls_call_insn (r2, tls_call);
|
| 3573 |
|
|
insn = get_insns ();
|
| 3574 |
|
|
end_sequence ();
|
| 3575 |
|
|
|
| 3576 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM_NTPOFF);
|
| 3577 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3578 |
|
|
emit_libcall_block (insn, temp, r2, new_rtx);
|
| 3579 |
|
|
|
| 3580 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
|
| 3581 |
|
|
base = gen_reg_rtx (Pmode);
|
| 3582 |
|
|
s390_load_address (base, new_rtx);
|
| 3583 |
|
|
|
| 3584 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_DTPOFF);
|
| 3585 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3586 |
|
|
new_rtx = force_const_mem (Pmode, new_rtx);
|
| 3587 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3588 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3589 |
|
|
|
| 3590 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, base, temp);
|
| 3591 |
|
|
if (reg != 0)
|
| 3592 |
|
|
{
|
| 3593 |
|
|
s390_load_address (reg, new_rtx);
|
| 3594 |
|
|
new_rtx = reg;
|
| 3595 |
|
|
}
|
| 3596 |
|
|
break;
|
| 3597 |
|
|
|
| 3598 |
|
|
case TLS_MODEL_INITIAL_EXEC:
|
| 3599 |
|
|
if (flag_pic == 1)
|
| 3600 |
|
|
{
|
| 3601 |
|
|
/* Assume GOT offset < 4k. This is handled the same way
|
| 3602 |
|
|
in both 31- and 64-bit code. */
|
| 3603 |
|
|
|
| 3604 |
|
|
if (reload_in_progress || reload_completed)
|
| 3605 |
|
|
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
|
| 3606 |
|
|
|
| 3607 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF);
|
| 3608 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3609 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new_rtx);
|
| 3610 |
|
|
new_rtx = gen_const_mem (Pmode, new_rtx);
|
| 3611 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3612 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3613 |
|
|
}
|
| 3614 |
|
|
else if (TARGET_CPU_ZARCH)
|
| 3615 |
|
|
{
|
| 3616 |
|
|
/* If the GOT offset might be >= 4k, we determine the position
|
| 3617 |
|
|
of the GOT entry via a PC-relative LARL. */
|
| 3618 |
|
|
|
| 3619 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF);
|
| 3620 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3621 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3622 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3623 |
|
|
|
| 3624 |
|
|
new_rtx = gen_const_mem (Pmode, temp);
|
| 3625 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3626 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3627 |
|
|
}
|
| 3628 |
|
|
else if (flag_pic)
|
| 3629 |
|
|
{
|
| 3630 |
|
|
/* If the GOT offset might be >= 4k, we have to load it
|
| 3631 |
|
|
from the literal pool. */
|
| 3632 |
|
|
|
| 3633 |
|
|
if (reload_in_progress || reload_completed)
|
| 3634 |
|
|
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
|
| 3635 |
|
|
|
| 3636 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF);
|
| 3637 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3638 |
|
|
new_rtx = force_const_mem (Pmode, new_rtx);
|
| 3639 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3640 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3641 |
|
|
|
| 3642 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
|
| 3643 |
|
|
new_rtx = gen_const_mem (Pmode, new_rtx);
|
| 3644 |
|
|
|
| 3645 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new_rtx, addr), UNSPEC_TLS_LOAD);
|
| 3646 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3647 |
|
|
emit_insn (gen_rtx_SET (Pmode, temp, new_rtx));
|
| 3648 |
|
|
}
|
| 3649 |
|
|
else
|
| 3650 |
|
|
{
|
| 3651 |
|
|
/* In position-dependent code, load the absolute address of
|
| 3652 |
|
|
the GOT entry from the literal pool. */
|
| 3653 |
|
|
|
| 3654 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF);
|
| 3655 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3656 |
|
|
new_rtx = force_const_mem (Pmode, new_rtx);
|
| 3657 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3658 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3659 |
|
|
|
| 3660 |
|
|
new_rtx = temp;
|
| 3661 |
|
|
new_rtx = gen_const_mem (Pmode, new_rtx);
|
| 3662 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new_rtx, addr), UNSPEC_TLS_LOAD);
|
| 3663 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3664 |
|
|
emit_insn (gen_rtx_SET (Pmode, temp, new_rtx));
|
| 3665 |
|
|
}
|
| 3666 |
|
|
|
| 3667 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
|
| 3668 |
|
|
if (reg != 0)
|
| 3669 |
|
|
{
|
| 3670 |
|
|
s390_load_address (reg, new_rtx);
|
| 3671 |
|
|
new_rtx = reg;
|
| 3672 |
|
|
}
|
| 3673 |
|
|
break;
|
| 3674 |
|
|
|
| 3675 |
|
|
case TLS_MODEL_LOCAL_EXEC:
|
| 3676 |
|
|
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF);
|
| 3677 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3678 |
|
|
new_rtx = force_const_mem (Pmode, new_rtx);
|
| 3679 |
|
|
temp = gen_reg_rtx (Pmode);
|
| 3680 |
|
|
emit_move_insn (temp, new_rtx);
|
| 3681 |
|
|
|
| 3682 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
|
| 3683 |
|
|
if (reg != 0)
|
| 3684 |
|
|
{
|
| 3685 |
|
|
s390_load_address (reg, new_rtx);
|
| 3686 |
|
|
new_rtx = reg;
|
| 3687 |
|
|
}
|
| 3688 |
|
|
break;
|
| 3689 |
|
|
|
| 3690 |
|
|
default:
|
| 3691 |
|
|
gcc_unreachable ();
|
| 3692 |
|
|
}
|
| 3693 |
|
|
|
| 3694 |
|
|
else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == UNSPEC)
|
| 3695 |
|
|
{
|
| 3696 |
|
|
switch (XINT (XEXP (addr, 0), 1))
|
| 3697 |
|
|
{
|
| 3698 |
|
|
case UNSPEC_INDNTPOFF:
|
| 3699 |
|
|
gcc_assert (TARGET_CPU_ZARCH);
|
| 3700 |
|
|
new_rtx = addr;
|
| 3701 |
|
|
break;
|
| 3702 |
|
|
|
| 3703 |
|
|
default:
|
| 3704 |
|
|
gcc_unreachable ();
|
| 3705 |
|
|
}
|
| 3706 |
|
|
}
|
| 3707 |
|
|
|
| 3708 |
|
|
else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
|
| 3709 |
|
|
&& GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
|
| 3710 |
|
|
{
|
| 3711 |
|
|
new_rtx = XEXP (XEXP (addr, 0), 0);
|
| 3712 |
|
|
if (GET_CODE (new_rtx) != SYMBOL_REF)
|
| 3713 |
|
|
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
|
| 3714 |
|
|
|
| 3715 |
|
|
new_rtx = legitimize_tls_address (new_rtx, reg);
|
| 3716 |
|
|
new_rtx = plus_constant (new_rtx, INTVAL (XEXP (XEXP (addr, 0), 1)));
|
| 3717 |
|
|
new_rtx = force_operand (new_rtx, 0);
|
| 3718 |
|
|
}
|
| 3719 |
|
|
|
| 3720 |
|
|
else
|
| 3721 |
|
|
gcc_unreachable (); /* for now ... */
|
| 3722 |
|
|
|
| 3723 |
|
|
return new_rtx;
|
| 3724 |
|
|
}
|
| 3725 |
|
|
|
| 3726 |
|
|
/* Emit insns making the address in operands[1] valid for a standard
|
| 3727 |
|
|
move to operands[0]. operands[1] is replaced by an address which
|
| 3728 |
|
|
should be used instead of the former RTX to emit the move
|
| 3729 |
|
|
pattern. */
|
| 3730 |
|
|
|
| 3731 |
|
|
void
|
| 3732 |
|
|
emit_symbolic_move (rtx *operands)
|
| 3733 |
|
|
{
|
| 3734 |
|
|
rtx temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
|
| 3735 |
|
|
|
| 3736 |
|
|
if (GET_CODE (operands[0]) == MEM)
|
| 3737 |
|
|
operands[1] = force_reg (Pmode, operands[1]);
|
| 3738 |
|
|
else if (TLS_SYMBOLIC_CONST (operands[1]))
|
| 3739 |
|
|
operands[1] = legitimize_tls_address (operands[1], temp);
|
| 3740 |
|
|
else if (flag_pic)
|
| 3741 |
|
|
operands[1] = legitimize_pic_address (operands[1], temp);
|
| 3742 |
|
|
}
|
| 3743 |
|
|
|
| 3744 |
|
|
/* Try machine-dependent ways of modifying an illegitimate address X
|
| 3745 |
|
|
to be legitimate. If we find one, return the new, valid address.
|
| 3746 |
|
|
|
| 3747 |
|
|
OLDX is the address as it was before break_out_memory_refs was called.
|
| 3748 |
|
|
In some cases it is useful to look at this to decide what needs to be done.
|
| 3749 |
|
|
|
| 3750 |
|
|
MODE is the mode of the operand pointed to by X.
|
| 3751 |
|
|
|
| 3752 |
|
|
When -fpic is used, special handling is needed for symbolic references.
|
| 3753 |
|
|
See comments by legitimize_pic_address for details. */
|
| 3754 |
|
|
|
| 3755 |
|
|
static rtx
|
| 3756 |
|
|
s390_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
|
| 3757 |
|
|
enum machine_mode mode ATTRIBUTE_UNUSED)
|
| 3758 |
|
|
{
|
| 3759 |
|
|
rtx constant_term = const0_rtx;
|
| 3760 |
|
|
|
| 3761 |
|
|
if (TLS_SYMBOLIC_CONST (x))
|
| 3762 |
|
|
{
|
| 3763 |
|
|
x = legitimize_tls_address (x, 0);
|
| 3764 |
|
|
|
| 3765 |
|
|
if (s390_legitimate_address_p (mode, x, FALSE))
|
| 3766 |
|
|
return x;
|
| 3767 |
|
|
}
|
| 3768 |
|
|
else if (GET_CODE (x) == PLUS
|
| 3769 |
|
|
&& (TLS_SYMBOLIC_CONST (XEXP (x, 0))
|
| 3770 |
|
|
|| TLS_SYMBOLIC_CONST (XEXP (x, 1))))
|
| 3771 |
|
|
{
|
| 3772 |
|
|
return x;
|
| 3773 |
|
|
}
|
| 3774 |
|
|
else if (flag_pic)
|
| 3775 |
|
|
{
|
| 3776 |
|
|
if (SYMBOLIC_CONST (x)
|
| 3777 |
|
|
|| (GET_CODE (x) == PLUS
|
| 3778 |
|
|
&& (SYMBOLIC_CONST (XEXP (x, 0))
|
| 3779 |
|
|
|| SYMBOLIC_CONST (XEXP (x, 1)))))
|
| 3780 |
|
|
x = legitimize_pic_address (x, 0);
|
| 3781 |
|
|
|
| 3782 |
|
|
if (s390_legitimate_address_p (mode, x, FALSE))
|
| 3783 |
|
|
return x;
|
| 3784 |
|
|
}
|
| 3785 |
|
|
|
| 3786 |
|
|
x = eliminate_constant_term (x, &constant_term);
|
| 3787 |
|
|
|
| 3788 |
|
|
/* Optimize loading of large displacements by splitting them
|
| 3789 |
|
|
into the multiple of 4K and the rest; this allows the
|
| 3790 |
|
|
former to be CSE'd if possible.
|
| 3791 |
|
|
|
| 3792 |
|
|
Don't do this if the displacement is added to a register
|
| 3793 |
|
|
pointing into the stack frame, as the offsets will
|
| 3794 |
|
|
change later anyway. */
|
| 3795 |
|
|
|
| 3796 |
|
|
if (GET_CODE (constant_term) == CONST_INT
|
| 3797 |
|
|
&& !TARGET_LONG_DISPLACEMENT
|
| 3798 |
|
|
&& !DISP_IN_RANGE (INTVAL (constant_term))
|
| 3799 |
|
|
&& !(REG_P (x) && REGNO_PTR_FRAME_P (REGNO (x))))
|
| 3800 |
|
|
{
|
| 3801 |
|
|
HOST_WIDE_INT lower = INTVAL (constant_term) & 0xfff;
|
| 3802 |
|
|
HOST_WIDE_INT upper = INTVAL (constant_term) ^ lower;
|
| 3803 |
|
|
|
| 3804 |
|
|
rtx temp = gen_reg_rtx (Pmode);
|
| 3805 |
|
|
rtx val = force_operand (GEN_INT (upper), temp);
|
| 3806 |
|
|
if (val != temp)
|
| 3807 |
|
|
emit_move_insn (temp, val);
|
| 3808 |
|
|
|
| 3809 |
|
|
x = gen_rtx_PLUS (Pmode, x, temp);
|
| 3810 |
|
|
constant_term = GEN_INT (lower);
|
| 3811 |
|
|
}
|
| 3812 |
|
|
|
| 3813 |
|
|
if (GET_CODE (x) == PLUS)
|
| 3814 |
|
|
{
|
| 3815 |
|
|
if (GET_CODE (XEXP (x, 0)) == REG)
|
| 3816 |
|
|
{
|
| 3817 |
|
|
rtx temp = gen_reg_rtx (Pmode);
|
| 3818 |
|
|
rtx val = force_operand (XEXP (x, 1), temp);
|
| 3819 |
|
|
if (val != temp)
|
| 3820 |
|
|
emit_move_insn (temp, val);
|
| 3821 |
|
|
|
| 3822 |
|
|
x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp);
|
| 3823 |
|
|
}
|
| 3824 |
|
|
|
| 3825 |
|
|
else if (GET_CODE (XEXP (x, 1)) == REG)
|
| 3826 |
|
|
{
|
| 3827 |
|
|
rtx temp = gen_reg_rtx (Pmode);
|
| 3828 |
|
|
rtx val = force_operand (XEXP (x, 0), temp);
|
| 3829 |
|
|
if (val != temp)
|
| 3830 |
|
|
emit_move_insn (temp, val);
|
| 3831 |
|
|
|
| 3832 |
|
|
x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1));
|
| 3833 |
|
|
}
|
| 3834 |
|
|
}
|
| 3835 |
|
|
|
| 3836 |
|
|
if (constant_term != const0_rtx)
|
| 3837 |
|
|
x = gen_rtx_PLUS (Pmode, x, constant_term);
|
| 3838 |
|
|
|
| 3839 |
|
|
return x;
|
| 3840 |
|
|
}
|
| 3841 |
|
|
|
| 3842 |
|
|
/* Try a machine-dependent way of reloading an illegitimate address AD
|
| 3843 |
|
|
operand. If we find one, push the reload and and return the new address.
|
| 3844 |
|
|
|
| 3845 |
|
|
MODE is the mode of the enclosing MEM. OPNUM is the operand number
|
| 3846 |
|
|
and TYPE is the reload type of the current reload. */
|
| 3847 |
|
|
|
| 3848 |
|
|
rtx
|
| 3849 |
|
|
legitimize_reload_address (rtx ad, enum machine_mode mode ATTRIBUTE_UNUSED,
|
| 3850 |
|
|
int opnum, int type)
|
| 3851 |
|
|
{
|
| 3852 |
|
|
if (!optimize || TARGET_LONG_DISPLACEMENT)
|
| 3853 |
|
|
return NULL_RTX;
|
| 3854 |
|
|
|
| 3855 |
|
|
if (GET_CODE (ad) == PLUS)
|
| 3856 |
|
|
{
|
| 3857 |
|
|
rtx tem = simplify_binary_operation (PLUS, Pmode,
|
| 3858 |
|
|
XEXP (ad, 0), XEXP (ad, 1));
|
| 3859 |
|
|
if (tem)
|
| 3860 |
|
|
ad = tem;
|
| 3861 |
|
|
}
|
| 3862 |
|
|
|
| 3863 |
|
|
if (GET_CODE (ad) == PLUS
|
| 3864 |
|
|
&& GET_CODE (XEXP (ad, 0)) == REG
|
| 3865 |
|
|
&& GET_CODE (XEXP (ad, 1)) == CONST_INT
|
| 3866 |
|
|
&& !DISP_IN_RANGE (INTVAL (XEXP (ad, 1))))
|
| 3867 |
|
|
{
|
| 3868 |
|
|
HOST_WIDE_INT lower = INTVAL (XEXP (ad, 1)) & 0xfff;
|
| 3869 |
|
|
HOST_WIDE_INT upper = INTVAL (XEXP (ad, 1)) ^ lower;
|
| 3870 |
|
|
rtx cst, tem, new_rtx;
|
| 3871 |
|
|
|
| 3872 |
|
|
cst = GEN_INT (upper);
|
| 3873 |
|
|
if (!legitimate_reload_constant_p (cst))
|
| 3874 |
|
|
cst = force_const_mem (Pmode, cst);
|
| 3875 |
|
|
|
| 3876 |
|
|
tem = gen_rtx_PLUS (Pmode, XEXP (ad, 0), cst);
|
| 3877 |
|
|
new_rtx = gen_rtx_PLUS (Pmode, tem, GEN_INT (lower));
|
| 3878 |
|
|
|
| 3879 |
|
|
push_reload (XEXP (tem, 1), 0, &XEXP (tem, 1), 0,
|
| 3880 |
|
|
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
|
| 3881 |
|
|
opnum, (enum reload_type) type);
|
| 3882 |
|
|
return new_rtx;
|
| 3883 |
|
|
}
|
| 3884 |
|
|
|
| 3885 |
|
|
return NULL_RTX;
|
| 3886 |
|
|
}
|
| 3887 |
|
|
|
| 3888 |
|
|
/* Emit code to move LEN bytes from DST to SRC. */
|
| 3889 |
|
|
|
| 3890 |
|
|
void
|
| 3891 |
|
|
s390_expand_movmem (rtx dst, rtx src, rtx len)
|
| 3892 |
|
|
{
|
| 3893 |
|
|
if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
|
| 3894 |
|
|
{
|
| 3895 |
|
|
if (INTVAL (len) > 0)
|
| 3896 |
|
|
emit_insn (gen_movmem_short (dst, src, GEN_INT (INTVAL (len) - 1)));
|
| 3897 |
|
|
}
|
| 3898 |
|
|
|
| 3899 |
|
|
else if (TARGET_MVCLE)
|
| 3900 |
|
|
{
|
| 3901 |
|
|
emit_insn (gen_movmem_long (dst, src, convert_to_mode (Pmode, len, 1)));
|
| 3902 |
|
|
}
|
| 3903 |
|
|
|
| 3904 |
|
|
else
|
| 3905 |
|
|
{
|
| 3906 |
|
|
rtx dst_addr, src_addr, count, blocks, temp;
|
| 3907 |
|
|
rtx loop_start_label = gen_label_rtx ();
|
| 3908 |
|
|
rtx loop_end_label = gen_label_rtx ();
|
| 3909 |
|
|
rtx end_label = gen_label_rtx ();
|
| 3910 |
|
|
enum machine_mode mode;
|
| 3911 |
|
|
|
| 3912 |
|
|
mode = GET_MODE (len);
|
| 3913 |
|
|
if (mode == VOIDmode)
|
| 3914 |
|
|
mode = Pmode;
|
| 3915 |
|
|
|
| 3916 |
|
|
dst_addr = gen_reg_rtx (Pmode);
|
| 3917 |
|
|
src_addr = gen_reg_rtx (Pmode);
|
| 3918 |
|
|
count = gen_reg_rtx (mode);
|
| 3919 |
|
|
blocks = gen_reg_rtx (mode);
|
| 3920 |
|
|
|
| 3921 |
|
|
convert_move (count, len, 1);
|
| 3922 |
|
|
emit_cmp_and_jump_insns (count, const0_rtx,
|
| 3923 |
|
|
EQ, NULL_RTX, mode, 1, end_label);
|
| 3924 |
|
|
|
| 3925 |
|
|
emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
|
| 3926 |
|
|
emit_move_insn (src_addr, force_operand (XEXP (src, 0), NULL_RTX));
|
| 3927 |
|
|
dst = change_address (dst, VOIDmode, dst_addr);
|
| 3928 |
|
|
src = change_address (src, VOIDmode, src_addr);
|
| 3929 |
|
|
|
| 3930 |
|
|
temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1,
|
| 3931 |
|
|
OPTAB_DIRECT);
|
| 3932 |
|
|
if (temp != count)
|
| 3933 |
|
|
emit_move_insn (count, temp);
|
| 3934 |
|
|
|
| 3935 |
|
|
temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1,
|
| 3936 |
|
|
OPTAB_DIRECT);
|
| 3937 |
|
|
if (temp != blocks)
|
| 3938 |
|
|
emit_move_insn (blocks, temp);
|
| 3939 |
|
|
|
| 3940 |
|
|
emit_cmp_and_jump_insns (blocks, const0_rtx,
|
| 3941 |
|
|
EQ, NULL_RTX, mode, 1, loop_end_label);
|
| 3942 |
|
|
|
| 3943 |
|
|
emit_label (loop_start_label);
|
| 3944 |
|
|
|
| 3945 |
|
|
emit_insn (gen_movmem_short (dst, src, GEN_INT (255)));
|
| 3946 |
|
|
s390_load_address (dst_addr,
|
| 3947 |
|
|
gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
|
| 3948 |
|
|
s390_load_address (src_addr,
|
| 3949 |
|
|
gen_rtx_PLUS (Pmode, src_addr, GEN_INT (256)));
|
| 3950 |
|
|
|
| 3951 |
|
|
temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1,
|
| 3952 |
|
|
OPTAB_DIRECT);
|
| 3953 |
|
|
if (temp != blocks)
|
| 3954 |
|
|
emit_move_insn (blocks, temp);
|
| 3955 |
|
|
|
| 3956 |
|
|
emit_cmp_and_jump_insns (blocks, const0_rtx,
|
| 3957 |
|
|
EQ, NULL_RTX, mode, 1, loop_end_label);
|
| 3958 |
|
|
|
| 3959 |
|
|
emit_jump (loop_start_label);
|
| 3960 |
|
|
emit_label (loop_end_label);
|
| 3961 |
|
|
|
| 3962 |
|
|
emit_insn (gen_movmem_short (dst, src,
|
| 3963 |
|
|
convert_to_mode (Pmode, count, 1)));
|
| 3964 |
|
|
emit_label (end_label);
|
| 3965 |
|
|
}
|
| 3966 |
|
|
}
|
| 3967 |
|
|
|
| 3968 |
|
|
/* Emit code to set LEN bytes at DST to VAL.
|
| 3969 |
|
|
Make use of clrmem if VAL is zero. */
|
| 3970 |
|
|
|
| 3971 |
|
|
void
|
| 3972 |
|
|
s390_expand_setmem (rtx dst, rtx len, rtx val)
|
| 3973 |
|
|
{
|
| 3974 |
|
|
if (GET_CODE (len) == CONST_INT && INTVAL (len) == 0)
|
| 3975 |
|
|
return;
|
| 3976 |
|
|
|
| 3977 |
|
|
gcc_assert (GET_CODE (val) == CONST_INT || GET_MODE (val) == QImode);
|
| 3978 |
|
|
|
| 3979 |
|
|
if (GET_CODE (len) == CONST_INT && INTVAL (len) > 0 && INTVAL (len) <= 257)
|
| 3980 |
|
|
{
|
| 3981 |
|
|
if (val == const0_rtx && INTVAL (len) <= 256)
|
| 3982 |
|
|
emit_insn (gen_clrmem_short (dst, GEN_INT (INTVAL (len) - 1)));
|
| 3983 |
|
|
else
|
| 3984 |
|
|
{
|
| 3985 |
|
|
/* Initialize memory by storing the first byte. */
|
| 3986 |
|
|
emit_move_insn (adjust_address (dst, QImode, 0), val);
|
| 3987 |
|
|
|
| 3988 |
|
|
if (INTVAL (len) > 1)
|
| 3989 |
|
|
{
|
| 3990 |
|
|
/* Initiate 1 byte overlap move.
|
| 3991 |
|
|
The first byte of DST is propagated through DSTP1.
|
| 3992 |
|
|
Prepare a movmem for: DST+1 = DST (length = LEN - 1).
|
| 3993 |
|
|
DST is set to size 1 so the rest of the memory location
|
| 3994 |
|
|
does not count as source operand. */
|
| 3995 |
|
|
rtx dstp1 = adjust_address (dst, VOIDmode, 1);
|
| 3996 |
|
|
set_mem_size (dst, const1_rtx);
|
| 3997 |
|
|
|
| 3998 |
|
|
emit_insn (gen_movmem_short (dstp1, dst,
|
| 3999 |
|
|
GEN_INT (INTVAL (len) - 2)));
|
| 4000 |
|
|
}
|
| 4001 |
|
|
}
|
| 4002 |
|
|
}
|
| 4003 |
|
|
|
| 4004 |
|
|
else if (TARGET_MVCLE)
|
| 4005 |
|
|
{
|
| 4006 |
|
|
val = force_not_mem (convert_modes (Pmode, QImode, val, 1));
|
| 4007 |
|
|
emit_insn (gen_setmem_long (dst, convert_to_mode (Pmode, len, 1), val));
|
| 4008 |
|
|
}
|
| 4009 |
|
|
|
| 4010 |
|
|
else
|
| 4011 |
|
|
{
|
| 4012 |
|
|
rtx dst_addr, src_addr, count, blocks, temp, dstp1 = NULL_RTX;
|
| 4013 |
|
|
rtx loop_start_label = gen_label_rtx ();
|
| 4014 |
|
|
rtx loop_end_label = gen_label_rtx ();
|
| 4015 |
|
|
rtx end_label = gen_label_rtx ();
|
| 4016 |
|
|
enum machine_mode mode;
|
| 4017 |
|
|
|
| 4018 |
|
|
mode = GET_MODE (len);
|
| 4019 |
|
|
if (mode == VOIDmode)
|
| 4020 |
|
|
mode = Pmode;
|
| 4021 |
|
|
|
| 4022 |
|
|
dst_addr = gen_reg_rtx (Pmode);
|
| 4023 |
|
|
src_addr = gen_reg_rtx (Pmode);
|
| 4024 |
|
|
count = gen_reg_rtx (mode);
|
| 4025 |
|
|
blocks = gen_reg_rtx (mode);
|
| 4026 |
|
|
|
| 4027 |
|
|
convert_move (count, len, 1);
|
| 4028 |
|
|
emit_cmp_and_jump_insns (count, const0_rtx,
|
| 4029 |
|
|
EQ, NULL_RTX, mode, 1, end_label);
|
| 4030 |
|
|
|
| 4031 |
|
|
emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
|
| 4032 |
|
|
dst = change_address (dst, VOIDmode, dst_addr);
|
| 4033 |
|
|
|
| 4034 |
|
|
if (val == const0_rtx)
|
| 4035 |
|
|
temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1,
|
| 4036 |
|
|
OPTAB_DIRECT);
|
| 4037 |
|
|
else
|
| 4038 |
|
|
{
|
| 4039 |
|
|
dstp1 = adjust_address (dst, VOIDmode, 1);
|
| 4040 |
|
|
set_mem_size (dst, const1_rtx);
|
| 4041 |
|
|
|
| 4042 |
|
|
/* Initialize memory by storing the first byte. */
|
| 4043 |
|
|
emit_move_insn (adjust_address (dst, QImode, 0), val);
|
| 4044 |
|
|
|
| 4045 |
|
|
/* If count is 1 we are done. */
|
| 4046 |
|
|
emit_cmp_and_jump_insns (count, const1_rtx,
|
| 4047 |
|
|
EQ, NULL_RTX, mode, 1, end_label);
|
| 4048 |
|
|
|
| 4049 |
|
|
temp = expand_binop (mode, add_optab, count, GEN_INT (-2), count, 1,
|
| 4050 |
|
|
OPTAB_DIRECT);
|
| 4051 |
|
|
}
|
| 4052 |
|
|
if (temp != count)
|
| 4053 |
|
|
emit_move_insn (count, temp);
|
| 4054 |
|
|
|
| 4055 |
|
|
temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1,
|
| 4056 |
|
|
OPTAB_DIRECT);
|
| 4057 |
|
|
if (temp != blocks)
|
| 4058 |
|
|
emit_move_insn (blocks, temp);
|
| 4059 |
|
|
|
| 4060 |
|
|
emit_cmp_and_jump_insns (blocks, const0_rtx,
|
| 4061 |
|
|
EQ, NULL_RTX, mode, 1, loop_end_label);
|
| 4062 |
|
|
|
| 4063 |
|
|
emit_label (loop_start_label);
|
| 4064 |
|
|
|
| 4065 |
|
|
if (val == const0_rtx)
|
| 4066 |
|
|
emit_insn (gen_clrmem_short (dst, GEN_INT (255)));
|
| 4067 |
|
|
else
|
| 4068 |
|
|
emit_insn (gen_movmem_short (dstp1, dst, GEN_INT (255)));
|
| 4069 |
|
|
s390_load_address (dst_addr,
|
| 4070 |
|
|
gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
|
| 4071 |
|
|
|
| 4072 |
|
|
temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1,
|
| 4073 |
|
|
OPTAB_DIRECT);
|
| 4074 |
|
|
if (temp != blocks)
|
| 4075 |
|
|
emit_move_insn (blocks, temp);
|
| 4076 |
|
|
|
| 4077 |
|
|
emit_cmp_and_jump_insns (blocks, const0_rtx,
|
| 4078 |
|
|
EQ, NULL_RTX, mode, 1, loop_end_label);
|
| 4079 |
|
|
|
| 4080 |
|
|
emit_jump (loop_start_label);
|
| 4081 |
|
|
emit_label (loop_end_label);
|
| 4082 |
|
|
|
| 4083 |
|
|
if (val == const0_rtx)
|
| 4084 |
|
|
emit_insn (gen_clrmem_short (dst, convert_to_mode (Pmode, count, 1)));
|
| 4085 |
|
|
else
|
| 4086 |
|
|
emit_insn (gen_movmem_short (dstp1, dst, convert_to_mode (Pmode, count, 1)));
|
| 4087 |
|
|
emit_label (end_label);
|
| 4088 |
|
|
}
|
| 4089 |
|
|
}
|
| 4090 |
|
|
|
| 4091 |
|
|
/* Emit code to compare LEN bytes at OP0 with those at OP1,
|
| 4092 |
|
|
and return the result in TARGET. */
|
| 4093 |
|
|
|
| 4094 |
|
|
void
|
| 4095 |
|
|
s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
|
| 4096 |
|
|
{
|
| 4097 |
|
|
rtx ccreg = gen_rtx_REG (CCUmode, CC_REGNUM);
|
| 4098 |
|
|
rtx tmp;
|
| 4099 |
|
|
|
| 4100 |
|
|
/* As the result of CMPINT is inverted compared to what we need,
|
| 4101 |
|
|
we have to swap the operands. */
|
| 4102 |
|
|
tmp = op0; op0 = op1; op1 = tmp;
|
| 4103 |
|
|
|
| 4104 |
|
|
if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
|
| 4105 |
|
|
{
|
| 4106 |
|
|
if (INTVAL (len) > 0)
|
| 4107 |
|
|
{
|
| 4108 |
|
|
emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (INTVAL (len) - 1)));
|
| 4109 |
|
|
emit_insn (gen_cmpint (target, ccreg));
|
| 4110 |
|
|
}
|
| 4111 |
|
|
else
|
| 4112 |
|
|
emit_move_insn (target, const0_rtx);
|
| 4113 |
|
|
}
|
| 4114 |
|
|
else if (TARGET_MVCLE)
|
| 4115 |
|
|
{
|
| 4116 |
|
|
emit_insn (gen_cmpmem_long (op0, op1, convert_to_mode (Pmode, len, 1)));
|
| 4117 |
|
|
emit_insn (gen_cmpint (target, ccreg));
|
| 4118 |
|
|
}
|
| 4119 |
|
|
else
|
| 4120 |
|
|
{
|
| 4121 |
|
|
rtx addr0, addr1, count, blocks, temp;
|
| 4122 |
|
|
rtx loop_start_label = gen_label_rtx ();
|
| 4123 |
|
|
rtx loop_end_label = gen_label_rtx ();
|
| 4124 |
|
|
rtx end_label = gen_label_rtx ();
|
| 4125 |
|
|
enum machine_mode mode;
|
| 4126 |
|
|
|
| 4127 |
|
|
mode = GET_MODE (len);
|
| 4128 |
|
|
if (mode == VOIDmode)
|
| 4129 |
|
|
mode = Pmode;
|
| 4130 |
|
|
|
| 4131 |
|
|
addr0 = gen_reg_rtx (Pmode);
|
| 4132 |
|
|
addr1 = gen_reg_rtx (Pmode);
|
| 4133 |
|
|
count = gen_reg_rtx (mode);
|
| 4134 |
|
|
blocks = gen_reg_rtx (mode);
|
| 4135 |
|
|
|
| 4136 |
|
|
convert_move (count, len, 1);
|
| 4137 |
|
|
emit_cmp_and_jump_insns (count, const0_rtx,
|
| 4138 |
|
|
EQ, NULL_RTX, mode, 1, end_label);
|
| 4139 |
|
|
|
| 4140 |
|
|
emit_move_insn (addr0, force_operand (XEXP (op0, 0), NULL_RTX));
|
| 4141 |
|
|
emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX));
|
| 4142 |
|
|
op0 = change_address (op0, VOIDmode, addr0);
|
| 4143 |
|
|
op1 = change_address (op1, VOIDmode, addr1);
|
| 4144 |
|
|
|
| 4145 |
|
|
temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1,
|
| 4146 |
|
|
OPTAB_DIRECT);
|
| 4147 |
|
|
if (temp != count)
|
| 4148 |
|
|
emit_move_insn (count, temp);
|
| 4149 |
|
|
|
| 4150 |
|
|
temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1,
|
| 4151 |
|
|
OPTAB_DIRECT);
|
| 4152 |
|
|
if (temp != blocks)
|
| 4153 |
|
|
emit_move_insn (blocks, temp);
|
| 4154 |
|
|
|
| 4155 |
|
|
emit_cmp_and_jump_insns (blocks, const0_rtx,
|
| 4156 |
|
|
EQ, NULL_RTX, mode, 1, loop_end_label);
|
| 4157 |
|
|
|
| 4158 |
|
|
emit_label (loop_start_label);
|
| 4159 |
|
|
|
| 4160 |
|
|
emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255)));
|
| 4161 |
|
|
temp = gen_rtx_NE (VOIDmode, ccreg, const0_rtx);
|
| 4162 |
|
|
temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp,
|
| 4163 |
|
|
gen_rtx_LABEL_REF (VOIDmode, end_label), pc_rtx);
|
| 4164 |
|
|
temp = gen_rtx_SET (VOIDmode, pc_rtx, temp);
|
| 4165 |
|
|
emit_jump_insn (temp);
|
| 4166 |
|
|
|
| 4167 |
|
|
s390_load_address (addr0,
|
| 4168 |
|
|
gen_rtx_PLUS (Pmode, addr0, GEN_INT (256)));
|
| 4169 |
|
|
s390_load_address (addr1,
|
| 4170 |
|
|
gen_rtx_PLUS (Pmode, addr1, GEN_INT (256)));
|
| 4171 |
|
|
|
| 4172 |
|
|
temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1,
|
| 4173 |
|
|
OPTAB_DIRECT);
|
| 4174 |
|
|
if (temp != blocks)
|
| 4175 |
|
|
emit_move_insn (blocks, temp);
|
| 4176 |
|
|
|
| 4177 |
|
|
emit_cmp_and_jump_insns (blocks, const0_rtx,
|
| 4178 |
|
|
EQ, NULL_RTX, mode, 1, loop_end_label);
|
| 4179 |
|
|
|
| 4180 |
|
|
emit_jump (loop_start_label);
|
| 4181 |
|
|
emit_label (loop_end_label);
|
| 4182 |
|
|
|
| 4183 |
|
|
emit_insn (gen_cmpmem_short (op0, op1,
|
| 4184 |
|
|
convert_to_mode (Pmode, count, 1)));
|
| 4185 |
|
|
emit_label (end_label);
|
| 4186 |
|
|
|
| 4187 |
|
|
emit_insn (gen_cmpint (target, ccreg));
|
| 4188 |
|
|
}
|
| 4189 |
|
|
}
|
| 4190 |
|
|
|
| 4191 |
|
|
|
| 4192 |
|
|
/* Expand conditional increment or decrement using alc/slb instructions.
|
| 4193 |
|
|
Should generate code setting DST to either SRC or SRC + INCREMENT,
|
| 4194 |
|
|
depending on the result of the comparison CMP_OP0 CMP_CODE CMP_OP1.
|
| 4195 |
|
|
Returns true if successful, false otherwise.
|
| 4196 |
|
|
|
| 4197 |
|
|
That makes it possible to implement some if-constructs without jumps e.g.:
|
| 4198 |
|
|
(borrow = CC0 | CC1 and carry = CC2 | CC3)
|
| 4199 |
|
|
unsigned int a, b, c;
|
| 4200 |
|
|
if (a < b) c++; -> CCU b > a -> CC2; c += carry;
|
| 4201 |
|
|
if (a < b) c--; -> CCL3 a - b -> borrow; c -= borrow;
|
| 4202 |
|
|
if (a <= b) c++; -> CCL3 b - a -> borrow; c += carry;
|
| 4203 |
|
|
if (a <= b) c--; -> CCU a <= b -> borrow; c -= borrow;
|
| 4204 |
|
|
|
| 4205 |
|
|
Checks for EQ and NE with a nonzero value need an additional xor e.g.:
|
| 4206 |
|
|
if (a == b) c++; -> CCL3 a ^= b; 0 - a -> borrow; c += carry;
|
| 4207 |
|
|
if (a == b) c--; -> CCU a ^= b; a <= 0 -> CC0 | CC1; c -= borrow;
|
| 4208 |
|
|
if (a != b) c++; -> CCU a ^= b; a > 0 -> CC2; c += carry;
|
| 4209 |
|
|
if (a != b) c--; -> CCL3 a ^= b; 0 - a -> borrow; c -= borrow; */
|
| 4210 |
|
|
|
| 4211 |
|
|
bool
|
| 4212 |
|
|
s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1,
|
| 4213 |
|
|
rtx dst, rtx src, rtx increment)
|
| 4214 |
|
|
{
|
| 4215 |
|
|
enum machine_mode cmp_mode;
|
| 4216 |
|
|
enum machine_mode cc_mode;
|
| 4217 |
|
|
rtx op_res;
|
| 4218 |
|
|
rtx insn;
|
| 4219 |
|
|
rtvec p;
|
| 4220 |
|
|
int ret;
|
| 4221 |
|
|
|
| 4222 |
|
|
if ((GET_MODE (cmp_op0) == SImode || GET_MODE (cmp_op0) == VOIDmode)
|
| 4223 |
|
|
&& (GET_MODE (cmp_op1) == SImode || GET_MODE (cmp_op1) == VOIDmode))
|
| 4224 |
|
|
cmp_mode = SImode;
|
| 4225 |
|
|
else if ((GET_MODE (cmp_op0) == DImode || GET_MODE (cmp_op0) == VOIDmode)
|
| 4226 |
|
|
&& (GET_MODE (cmp_op1) == DImode || GET_MODE (cmp_op1) == VOIDmode))
|
| 4227 |
|
|
cmp_mode = DImode;
|
| 4228 |
|
|
else
|
| 4229 |
|
|
return false;
|
| 4230 |
|
|
|
| 4231 |
|
|
/* Try ADD LOGICAL WITH CARRY. */
|
| 4232 |
|
|
if (increment == const1_rtx)
|
| 4233 |
|
|
{
|
| 4234 |
|
|
/* Determine CC mode to use. */
|
| 4235 |
|
|
if (cmp_code == EQ || cmp_code == NE)
|
| 4236 |
|
|
{
|
| 4237 |
|
|
if (cmp_op1 != const0_rtx)
|
| 4238 |
|
|
{
|
| 4239 |
|
|
cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1,
|
| 4240 |
|
|
NULL_RTX, 0, OPTAB_WIDEN);
|
| 4241 |
|
|
cmp_op1 = const0_rtx;
|
| 4242 |
|
|
}
|
| 4243 |
|
|
|
| 4244 |
|
|
cmp_code = cmp_code == EQ ? LEU : GTU;
|
| 4245 |
|
|
}
|
| 4246 |
|
|
|
| 4247 |
|
|
if (cmp_code == LTU || cmp_code == LEU)
|
| 4248 |
|
|
{
|
| 4249 |
|
|
rtx tem = cmp_op0;
|
| 4250 |
|
|
cmp_op0 = cmp_op1;
|
| 4251 |
|
|
cmp_op1 = tem;
|
| 4252 |
|
|
cmp_code = swap_condition (cmp_code);
|
| 4253 |
|
|
}
|
| 4254 |
|
|
|
| 4255 |
|
|
switch (cmp_code)
|
| 4256 |
|
|
{
|
| 4257 |
|
|
case GTU:
|
| 4258 |
|
|
cc_mode = CCUmode;
|
| 4259 |
|
|
break;
|
| 4260 |
|
|
|
| 4261 |
|
|
case GEU:
|
| 4262 |
|
|
cc_mode = CCL3mode;
|
| 4263 |
|
|
break;
|
| 4264 |
|
|
|
| 4265 |
|
|
default:
|
| 4266 |
|
|
return false;
|
| 4267 |
|
|
}
|
| 4268 |
|
|
|
| 4269 |
|
|
/* Emit comparison instruction pattern. */
|
| 4270 |
|
|
if (!register_operand (cmp_op0, cmp_mode))
|
| 4271 |
|
|
cmp_op0 = force_reg (cmp_mode, cmp_op0);
|
| 4272 |
|
|
|
| 4273 |
|
|
insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM),
|
| 4274 |
|
|
gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1));
|
| 4275 |
|
|
/* We use insn_invalid_p here to add clobbers if required. */
|
| 4276 |
|
|
ret = insn_invalid_p (emit_insn (insn));
|
| 4277 |
|
|
gcc_assert (!ret);
|
| 4278 |
|
|
|
| 4279 |
|
|
/* Emit ALC instruction pattern. */
|
| 4280 |
|
|
op_res = gen_rtx_fmt_ee (cmp_code, GET_MODE (dst),
|
| 4281 |
|
|
gen_rtx_REG (cc_mode, CC_REGNUM),
|
| 4282 |
|
|
const0_rtx);
|
| 4283 |
|
|
|
| 4284 |
|
|
if (src != const0_rtx)
|
| 4285 |
|
|
{
|
| 4286 |
|
|
if (!register_operand (src, GET_MODE (dst)))
|
| 4287 |
|
|
src = force_reg (GET_MODE (dst), src);
|
| 4288 |
|
|
|
| 4289 |
|
|
op_res = gen_rtx_PLUS (GET_MODE (dst), op_res, src);
|
| 4290 |
|
|
op_res = gen_rtx_PLUS (GET_MODE (dst), op_res, const0_rtx);
|
| 4291 |
|
|
}
|
| 4292 |
|
|
|
| 4293 |
|
|
p = rtvec_alloc (2);
|
| 4294 |
|
|
RTVEC_ELT (p, 0) =
|
| 4295 |
|
|
gen_rtx_SET (VOIDmode, dst, op_res);
|
| 4296 |
|
|
RTVEC_ELT (p, 1) =
|
| 4297 |
|
|
gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
|
| 4298 |
|
|
emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
|
| 4299 |
|
|
|
| 4300 |
|
|
return true;
|
| 4301 |
|
|
}
|
| 4302 |
|
|
|
| 4303 |
|
|
/* Try SUBTRACT LOGICAL WITH BORROW. */
|
| 4304 |
|
|
if (increment == constm1_rtx)
|
| 4305 |
|
|
{
|
| 4306 |
|
|
/* Determine CC mode to use. */
|
| 4307 |
|
|
if (cmp_code == EQ || cmp_code == NE)
|
| 4308 |
|
|
{
|
| 4309 |
|
|
if (cmp_op1 != const0_rtx)
|
| 4310 |
|
|
{
|
| 4311 |
|
|
cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1,
|
| 4312 |
|
|
NULL_RTX, 0, OPTAB_WIDEN);
|
| 4313 |
|
|
cmp_op1 = const0_rtx;
|
| 4314 |
|
|
}
|
| 4315 |
|
|
|
| 4316 |
|
|
cmp_code = cmp_code == EQ ? LEU : GTU;
|
| 4317 |
|
|
}
|
| 4318 |
|
|
|
| 4319 |
|
|
if (cmp_code == GTU || cmp_code == GEU)
|
| 4320 |
|
|
{
|
| 4321 |
|
|
rtx tem = cmp_op0;
|
| 4322 |
|
|
cmp_op0 = cmp_op1;
|
| 4323 |
|
|
cmp_op1 = tem;
|
| 4324 |
|
|
cmp_code = swap_condition (cmp_code);
|
| 4325 |
|
|
}
|
| 4326 |
|
|
|
| 4327 |
|
|
switch (cmp_code)
|
| 4328 |
|
|
{
|
| 4329 |
|
|
case LEU:
|
| 4330 |
|
|
cc_mode = CCUmode;
|
| 4331 |
|
|
break;
|
| 4332 |
|
|
|
| 4333 |
|
|
case LTU:
|
| 4334 |
|
|
cc_mode = CCL3mode;
|
| 4335 |
|
|
break;
|
| 4336 |
|
|
|
| 4337 |
|
|
default:
|
| 4338 |
|
|
return false;
|
| 4339 |
|
|
}
|
| 4340 |
|
|
|
| 4341 |
|
|
/* Emit comparison instruction pattern. */
|
| 4342 |
|
|
if (!register_operand (cmp_op0, cmp_mode))
|
| 4343 |
|
|
cmp_op0 = force_reg (cmp_mode, cmp_op0);
|
| 4344 |
|
|
|
| 4345 |
|
|
insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM),
|
| 4346 |
|
|
gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1));
|
| 4347 |
|
|
/* We use insn_invalid_p here to add clobbers if required. */
|
| 4348 |
|
|
ret = insn_invalid_p (emit_insn (insn));
|
| 4349 |
|
|
gcc_assert (!ret);
|
| 4350 |
|
|
|
| 4351 |
|
|
/* Emit SLB instruction pattern. */
|
| 4352 |
|
|
if (!register_operand (src, GET_MODE (dst)))
|
| 4353 |
|
|
src = force_reg (GET_MODE (dst), src);
|
| 4354 |
|
|
|
| 4355 |
|
|
op_res = gen_rtx_MINUS (GET_MODE (dst),
|
| 4356 |
|
|
gen_rtx_MINUS (GET_MODE (dst), src, const0_rtx),
|
| 4357 |
|
|
gen_rtx_fmt_ee (cmp_code, GET_MODE (dst),
|
| 4358 |
|
|
gen_rtx_REG (cc_mode, CC_REGNUM),
|
| 4359 |
|
|
const0_rtx));
|
| 4360 |
|
|
p = rtvec_alloc (2);
|
| 4361 |
|
|
RTVEC_ELT (p, 0) =
|
| 4362 |
|
|
gen_rtx_SET (VOIDmode, dst, op_res);
|
| 4363 |
|
|
RTVEC_ELT (p, 1) =
|
| 4364 |
|
|
gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
|
| 4365 |
|
|
emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
|
| 4366 |
|
|
|
| 4367 |
|
|
return true;
|
| 4368 |
|
|
}
|
| 4369 |
|
|
|
| 4370 |
|
|
return false;
|
| 4371 |
|
|
}
|
| 4372 |
|
|
|
| 4373 |
|
|
/* Expand code for the insv template. Return true if successful. */
|
| 4374 |
|
|
|
| 4375 |
|
|
bool
|
| 4376 |
|
|
s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
|
| 4377 |
|
|
{
|
| 4378 |
|
|
int bitsize = INTVAL (op1);
|
| 4379 |
|
|
int bitpos = INTVAL (op2);
|
| 4380 |
|
|
|
| 4381 |
|
|
/* On z10 we can use the risbg instruction to implement insv. */
|
| 4382 |
|
|
if (TARGET_Z10
|
| 4383 |
|
|
&& ((GET_MODE (dest) == DImode && GET_MODE (src) == DImode)
|
| 4384 |
|
|
|| (GET_MODE (dest) == SImode && GET_MODE (src) == SImode)))
|
| 4385 |
|
|
{
|
| 4386 |
|
|
rtx op;
|
| 4387 |
|
|
rtx clobber;
|
| 4388 |
|
|
|
| 4389 |
|
|
op = gen_rtx_SET (GET_MODE(src),
|
| 4390 |
|
|
gen_rtx_ZERO_EXTRACT (GET_MODE (dest), dest, op1, op2),
|
| 4391 |
|
|
src);
|
| 4392 |
|
|
clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
|
| 4393 |
|
|
emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber)));
|
| 4394 |
|
|
|
| 4395 |
|
|
return true;
|
| 4396 |
|
|
}
|
| 4397 |
|
|
|
| 4398 |
|
|
/* We need byte alignment. */
|
| 4399 |
|
|
if (bitsize % BITS_PER_UNIT)
|
| 4400 |
|
|
return false;
|
| 4401 |
|
|
|
| 4402 |
|
|
if (bitpos == 0
|
| 4403 |
|
|
&& memory_operand (dest, VOIDmode)
|
| 4404 |
|
|
&& (register_operand (src, word_mode)
|
| 4405 |
|
|
|| const_int_operand (src, VOIDmode)))
|
| 4406 |
|
|
{
|
| 4407 |
|
|
/* Emit standard pattern if possible. */
|
| 4408 |
|
|
enum machine_mode mode = smallest_mode_for_size (bitsize, MODE_INT);
|
| 4409 |
|
|
if (GET_MODE_BITSIZE (mode) == bitsize)
|
| 4410 |
|
|
emit_move_insn (adjust_address (dest, mode, 0), gen_lowpart (mode, src));
|
| 4411 |
|
|
|
| 4412 |
|
|
/* (set (ze (mem)) (const_int)). */
|
| 4413 |
|
|
else if (const_int_operand (src, VOIDmode))
|
| 4414 |
|
|
{
|
| 4415 |
|
|
int size = bitsize / BITS_PER_UNIT;
|
| 4416 |
|
|
rtx src_mem = adjust_address (force_const_mem (word_mode, src), BLKmode,
|
| 4417 |
|
|
GET_MODE_SIZE (word_mode) - size);
|
| 4418 |
|
|
|
| 4419 |
|
|
dest = adjust_address (dest, BLKmode, 0);
|
| 4420 |
|
|
set_mem_size (dest, GEN_INT (size));
|
| 4421 |
|
|
s390_expand_movmem (dest, src_mem, GEN_INT (size));
|
| 4422 |
|
|
}
|
| 4423 |
|
|
|
| 4424 |
|
|
/* (set (ze (mem)) (reg)). */
|
| 4425 |
|
|
else if (register_operand (src, word_mode))
|
| 4426 |
|
|
{
|
| 4427 |
|
|
if (bitsize <= GET_MODE_BITSIZE (SImode))
|
| 4428 |
|
|
emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, op1,
|
| 4429 |
|
|
const0_rtx), src);
|
| 4430 |
|
|
else
|
| 4431 |
|
|
{
|
| 4432 |
|
|
/* Emit st,stcmh sequence. */
|
| 4433 |
|
|
int stcmh_width = bitsize - GET_MODE_BITSIZE (SImode);
|
| 4434 |
|
|
int size = stcmh_width / BITS_PER_UNIT;
|
| 4435 |
|
|
|
| 4436 |
|
|
emit_move_insn (adjust_address (dest, SImode, size),
|
| 4437 |
|
|
gen_lowpart (SImode, src));
|
| 4438 |
|
|
set_mem_size (dest, GEN_INT (size));
|
| 4439 |
|
|
emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, GEN_INT
|
| 4440 |
|
|
(stcmh_width), const0_rtx),
|
| 4441 |
|
|
gen_rtx_LSHIFTRT (word_mode, src, GEN_INT
|
| 4442 |
|
|
(GET_MODE_BITSIZE (SImode))));
|
| 4443 |
|
|
}
|
| 4444 |
|
|
}
|
| 4445 |
|
|
else
|
| 4446 |
|
|
return false;
|
| 4447 |
|
|
|
| 4448 |
|
|
return true;
|
| 4449 |
|
|
}
|
| 4450 |
|
|
|
| 4451 |
|
|
/* (set (ze (reg)) (const_int)). */
|
| 4452 |
|
|
if (TARGET_ZARCH
|
| 4453 |
|
|
&& register_operand (dest, word_mode)
|
| 4454 |
|
|
&& (bitpos % 16) == 0
|
| 4455 |
|
|
&& (bitsize % 16) == 0
|
| 4456 |
|
|
&& const_int_operand (src, VOIDmode))
|
| 4457 |
|
|
{
|
| 4458 |
|
|
HOST_WIDE_INT val = INTVAL (src);
|
| 4459 |
|
|
int regpos = bitpos + bitsize;
|
| 4460 |
|
|
|
| 4461 |
|
|
while (regpos > bitpos)
|
| 4462 |
|
|
{
|
| 4463 |
|
|
enum machine_mode putmode;
|
| 4464 |
|
|
int putsize;
|
| 4465 |
|
|
|
| 4466 |
|
|
if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32))
|
| 4467 |
|
|
putmode = SImode;
|
| 4468 |
|
|
else
|
| 4469 |
|
|
putmode = HImode;
|
| 4470 |
|
|
|
| 4471 |
|
|
putsize = GET_MODE_BITSIZE (putmode);
|
| 4472 |
|
|
regpos -= putsize;
|
| 4473 |
|
|
emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest,
|
| 4474 |
|
|
GEN_INT (putsize),
|
| 4475 |
|
|
GEN_INT (regpos)),
|
| 4476 |
|
|
gen_int_mode (val, putmode));
|
| 4477 |
|
|
val >>= putsize;
|
| 4478 |
|
|
}
|
| 4479 |
|
|
gcc_assert (regpos == bitpos);
|
| 4480 |
|
|
return true;
|
| 4481 |
|
|
}
|
| 4482 |
|
|
|
| 4483 |
|
|
return false;
|
| 4484 |
|
|
}
|
| 4485 |
|
|
|
| 4486 |
|
|
/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic which returns a
|
| 4487 |
|
|
register that holds VAL of mode MODE shifted by COUNT bits. */
|
| 4488 |
|
|
|
| 4489 |
|
|
static inline rtx
|
| 4490 |
|
|
s390_expand_mask_and_shift (rtx val, enum machine_mode mode, rtx count)
|
| 4491 |
|
|
{
|
| 4492 |
|
|
val = expand_simple_binop (SImode, AND, val, GEN_INT (GET_MODE_MASK (mode)),
|
| 4493 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4494 |
|
|
return expand_simple_binop (SImode, ASHIFT, val, count,
|
| 4495 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4496 |
|
|
}
|
| 4497 |
|
|
|
| 4498 |
|
|
/* Structure to hold the initial parameters for a compare_and_swap operation
|
| 4499 |
|
|
in HImode and QImode. */
|
| 4500 |
|
|
|
| 4501 |
|
|
struct alignment_context
|
| 4502 |
|
|
{
|
| 4503 |
|
|
rtx memsi; /* SI aligned memory location. */
|
| 4504 |
|
|
rtx shift; /* Bit offset with regard to lsb. */
|
| 4505 |
|
|
rtx modemask; /* Mask of the HQImode shifted by SHIFT bits. */
|
| 4506 |
|
|
rtx modemaski; /* ~modemask */
|
| 4507 |
|
|
bool aligned; /* True if memory is aligned, false else. */
|
| 4508 |
|
|
};
|
| 4509 |
|
|
|
| 4510 |
|
|
/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic to initialize
|
| 4511 |
|
|
structure AC for transparent simplifying, if the memory alignment is known
|
| 4512 |
|
|
to be at least 32bit. MEM is the memory location for the actual operation
|
| 4513 |
|
|
and MODE its mode. */
|
| 4514 |
|
|
|
| 4515 |
|
|
static void
|
| 4516 |
|
|
init_alignment_context (struct alignment_context *ac, rtx mem,
|
| 4517 |
|
|
enum machine_mode mode)
|
| 4518 |
|
|
{
|
| 4519 |
|
|
ac->shift = GEN_INT (GET_MODE_SIZE (SImode) - GET_MODE_SIZE (mode));
|
| 4520 |
|
|
ac->aligned = (MEM_ALIGN (mem) >= GET_MODE_BITSIZE (SImode));
|
| 4521 |
|
|
|
| 4522 |
|
|
if (ac->aligned)
|
| 4523 |
|
|
ac->memsi = adjust_address (mem, SImode, 0); /* Memory is aligned. */
|
| 4524 |
|
|
else
|
| 4525 |
|
|
{
|
| 4526 |
|
|
/* Alignment is unknown. */
|
| 4527 |
|
|
rtx byteoffset, addr, align;
|
| 4528 |
|
|
|
| 4529 |
|
|
/* Force the address into a register. */
|
| 4530 |
|
|
addr = force_reg (Pmode, XEXP (mem, 0));
|
| 4531 |
|
|
|
| 4532 |
|
|
/* Align it to SImode. */
|
| 4533 |
|
|
align = expand_simple_binop (Pmode, AND, addr,
|
| 4534 |
|
|
GEN_INT (-GET_MODE_SIZE (SImode)),
|
| 4535 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4536 |
|
|
/* Generate MEM. */
|
| 4537 |
|
|
ac->memsi = gen_rtx_MEM (SImode, align);
|
| 4538 |
|
|
MEM_VOLATILE_P (ac->memsi) = MEM_VOLATILE_P (mem);
|
| 4539 |
|
|
set_mem_alias_set (ac->memsi, ALIAS_SET_MEMORY_BARRIER);
|
| 4540 |
|
|
set_mem_align (ac->memsi, GET_MODE_BITSIZE (SImode));
|
| 4541 |
|
|
|
| 4542 |
|
|
/* Calculate shiftcount. */
|
| 4543 |
|
|
byteoffset = expand_simple_binop (Pmode, AND, addr,
|
| 4544 |
|
|
GEN_INT (GET_MODE_SIZE (SImode) - 1),
|
| 4545 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4546 |
|
|
/* As we already have some offset, evaluate the remaining distance. */
|
| 4547 |
|
|
ac->shift = expand_simple_binop (SImode, MINUS, ac->shift, byteoffset,
|
| 4548 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4549 |
|
|
|
| 4550 |
|
|
}
|
| 4551 |
|
|
/* Shift is the byte count, but we need the bitcount. */
|
| 4552 |
|
|
ac->shift = expand_simple_binop (SImode, MULT, ac->shift, GEN_INT (BITS_PER_UNIT),
|
| 4553 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4554 |
|
|
/* Calculate masks. */
|
| 4555 |
|
|
ac->modemask = expand_simple_binop (SImode, ASHIFT,
|
| 4556 |
|
|
GEN_INT (GET_MODE_MASK (mode)), ac->shift,
|
| 4557 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4558 |
|
|
ac->modemaski = expand_simple_unop (SImode, NOT, ac->modemask, NULL_RTX, 1);
|
| 4559 |
|
|
}
|
| 4560 |
|
|
|
| 4561 |
|
|
/* Expand an atomic compare and swap operation for HImode and QImode. MEM is
|
| 4562 |
|
|
the memory location, CMP the old value to compare MEM with and NEW_RTX the value
|
| 4563 |
|
|
to set if CMP == MEM.
|
| 4564 |
|
|
CMP is never in memory for compare_and_swap_cc because
|
| 4565 |
|
|
expand_bool_compare_and_swap puts it into a register for later compare. */
|
| 4566 |
|
|
|
| 4567 |
|
|
void
|
| 4568 |
|
|
s390_expand_cs_hqi (enum machine_mode mode, rtx target, rtx mem, rtx cmp, rtx new_rtx)
|
| 4569 |
|
|
{
|
| 4570 |
|
|
struct alignment_context ac;
|
| 4571 |
|
|
rtx cmpv, newv, val, resv, cc;
|
| 4572 |
|
|
rtx res = gen_reg_rtx (SImode);
|
| 4573 |
|
|
rtx csloop = gen_label_rtx ();
|
| 4574 |
|
|
rtx csend = gen_label_rtx ();
|
| 4575 |
|
|
|
| 4576 |
|
|
gcc_assert (register_operand (target, VOIDmode));
|
| 4577 |
|
|
gcc_assert (MEM_P (mem));
|
| 4578 |
|
|
|
| 4579 |
|
|
init_alignment_context (&ac, mem, mode);
|
| 4580 |
|
|
|
| 4581 |
|
|
/* Shift the values to the correct bit positions. */
|
| 4582 |
|
|
if (!(ac.aligned && MEM_P (cmp)))
|
| 4583 |
|
|
cmp = s390_expand_mask_and_shift (cmp, mode, ac.shift);
|
| 4584 |
|
|
if (!(ac.aligned && MEM_P (new_rtx)))
|
| 4585 |
|
|
new_rtx = s390_expand_mask_and_shift (new_rtx, mode, ac.shift);
|
| 4586 |
|
|
|
| 4587 |
|
|
/* Load full word. Subsequent loads are performed by CS. */
|
| 4588 |
|
|
val = expand_simple_binop (SImode, AND, ac.memsi, ac.modemaski,
|
| 4589 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4590 |
|
|
|
| 4591 |
|
|
/* Start CS loop. */
|
| 4592 |
|
|
emit_label (csloop);
|
| 4593 |
|
|
/* val = "<mem>00..0<mem>"
|
| 4594 |
|
|
* cmp = "00..0<cmp>00..0"
|
| 4595 |
|
|
* new = "00..0<new>00..0"
|
| 4596 |
|
|
*/
|
| 4597 |
|
|
|
| 4598 |
|
|
/* Patch cmp and new with val at correct position. */
|
| 4599 |
|
|
if (ac.aligned && MEM_P (cmp))
|
| 4600 |
|
|
{
|
| 4601 |
|
|
cmpv = force_reg (SImode, val);
|
| 4602 |
|
|
store_bit_field (cmpv, GET_MODE_BITSIZE (mode), 0, SImode, cmp);
|
| 4603 |
|
|
}
|
| 4604 |
|
|
else
|
| 4605 |
|
|
cmpv = force_reg (SImode, expand_simple_binop (SImode, IOR, cmp, val,
|
| 4606 |
|
|
NULL_RTX, 1, OPTAB_DIRECT));
|
| 4607 |
|
|
if (ac.aligned && MEM_P (new_rtx))
|
| 4608 |
|
|
{
|
| 4609 |
|
|
newv = force_reg (SImode, val);
|
| 4610 |
|
|
store_bit_field (newv, GET_MODE_BITSIZE (mode), 0, SImode, new_rtx);
|
| 4611 |
|
|
}
|
| 4612 |
|
|
else
|
| 4613 |
|
|
newv = force_reg (SImode, expand_simple_binop (SImode, IOR, new_rtx, val,
|
| 4614 |
|
|
NULL_RTX, 1, OPTAB_DIRECT));
|
| 4615 |
|
|
|
| 4616 |
|
|
/* Jump to end if we're done (likely?). */
|
| 4617 |
|
|
s390_emit_jump (csend, s390_emit_compare_and_swap (EQ, res, ac.memsi,
|
| 4618 |
|
|
cmpv, newv));
|
| 4619 |
|
|
|
| 4620 |
|
|
/* Check for changes outside mode. */
|
| 4621 |
|
|
resv = expand_simple_binop (SImode, AND, res, ac.modemaski,
|
| 4622 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4623 |
|
|
cc = s390_emit_compare (NE, resv, val);
|
| 4624 |
|
|
emit_move_insn (val, resv);
|
| 4625 |
|
|
/* Loop internal if so. */
|
| 4626 |
|
|
s390_emit_jump (csloop, cc);
|
| 4627 |
|
|
|
| 4628 |
|
|
emit_label (csend);
|
| 4629 |
|
|
|
| 4630 |
|
|
/* Return the correct part of the bitfield. */
|
| 4631 |
|
|
convert_move (target, expand_simple_binop (SImode, LSHIFTRT, res, ac.shift,
|
| 4632 |
|
|
NULL_RTX, 1, OPTAB_DIRECT), 1);
|
| 4633 |
|
|
}
|
| 4634 |
|
|
|
| 4635 |
|
|
/* Expand an atomic operation CODE of mode MODE. MEM is the memory location
|
| 4636 |
|
|
and VAL the value to play with. If AFTER is true then store the value
|
| 4637 |
|
|
MEM holds after the operation, if AFTER is false then store the value MEM
|
| 4638 |
|
|
holds before the operation. If TARGET is zero then discard that value, else
|
| 4639 |
|
|
store it to TARGET. */
|
| 4640 |
|
|
|
| 4641 |
|
|
void
|
| 4642 |
|
|
s390_expand_atomic (enum machine_mode mode, enum rtx_code code,
|
| 4643 |
|
|
rtx target, rtx mem, rtx val, bool after)
|
| 4644 |
|
|
{
|
| 4645 |
|
|
struct alignment_context ac;
|
| 4646 |
|
|
rtx cmp;
|
| 4647 |
|
|
rtx new_rtx = gen_reg_rtx (SImode);
|
| 4648 |
|
|
rtx orig = gen_reg_rtx (SImode);
|
| 4649 |
|
|
rtx csloop = gen_label_rtx ();
|
| 4650 |
|
|
|
| 4651 |
|
|
gcc_assert (!target || register_operand (target, VOIDmode));
|
| 4652 |
|
|
gcc_assert (MEM_P (mem));
|
| 4653 |
|
|
|
| 4654 |
|
|
init_alignment_context (&ac, mem, mode);
|
| 4655 |
|
|
|
| 4656 |
|
|
/* Shift val to the correct bit positions.
|
| 4657 |
|
|
Preserve "icm", but prevent "ex icm". */
|
| 4658 |
|
|
if (!(ac.aligned && code == SET && MEM_P (val)))
|
| 4659 |
|
|
val = s390_expand_mask_and_shift (val, mode, ac.shift);
|
| 4660 |
|
|
|
| 4661 |
|
|
/* Further preparation insns. */
|
| 4662 |
|
|
if (code == PLUS || code == MINUS)
|
| 4663 |
|
|
emit_move_insn (orig, val);
|
| 4664 |
|
|
else if (code == MULT || code == AND) /* val = "11..1<val>11..1" */
|
| 4665 |
|
|
val = expand_simple_binop (SImode, XOR, val, ac.modemaski,
|
| 4666 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4667 |
|
|
|
| 4668 |
|
|
/* Load full word. Subsequent loads are performed by CS. */
|
| 4669 |
|
|
cmp = force_reg (SImode, ac.memsi);
|
| 4670 |
|
|
|
| 4671 |
|
|
/* Start CS loop. */
|
| 4672 |
|
|
emit_label (csloop);
|
| 4673 |
|
|
emit_move_insn (new_rtx, cmp);
|
| 4674 |
|
|
|
| 4675 |
|
|
/* Patch new with val at correct position. */
|
| 4676 |
|
|
switch (code)
|
| 4677 |
|
|
{
|
| 4678 |
|
|
case PLUS:
|
| 4679 |
|
|
case MINUS:
|
| 4680 |
|
|
val = expand_simple_binop (SImode, code, new_rtx, orig,
|
| 4681 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4682 |
|
|
val = expand_simple_binop (SImode, AND, val, ac.modemask,
|
| 4683 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4684 |
|
|
/* FALLTHRU */
|
| 4685 |
|
|
case SET:
|
| 4686 |
|
|
if (ac.aligned && MEM_P (val))
|
| 4687 |
|
|
store_bit_field (new_rtx, GET_MODE_BITSIZE (mode), 0, SImode, val);
|
| 4688 |
|
|
else
|
| 4689 |
|
|
{
|
| 4690 |
|
|
new_rtx = expand_simple_binop (SImode, AND, new_rtx, ac.modemaski,
|
| 4691 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4692 |
|
|
new_rtx = expand_simple_binop (SImode, IOR, new_rtx, val,
|
| 4693 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4694 |
|
|
}
|
| 4695 |
|
|
break;
|
| 4696 |
|
|
case AND:
|
| 4697 |
|
|
case IOR:
|
| 4698 |
|
|
case XOR:
|
| 4699 |
|
|
new_rtx = expand_simple_binop (SImode, code, new_rtx, val,
|
| 4700 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4701 |
|
|
break;
|
| 4702 |
|
|
case MULT: /* NAND */
|
| 4703 |
|
|
new_rtx = expand_simple_binop (SImode, AND, new_rtx, val,
|
| 4704 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4705 |
|
|
new_rtx = expand_simple_binop (SImode, XOR, new_rtx, ac.modemask,
|
| 4706 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
| 4707 |
|
|
break;
|
| 4708 |
|
|
default:
|
| 4709 |
|
|
gcc_unreachable ();
|
| 4710 |
|
|
}
|
| 4711 |
|
|
|
| 4712 |
|
|
s390_emit_jump (csloop, s390_emit_compare_and_swap (NE, cmp,
|
| 4713 |
|
|
ac.memsi, cmp, new_rtx));
|
| 4714 |
|
|
|
| 4715 |
|
|
/* Return the correct part of the bitfield. */
|
| 4716 |
|
|
if (target)
|
| 4717 |
|
|
convert_move (target, expand_simple_binop (SImode, LSHIFTRT,
|
| 4718 |
|
|
after ? new_rtx : cmp, ac.shift,
|
| 4719 |
|
|
NULL_RTX, 1, OPTAB_DIRECT), 1);
|
| 4720 |
|
|
}
|
| 4721 |
|
|
|
| 4722 |
|
|
/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
|
| 4723 |
|
|
We need to emit DTP-relative relocations. */
|
| 4724 |
|
|
|
| 4725 |
|
|
static void s390_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
|
| 4726 |
|
|
|
| 4727 |
|
|
static void
|
| 4728 |
|
|
s390_output_dwarf_dtprel (FILE *file, int size, rtx x)
|
| 4729 |
|
|
{
|
| 4730 |
|
|
switch (size)
|
| 4731 |
|
|
{
|
| 4732 |
|
|
case 4:
|
| 4733 |
|
|
fputs ("\t.long\t", file);
|
| 4734 |
|
|
break;
|
| 4735 |
|
|
case 8:
|
| 4736 |
|
|
fputs ("\t.quad\t", file);
|
| 4737 |
|
|
break;
|
| 4738 |
|
|
default:
|
| 4739 |
|
|
gcc_unreachable ();
|
| 4740 |
|
|
}
|
| 4741 |
|
|
output_addr_const (file, x);
|
| 4742 |
|
|
fputs ("@DTPOFF", file);
|
| 4743 |
|
|
}
|
| 4744 |
|
|
|
| 4745 |
|
|
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
|
| 4746 |
|
|
/* Implement TARGET_MANGLE_TYPE. */
|
| 4747 |
|
|
|
| 4748 |
|
|
static const char *
|
| 4749 |
|
|
s390_mangle_type (const_tree type)
|
| 4750 |
|
|
{
|
| 4751 |
|
|
if (TYPE_MAIN_VARIANT (type) == long_double_type_node
|
| 4752 |
|
|
&& TARGET_LONG_DOUBLE_128)
|
| 4753 |
|
|
return "g";
|
| 4754 |
|
|
|
| 4755 |
|
|
/* For all other types, use normal C++ mangling. */
|
| 4756 |
|
|
return NULL;
|
| 4757 |
|
|
}
|
| 4758 |
|
|
#endif
|
| 4759 |
|
|
|
| 4760 |
|
|
/* In the name of slightly smaller debug output, and to cater to
|
| 4761 |
|
|
general assembler lossage, recognize various UNSPEC sequences
|
| 4762 |
|
|
and turn them back into a direct symbol reference. */
|
| 4763 |
|
|
|
| 4764 |
|
|
static rtx
|
| 4765 |
|
|
s390_delegitimize_address (rtx orig_x)
|
| 4766 |
|
|
{
|
| 4767 |
|
|
rtx x, y;
|
| 4768 |
|
|
|
| 4769 |
|
|
orig_x = delegitimize_mem_from_attrs (orig_x);
|
| 4770 |
|
|
x = orig_x;
|
| 4771 |
|
|
if (GET_CODE (x) != MEM)
|
| 4772 |
|
|
return orig_x;
|
| 4773 |
|
|
|
| 4774 |
|
|
x = XEXP (x, 0);
|
| 4775 |
|
|
if (GET_CODE (x) == PLUS
|
| 4776 |
|
|
&& GET_CODE (XEXP (x, 1)) == CONST
|
| 4777 |
|
|
&& GET_CODE (XEXP (x, 0)) == REG
|
| 4778 |
|
|
&& REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
|
| 4779 |
|
|
{
|
| 4780 |
|
|
y = XEXP (XEXP (x, 1), 0);
|
| 4781 |
|
|
if (GET_CODE (y) == UNSPEC
|
| 4782 |
|
|
&& XINT (y, 1) == UNSPEC_GOT)
|
| 4783 |
|
|
return XVECEXP (y, 0, 0);
|
| 4784 |
|
|
return orig_x;
|
| 4785 |
|
|
}
|
| 4786 |
|
|
|
| 4787 |
|
|
if (GET_CODE (x) == CONST)
|
| 4788 |
|
|
{
|
| 4789 |
|
|
y = XEXP (x, 0);
|
| 4790 |
|
|
if (GET_CODE (y) == UNSPEC
|
| 4791 |
|
|
&& XINT (y, 1) == UNSPEC_GOTENT)
|
| 4792 |
|
|
return XVECEXP (y, 0, 0);
|
| 4793 |
|
|
return orig_x;
|
| 4794 |
|
|
}
|
| 4795 |
|
|
|
| 4796 |
|
|
return orig_x;
|
| 4797 |
|
|
}
|
| 4798 |
|
|
|
| 4799 |
|
|
/* Output operand OP to stdio stream FILE.
|
| 4800 |
|
|
OP is an address (register + offset) which is not used to address data;
|
| 4801 |
|
|
instead the rightmost bits are interpreted as the value. */
|
| 4802 |
|
|
|
| 4803 |
|
|
static void
|
| 4804 |
|
|
print_shift_count_operand (FILE *file, rtx op)
|
| 4805 |
|
|
{
|
| 4806 |
|
|
HOST_WIDE_INT offset;
|
| 4807 |
|
|
rtx base;
|
| 4808 |
|
|
|
| 4809 |
|
|
/* Extract base register and offset. */
|
| 4810 |
|
|
if (!s390_decompose_shift_count (op, &base, &offset))
|
| 4811 |
|
|
gcc_unreachable ();
|
| 4812 |
|
|
|
| 4813 |
|
|
/* Sanity check. */
|
| 4814 |
|
|
if (base)
|
| 4815 |
|
|
{
|
| 4816 |
|
|
gcc_assert (GET_CODE (base) == REG);
|
| 4817 |
|
|
gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER);
|
| 4818 |
|
|
gcc_assert (REGNO_REG_CLASS (REGNO (base)) == ADDR_REGS);
|
| 4819 |
|
|
}
|
| 4820 |
|
|
|
| 4821 |
|
|
/* Offsets are constricted to twelve bits. */
|
| 4822 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & ((1 << 12) - 1));
|
| 4823 |
|
|
if (base)
|
| 4824 |
|
|
fprintf (file, "(%s)", reg_names[REGNO (base)]);
|
| 4825 |
|
|
}
|
| 4826 |
|
|
|
| 4827 |
|
|
/* See 'get_some_local_dynamic_name'. */
|
| 4828 |
|
|
|
| 4829 |
|
|
static int
|
| 4830 |
|
|
get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
|
| 4831 |
|
|
{
|
| 4832 |
|
|
rtx x = *px;
|
| 4833 |
|
|
|
| 4834 |
|
|
if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
|
| 4835 |
|
|
{
|
| 4836 |
|
|
x = get_pool_constant (x);
|
| 4837 |
|
|
return for_each_rtx (&x, get_some_local_dynamic_name_1, 0);
|
| 4838 |
|
|
}
|
| 4839 |
|
|
|
| 4840 |
|
|
if (GET_CODE (x) == SYMBOL_REF
|
| 4841 |
|
|
&& tls_symbolic_operand (x) == TLS_MODEL_LOCAL_DYNAMIC)
|
| 4842 |
|
|
{
|
| 4843 |
|
|
cfun->machine->some_ld_name = XSTR (x, 0);
|
| 4844 |
|
|
return 1;
|
| 4845 |
|
|
}
|
| 4846 |
|
|
|
| 4847 |
|
|
return 0;
|
| 4848 |
|
|
}
|
| 4849 |
|
|
|
| 4850 |
|
|
/* Locate some local-dynamic symbol still in use by this function
|
| 4851 |
|
|
so that we can print its name in local-dynamic base patterns. */
|
| 4852 |
|
|
|
| 4853 |
|
|
static const char *
|
| 4854 |
|
|
get_some_local_dynamic_name (void)
|
| 4855 |
|
|
{
|
| 4856 |
|
|
rtx insn;
|
| 4857 |
|
|
|
| 4858 |
|
|
if (cfun->machine->some_ld_name)
|
| 4859 |
|
|
return cfun->machine->some_ld_name;
|
| 4860 |
|
|
|
| 4861 |
|
|
for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
|
| 4862 |
|
|
if (INSN_P (insn)
|
| 4863 |
|
|
&& for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
|
| 4864 |
|
|
return cfun->machine->some_ld_name;
|
| 4865 |
|
|
|
| 4866 |
|
|
gcc_unreachable ();
|
| 4867 |
|
|
}
|
| 4868 |
|
|
|
| 4869 |
|
|
/* Output machine-dependent UNSPECs occurring in address constant X
|
| 4870 |
|
|
in assembler syntax to stdio stream FILE. Returns true if the
|
| 4871 |
|
|
constant X could be recognized, false otherwise. */
|
| 4872 |
|
|
|
| 4873 |
|
|
bool
|
| 4874 |
|
|
s390_output_addr_const_extra (FILE *file, rtx x)
|
| 4875 |
|
|
{
|
| 4876 |
|
|
if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 1)
|
| 4877 |
|
|
switch (XINT (x, 1))
|
| 4878 |
|
|
{
|
| 4879 |
|
|
case UNSPEC_GOTENT:
|
| 4880 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4881 |
|
|
fprintf (file, "@GOTENT");
|
| 4882 |
|
|
return true;
|
| 4883 |
|
|
case UNSPEC_GOT:
|
| 4884 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4885 |
|
|
fprintf (file, "@GOT");
|
| 4886 |
|
|
return true;
|
| 4887 |
|
|
case UNSPEC_GOTOFF:
|
| 4888 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4889 |
|
|
fprintf (file, "@GOTOFF");
|
| 4890 |
|
|
return true;
|
| 4891 |
|
|
case UNSPEC_PLT:
|
| 4892 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4893 |
|
|
fprintf (file, "@PLT");
|
| 4894 |
|
|
return true;
|
| 4895 |
|
|
case UNSPEC_PLTOFF:
|
| 4896 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4897 |
|
|
fprintf (file, "@PLTOFF");
|
| 4898 |
|
|
return true;
|
| 4899 |
|
|
case UNSPEC_TLSGD:
|
| 4900 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4901 |
|
|
fprintf (file, "@TLSGD");
|
| 4902 |
|
|
return true;
|
| 4903 |
|
|
case UNSPEC_TLSLDM:
|
| 4904 |
|
|
assemble_name (file, get_some_local_dynamic_name ());
|
| 4905 |
|
|
fprintf (file, "@TLSLDM");
|
| 4906 |
|
|
return true;
|
| 4907 |
|
|
case UNSPEC_DTPOFF:
|
| 4908 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4909 |
|
|
fprintf (file, "@DTPOFF");
|
| 4910 |
|
|
return true;
|
| 4911 |
|
|
case UNSPEC_NTPOFF:
|
| 4912 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4913 |
|
|
fprintf (file, "@NTPOFF");
|
| 4914 |
|
|
return true;
|
| 4915 |
|
|
case UNSPEC_GOTNTPOFF:
|
| 4916 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4917 |
|
|
fprintf (file, "@GOTNTPOFF");
|
| 4918 |
|
|
return true;
|
| 4919 |
|
|
case UNSPEC_INDNTPOFF:
|
| 4920 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 4921 |
|
|
fprintf (file, "@INDNTPOFF");
|
| 4922 |
|
|
return true;
|
| 4923 |
|
|
}
|
| 4924 |
|
|
|
| 4925 |
|
|
if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 2)
|
| 4926 |
|
|
switch (XINT (x, 1))
|
| 4927 |
|
|
{
|
| 4928 |
|
|
case UNSPEC_POOL_OFFSET:
|
| 4929 |
|
|
x = gen_rtx_MINUS (GET_MODE (x), XVECEXP (x, 0, 0), XVECEXP (x, 0, 1));
|
| 4930 |
|
|
output_addr_const (file, x);
|
| 4931 |
|
|
return true;
|
| 4932 |
|
|
}
|
| 4933 |
|
|
return false;
|
| 4934 |
|
|
}
|
| 4935 |
|
|
|
| 4936 |
|
|
/* Output address operand ADDR in assembler syntax to
|
| 4937 |
|
|
stdio stream FILE. */
|
| 4938 |
|
|
|
| 4939 |
|
|
void
|
| 4940 |
|
|
print_operand_address (FILE *file, rtx addr)
|
| 4941 |
|
|
{
|
| 4942 |
|
|
struct s390_address ad;
|
| 4943 |
|
|
|
| 4944 |
|
|
if (s390_symref_operand_p (addr, NULL, NULL))
|
| 4945 |
|
|
{
|
| 4946 |
|
|
gcc_assert (TARGET_Z10);
|
| 4947 |
|
|
output_addr_const (file, addr);
|
| 4948 |
|
|
return;
|
| 4949 |
|
|
}
|
| 4950 |
|
|
|
| 4951 |
|
|
if (!s390_decompose_address (addr, &ad)
|
| 4952 |
|
|
|| (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base)))
|
| 4953 |
|
|
|| (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx))))
|
| 4954 |
|
|
output_operand_lossage ("cannot decompose address");
|
| 4955 |
|
|
|
| 4956 |
|
|
if (ad.disp)
|
| 4957 |
|
|
output_addr_const (file, ad.disp);
|
| 4958 |
|
|
else
|
| 4959 |
|
|
fprintf (file, "0");
|
| 4960 |
|
|
|
| 4961 |
|
|
if (ad.base && ad.indx)
|
| 4962 |
|
|
fprintf (file, "(%s,%s)", reg_names[REGNO (ad.indx)],
|
| 4963 |
|
|
reg_names[REGNO (ad.base)]);
|
| 4964 |
|
|
else if (ad.base)
|
| 4965 |
|
|
fprintf (file, "(%s)", reg_names[REGNO (ad.base)]);
|
| 4966 |
|
|
}
|
| 4967 |
|
|
|
| 4968 |
|
|
/* Output operand X in assembler syntax to stdio stream FILE.
|
| 4969 |
|
|
CODE specified the format flag. The following format flags
|
| 4970 |
|
|
are recognized:
|
| 4971 |
|
|
|
| 4972 |
|
|
'C': print opcode suffix for branch condition.
|
| 4973 |
|
|
'D': print opcode suffix for inverse branch condition.
|
| 4974 |
|
|
'E': print opcode suffix for branch on index instruction.
|
| 4975 |
|
|
'J': print tls_load/tls_gdcall/tls_ldcall suffix
|
| 4976 |
|
|
'G': print the size of the operand in bytes.
|
| 4977 |
|
|
'O': print only the displacement of a memory reference.
|
| 4978 |
|
|
'R': print only the base register of a memory reference.
|
| 4979 |
|
|
'S': print S-type memory reference (base+displacement).
|
| 4980 |
|
|
'N': print the second word of a DImode operand.
|
| 4981 |
|
|
'M': print the second word of a TImode operand.
|
| 4982 |
|
|
'Y': print shift count operand.
|
| 4983 |
|
|
|
| 4984 |
|
|
'b': print integer X as if it's an unsigned byte.
|
| 4985 |
|
|
'c': print integer X as if it's an signed byte.
|
| 4986 |
|
|
'x': print integer X as if it's an unsigned halfword.
|
| 4987 |
|
|
'h': print integer X as if it's a signed halfword.
|
| 4988 |
|
|
'i': print the first nonzero HImode part of X.
|
| 4989 |
|
|
'j': print the first HImode part unequal to -1 of X.
|
| 4990 |
|
|
'k': print the first nonzero SImode part of X.
|
| 4991 |
|
|
'm': print the first SImode part unequal to -1 of X.
|
| 4992 |
|
|
'o': print integer X as if it's an unsigned 32bit word. */
|
| 4993 |
|
|
|
| 4994 |
|
|
void
|
| 4995 |
|
|
print_operand (FILE *file, rtx x, int code)
|
| 4996 |
|
|
{
|
| 4997 |
|
|
switch (code)
|
| 4998 |
|
|
{
|
| 4999 |
|
|
case 'C':
|
| 5000 |
|
|
fprintf (file, s390_branch_condition_mnemonic (x, FALSE));
|
| 5001 |
|
|
return;
|
| 5002 |
|
|
|
| 5003 |
|
|
case 'D':
|
| 5004 |
|
|
fprintf (file, s390_branch_condition_mnemonic (x, TRUE));
|
| 5005 |
|
|
return;
|
| 5006 |
|
|
|
| 5007 |
|
|
case 'E':
|
| 5008 |
|
|
if (GET_CODE (x) == LE)
|
| 5009 |
|
|
fprintf (file, "l");
|
| 5010 |
|
|
else if (GET_CODE (x) == GT)
|
| 5011 |
|
|
fprintf (file, "h");
|
| 5012 |
|
|
else
|
| 5013 |
|
|
gcc_unreachable ();
|
| 5014 |
|
|
return;
|
| 5015 |
|
|
|
| 5016 |
|
|
case 'J':
|
| 5017 |
|
|
if (GET_CODE (x) == SYMBOL_REF)
|
| 5018 |
|
|
{
|
| 5019 |
|
|
fprintf (file, "%s", ":tls_load:");
|
| 5020 |
|
|
output_addr_const (file, x);
|
| 5021 |
|
|
}
|
| 5022 |
|
|
else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
|
| 5023 |
|
|
{
|
| 5024 |
|
|
fprintf (file, "%s", ":tls_gdcall:");
|
| 5025 |
|
|
output_addr_const (file, XVECEXP (x, 0, 0));
|
| 5026 |
|
|
}
|
| 5027 |
|
|
else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM)
|
| 5028 |
|
|
{
|
| 5029 |
|
|
fprintf (file, "%s", ":tls_ldcall:");
|
| 5030 |
|
|
assemble_name (file, get_some_local_dynamic_name ());
|
| 5031 |
|
|
}
|
| 5032 |
|
|
else
|
| 5033 |
|
|
gcc_unreachable ();
|
| 5034 |
|
|
return;
|
| 5035 |
|
|
|
| 5036 |
|
|
case 'G':
|
| 5037 |
|
|
fprintf (file, "%u", GET_MODE_SIZE (GET_MODE (x)));
|
| 5038 |
|
|
return;
|
| 5039 |
|
|
|
| 5040 |
|
|
case 'O':
|
| 5041 |
|
|
{
|
| 5042 |
|
|
struct s390_address ad;
|
| 5043 |
|
|
int ret;
|
| 5044 |
|
|
|
| 5045 |
|
|
gcc_assert (GET_CODE (x) == MEM);
|
| 5046 |
|
|
ret = s390_decompose_address (XEXP (x, 0), &ad);
|
| 5047 |
|
|
gcc_assert (ret);
|
| 5048 |
|
|
gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base)));
|
| 5049 |
|
|
gcc_assert (!ad.indx);
|
| 5050 |
|
|
|
| 5051 |
|
|
if (ad.disp)
|
| 5052 |
|
|
output_addr_const (file, ad.disp);
|
| 5053 |
|
|
else
|
| 5054 |
|
|
fprintf (file, "0");
|
| 5055 |
|
|
}
|
| 5056 |
|
|
return;
|
| 5057 |
|
|
|
| 5058 |
|
|
case 'R':
|
| 5059 |
|
|
{
|
| 5060 |
|
|
struct s390_address ad;
|
| 5061 |
|
|
int ret;
|
| 5062 |
|
|
|
| 5063 |
|
|
gcc_assert (GET_CODE (x) == MEM);
|
| 5064 |
|
|
ret = s390_decompose_address (XEXP (x, 0), &ad);
|
| 5065 |
|
|
gcc_assert (ret);
|
| 5066 |
|
|
gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base)));
|
| 5067 |
|
|
gcc_assert (!ad.indx);
|
| 5068 |
|
|
|
| 5069 |
|
|
if (ad.base)
|
| 5070 |
|
|
fprintf (file, "%s", reg_names[REGNO (ad.base)]);
|
| 5071 |
|
|
else
|
| 5072 |
|
|
fprintf (file, "0");
|
| 5073 |
|
|
}
|
| 5074 |
|
|
return;
|
| 5075 |
|
|
|
| 5076 |
|
|
case 'S':
|
| 5077 |
|
|
{
|
| 5078 |
|
|
struct s390_address ad;
|
| 5079 |
|
|
int ret;
|
| 5080 |
|
|
|
| 5081 |
|
|
gcc_assert (GET_CODE (x) == MEM);
|
| 5082 |
|
|
ret = s390_decompose_address (XEXP (x, 0), &ad);
|
| 5083 |
|
|
gcc_assert (ret);
|
| 5084 |
|
|
gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base)));
|
| 5085 |
|
|
gcc_assert (!ad.indx);
|
| 5086 |
|
|
|
| 5087 |
|
|
if (ad.disp)
|
| 5088 |
|
|
output_addr_const (file, ad.disp);
|
| 5089 |
|
|
else
|
| 5090 |
|
|
fprintf (file, "0");
|
| 5091 |
|
|
|
| 5092 |
|
|
if (ad.base)
|
| 5093 |
|
|
fprintf (file, "(%s)", reg_names[REGNO (ad.base)]);
|
| 5094 |
|
|
}
|
| 5095 |
|
|
return;
|
| 5096 |
|
|
|
| 5097 |
|
|
case 'N':
|
| 5098 |
|
|
if (GET_CODE (x) == REG)
|
| 5099 |
|
|
x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1);
|
| 5100 |
|
|
else if (GET_CODE (x) == MEM)
|
| 5101 |
|
|
x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 4));
|
| 5102 |
|
|
else
|
| 5103 |
|
|
gcc_unreachable ();
|
| 5104 |
|
|
break;
|
| 5105 |
|
|
|
| 5106 |
|
|
case 'M':
|
| 5107 |
|
|
if (GET_CODE (x) == REG)
|
| 5108 |
|
|
x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1);
|
| 5109 |
|
|
else if (GET_CODE (x) == MEM)
|
| 5110 |
|
|
x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 8));
|
| 5111 |
|
|
else
|
| 5112 |
|
|
gcc_unreachable ();
|
| 5113 |
|
|
break;
|
| 5114 |
|
|
|
| 5115 |
|
|
case 'Y':
|
| 5116 |
|
|
print_shift_count_operand (file, x);
|
| 5117 |
|
|
return;
|
| 5118 |
|
|
}
|
| 5119 |
|
|
|
| 5120 |
|
|
switch (GET_CODE (x))
|
| 5121 |
|
|
{
|
| 5122 |
|
|
case REG:
|
| 5123 |
|
|
fprintf (file, "%s", reg_names[REGNO (x)]);
|
| 5124 |
|
|
break;
|
| 5125 |
|
|
|
| 5126 |
|
|
case MEM:
|
| 5127 |
|
|
output_address (XEXP (x, 0));
|
| 5128 |
|
|
break;
|
| 5129 |
|
|
|
| 5130 |
|
|
case CONST:
|
| 5131 |
|
|
case CODE_LABEL:
|
| 5132 |
|
|
case LABEL_REF:
|
| 5133 |
|
|
case SYMBOL_REF:
|
| 5134 |
|
|
output_addr_const (file, x);
|
| 5135 |
|
|
break;
|
| 5136 |
|
|
|
| 5137 |
|
|
case CONST_INT:
|
| 5138 |
|
|
if (code == 'b')
|
| 5139 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff);
|
| 5140 |
|
|
else if (code == 'c')
|
| 5141 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xff) ^ 0x80) - 0x80);
|
| 5142 |
|
|
else if (code == 'x')
|
| 5143 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff);
|
| 5144 |
|
|
else if (code == 'h')
|
| 5145 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000);
|
| 5146 |
|
|
else if (code == 'i')
|
| 5147 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC,
|
| 5148 |
|
|
s390_extract_part (x, HImode, 0));
|
| 5149 |
|
|
else if (code == 'j')
|
| 5150 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC,
|
| 5151 |
|
|
s390_extract_part (x, HImode, -1));
|
| 5152 |
|
|
else if (code == 'k')
|
| 5153 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC,
|
| 5154 |
|
|
s390_extract_part (x, SImode, 0));
|
| 5155 |
|
|
else if (code == 'm')
|
| 5156 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC,
|
| 5157 |
|
|
s390_extract_part (x, SImode, -1));
|
| 5158 |
|
|
else if (code == 'o')
|
| 5159 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffffffff);
|
| 5160 |
|
|
else
|
| 5161 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
|
| 5162 |
|
|
break;
|
| 5163 |
|
|
|
| 5164 |
|
|
case CONST_DOUBLE:
|
| 5165 |
|
|
gcc_assert (GET_MODE (x) == VOIDmode);
|
| 5166 |
|
|
if (code == 'b')
|
| 5167 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xff);
|
| 5168 |
|
|
else if (code == 'x')
|
| 5169 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xffff);
|
| 5170 |
|
|
else if (code == 'h')
|
| 5171 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000);
|
| 5172 |
|
|
else
|
| 5173 |
|
|
gcc_unreachable ();
|
| 5174 |
|
|
break;
|
| 5175 |
|
|
|
| 5176 |
|
|
default:
|
| 5177 |
|
|
fatal_insn ("UNKNOWN in print_operand !?", x);
|
| 5178 |
|
|
break;
|
| 5179 |
|
|
}
|
| 5180 |
|
|
}
|
| 5181 |
|
|
|
| 5182 |
|
|
/* Target hook for assembling integer objects. We need to define it
|
| 5183 |
|
|
here to work a round a bug in some versions of GAS, which couldn't
|
| 5184 |
|
|
handle values smaller than INT_MIN when printed in decimal. */
|
| 5185 |
|
|
|
| 5186 |
|
|
static bool
|
| 5187 |
|
|
s390_assemble_integer (rtx x, unsigned int size, int aligned_p)
|
| 5188 |
|
|
{
|
| 5189 |
|
|
if (size == 8 && aligned_p
|
| 5190 |
|
|
&& GET_CODE (x) == CONST_INT && INTVAL (x) < INT_MIN)
|
| 5191 |
|
|
{
|
| 5192 |
|
|
fprintf (asm_out_file, "\t.quad\t" HOST_WIDE_INT_PRINT_HEX "\n",
|
| 5193 |
|
|
INTVAL (x));
|
| 5194 |
|
|
return true;
|
| 5195 |
|
|
}
|
| 5196 |
|
|
return default_assemble_integer (x, size, aligned_p);
|
| 5197 |
|
|
}
|
| 5198 |
|
|
|
| 5199 |
|
|
/* Returns true if register REGNO is used for forming
|
| 5200 |
|
|
a memory address in expression X. */
|
| 5201 |
|
|
|
| 5202 |
|
|
static bool
|
| 5203 |
|
|
reg_used_in_mem_p (int regno, rtx x)
|
| 5204 |
|
|
{
|
| 5205 |
|
|
enum rtx_code code = GET_CODE (x);
|
| 5206 |
|
|
int i, j;
|
| 5207 |
|
|
const char *fmt;
|
| 5208 |
|
|
|
| 5209 |
|
|
if (code == MEM)
|
| 5210 |
|
|
{
|
| 5211 |
|
|
if (refers_to_regno_p (regno, regno+1,
|
| 5212 |
|
|
XEXP (x, 0), 0))
|
| 5213 |
|
|
return true;
|
| 5214 |
|
|
}
|
| 5215 |
|
|
else if (code == SET
|
| 5216 |
|
|
&& GET_CODE (SET_DEST (x)) == PC)
|
| 5217 |
|
|
{
|
| 5218 |
|
|
if (refers_to_regno_p (regno, regno+1,
|
| 5219 |
|
|
SET_SRC (x), 0))
|
| 5220 |
|
|
return true;
|
| 5221 |
|
|
}
|
| 5222 |
|
|
|
| 5223 |
|
|
fmt = GET_RTX_FORMAT (code);
|
| 5224 |
|
|
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
| 5225 |
|
|
{
|
| 5226 |
|
|
if (fmt[i] == 'e'
|
| 5227 |
|
|
&& reg_used_in_mem_p (regno, XEXP (x, i)))
|
| 5228 |
|
|
return true;
|
| 5229 |
|
|
|
| 5230 |
|
|
else if (fmt[i] == 'E')
|
| 5231 |
|
|
for (j = 0; j < XVECLEN (x, i); j++)
|
| 5232 |
|
|
if (reg_used_in_mem_p (regno, XVECEXP (x, i, j)))
|
| 5233 |
|
|
return true;
|
| 5234 |
|
|
}
|
| 5235 |
|
|
return false;
|
| 5236 |
|
|
}
|
| 5237 |
|
|
|
| 5238 |
|
|
/* Returns true if expression DEP_RTX sets an address register
|
| 5239 |
|
|
used by instruction INSN to address memory. */
|
| 5240 |
|
|
|
| 5241 |
|
|
static bool
|
| 5242 |
|
|
addr_generation_dependency_p (rtx dep_rtx, rtx insn)
|
| 5243 |
|
|
{
|
| 5244 |
|
|
rtx target, pat;
|
| 5245 |
|
|
|
| 5246 |
|
|
if (GET_CODE (dep_rtx) == INSN)
|
| 5247 |
|
|
dep_rtx = PATTERN (dep_rtx);
|
| 5248 |
|
|
|
| 5249 |
|
|
if (GET_CODE (dep_rtx) == SET)
|
| 5250 |
|
|
{
|
| 5251 |
|
|
target = SET_DEST (dep_rtx);
|
| 5252 |
|
|
if (GET_CODE (target) == STRICT_LOW_PART)
|
| 5253 |
|
|
target = XEXP (target, 0);
|
| 5254 |
|
|
while (GET_CODE (target) == SUBREG)
|
| 5255 |
|
|
target = SUBREG_REG (target);
|
| 5256 |
|
|
|
| 5257 |
|
|
if (GET_CODE (target) == REG)
|
| 5258 |
|
|
{
|
| 5259 |
|
|
int regno = REGNO (target);
|
| 5260 |
|
|
|
| 5261 |
|
|
if (s390_safe_attr_type (insn) == TYPE_LA)
|
| 5262 |
|
|
{
|
| 5263 |
|
|
pat = PATTERN (insn);
|
| 5264 |
|
|
if (GET_CODE (pat) == PARALLEL)
|
| 5265 |
|
|
{
|
| 5266 |
|
|
gcc_assert (XVECLEN (pat, 0) == 2);
|
| 5267 |
|
|
pat = XVECEXP (pat, 0, 0);
|
| 5268 |
|
|
}
|
| 5269 |
|
|
gcc_assert (GET_CODE (pat) == SET);
|
| 5270 |
|
|
return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0);
|
| 5271 |
|
|
}
|
| 5272 |
|
|
else if (get_attr_atype (insn) == ATYPE_AGEN)
|
| 5273 |
|
|
return reg_used_in_mem_p (regno, PATTERN (insn));
|
| 5274 |
|
|
}
|
| 5275 |
|
|
}
|
| 5276 |
|
|
return false;
|
| 5277 |
|
|
}
|
| 5278 |
|
|
|
| 5279 |
|
|
/* Return 1, if dep_insn sets register used in insn in the agen unit. */
|
| 5280 |
|
|
|
| 5281 |
|
|
int
|
| 5282 |
|
|
s390_agen_dep_p (rtx dep_insn, rtx insn)
|
| 5283 |
|
|
{
|
| 5284 |
|
|
rtx dep_rtx = PATTERN (dep_insn);
|
| 5285 |
|
|
int i;
|
| 5286 |
|
|
|
| 5287 |
|
|
if (GET_CODE (dep_rtx) == SET
|
| 5288 |
|
|
&& addr_generation_dependency_p (dep_rtx, insn))
|
| 5289 |
|
|
return 1;
|
| 5290 |
|
|
else if (GET_CODE (dep_rtx) == PARALLEL)
|
| 5291 |
|
|
{
|
| 5292 |
|
|
for (i = 0; i < XVECLEN (dep_rtx, 0); i++)
|
| 5293 |
|
|
{
|
| 5294 |
|
|
if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), insn))
|
| 5295 |
|
|
return 1;
|
| 5296 |
|
|
}
|
| 5297 |
|
|
}
|
| 5298 |
|
|
return 0;
|
| 5299 |
|
|
}
|
| 5300 |
|
|
|
| 5301 |
|
|
|
| 5302 |
|
|
/* A C statement (sans semicolon) to update the integer scheduling priority
|
| 5303 |
|
|
INSN_PRIORITY (INSN). Increase the priority to execute the INSN earlier,
|
| 5304 |
|
|
reduce the priority to execute INSN later. Do not define this macro if
|
| 5305 |
|
|
you do not need to adjust the scheduling priorities of insns.
|
| 5306 |
|
|
|
| 5307 |
|
|
A STD instruction should be scheduled earlier,
|
| 5308 |
|
|
in order to use the bypass. */
|
| 5309 |
|
|
|
| 5310 |
|
|
|
| 5311 |
|
|
static int
|
| 5312 |
|
|
s390_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
|
| 5313 |
|
|
{
|
| 5314 |
|
|
if (! INSN_P (insn))
|
| 5315 |
|
|
return priority;
|
| 5316 |
|
|
|
| 5317 |
|
|
if (s390_tune != PROCESSOR_2084_Z990
|
| 5318 |
|
|
&& s390_tune != PROCESSOR_2094_Z9_109
|
| 5319 |
|
|
&& s390_tune != PROCESSOR_2097_Z10)
|
| 5320 |
|
|
return priority;
|
| 5321 |
|
|
|
| 5322 |
|
|
switch (s390_safe_attr_type (insn))
|
| 5323 |
|
|
{
|
| 5324 |
|
|
case TYPE_FSTOREDF:
|
| 5325 |
|
|
case TYPE_FSTORESF:
|
| 5326 |
|
|
priority = priority << 3;
|
| 5327 |
|
|
break;
|
| 5328 |
|
|
case TYPE_STORE:
|
| 5329 |
|
|
case TYPE_STM:
|
| 5330 |
|
|
priority = priority << 1;
|
| 5331 |
|
|
break;
|
| 5332 |
|
|
default:
|
| 5333 |
|
|
break;
|
| 5334 |
|
|
}
|
| 5335 |
|
|
return priority;
|
| 5336 |
|
|
}
|
| 5337 |
|
|
|
| 5338 |
|
|
|
| 5339 |
|
|
/* The number of instructions that can be issued per cycle. */
|
| 5340 |
|
|
|
| 5341 |
|
|
static int
|
| 5342 |
|
|
s390_issue_rate (void)
|
| 5343 |
|
|
{
|
| 5344 |
|
|
switch (s390_tune)
|
| 5345 |
|
|
{
|
| 5346 |
|
|
case PROCESSOR_2084_Z990:
|
| 5347 |
|
|
case PROCESSOR_2094_Z9_109:
|
| 5348 |
|
|
return 3;
|
| 5349 |
|
|
case PROCESSOR_2097_Z10:
|
| 5350 |
|
|
return 2;
|
| 5351 |
|
|
default:
|
| 5352 |
|
|
return 1;
|
| 5353 |
|
|
}
|
| 5354 |
|
|
}
|
| 5355 |
|
|
|
| 5356 |
|
|
static int
|
| 5357 |
|
|
s390_first_cycle_multipass_dfa_lookahead (void)
|
| 5358 |
|
|
{
|
| 5359 |
|
|
return 4;
|
| 5360 |
|
|
}
|
| 5361 |
|
|
|
| 5362 |
|
|
|
| 5363 |
|
|
/* Annotate every literal pool reference in X by an UNSPEC_LTREF expression.
|
| 5364 |
|
|
Fix up MEMs as required. */
|
| 5365 |
|
|
|
| 5366 |
|
|
static void
|
| 5367 |
|
|
annotate_constant_pool_refs (rtx *x)
|
| 5368 |
|
|
{
|
| 5369 |
|
|
int i, j;
|
| 5370 |
|
|
const char *fmt;
|
| 5371 |
|
|
|
| 5372 |
|
|
gcc_assert (GET_CODE (*x) != SYMBOL_REF
|
| 5373 |
|
|
|| !CONSTANT_POOL_ADDRESS_P (*x));
|
| 5374 |
|
|
|
| 5375 |
|
|
/* Literal pool references can only occur inside a MEM ... */
|
| 5376 |
|
|
if (GET_CODE (*x) == MEM)
|
| 5377 |
|
|
{
|
| 5378 |
|
|
rtx memref = XEXP (*x, 0);
|
| 5379 |
|
|
|
| 5380 |
|
|
if (GET_CODE (memref) == SYMBOL_REF
|
| 5381 |
|
|
&& CONSTANT_POOL_ADDRESS_P (memref))
|
| 5382 |
|
|
{
|
| 5383 |
|
|
rtx base = cfun->machine->base_reg;
|
| 5384 |
|
|
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, memref, base),
|
| 5385 |
|
|
UNSPEC_LTREF);
|
| 5386 |
|
|
|
| 5387 |
|
|
*x = replace_equiv_address (*x, addr);
|
| 5388 |
|
|
return;
|
| 5389 |
|
|
}
|
| 5390 |
|
|
|
| 5391 |
|
|
if (GET_CODE (memref) == CONST
|
| 5392 |
|
|
&& GET_CODE (XEXP (memref, 0)) == PLUS
|
| 5393 |
|
|
&& GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT
|
| 5394 |
|
|
&& GET_CODE (XEXP (XEXP (memref, 0), 0)) == SYMBOL_REF
|
| 5395 |
|
|
&& CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (memref, 0), 0)))
|
| 5396 |
|
|
{
|
| 5397 |
|
|
HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
|
| 5398 |
|
|
rtx sym = XEXP (XEXP (memref, 0), 0);
|
| 5399 |
|
|
rtx base = cfun->machine->base_reg;
|
| 5400 |
|
|
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
|
| 5401 |
|
|
UNSPEC_LTREF);
|
| 5402 |
|
|
|
| 5403 |
|
|
*x = replace_equiv_address (*x, plus_constant (addr, off));
|
| 5404 |
|
|
return;
|
| 5405 |
|
|
}
|
| 5406 |
|
|
}
|
| 5407 |
|
|
|
| 5408 |
|
|
/* ... or a load-address type pattern. */
|
| 5409 |
|
|
if (GET_CODE (*x) == SET)
|
| 5410 |
|
|
{
|
| 5411 |
|
|
rtx addrref = SET_SRC (*x);
|
| 5412 |
|
|
|
| 5413 |
|
|
if (GET_CODE (addrref) == SYMBOL_REF
|
| 5414 |
|
|
&& CONSTANT_POOL_ADDRESS_P (addrref))
|
| 5415 |
|
|
{
|
| 5416 |
|
|
rtx base = cfun->machine->base_reg;
|
| 5417 |
|
|
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addrref, base),
|
| 5418 |
|
|
UNSPEC_LTREF);
|
| 5419 |
|
|
|
| 5420 |
|
|
SET_SRC (*x) = addr;
|
| 5421 |
|
|
return;
|
| 5422 |
|
|
}
|
| 5423 |
|
|
|
| 5424 |
|
|
if (GET_CODE (addrref) == CONST
|
| 5425 |
|
|
&& GET_CODE (XEXP (addrref, 0)) == PLUS
|
| 5426 |
|
|
&& GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT
|
| 5427 |
|
|
&& GET_CODE (XEXP (XEXP (addrref, 0), 0)) == SYMBOL_REF
|
| 5428 |
|
|
&& CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (addrref, 0), 0)))
|
| 5429 |
|
|
{
|
| 5430 |
|
|
HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
|
| 5431 |
|
|
rtx sym = XEXP (XEXP (addrref, 0), 0);
|
| 5432 |
|
|
rtx base = cfun->machine->base_reg;
|
| 5433 |
|
|
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
|
| 5434 |
|
|
UNSPEC_LTREF);
|
| 5435 |
|
|
|
| 5436 |
|
|
SET_SRC (*x) = plus_constant (addr, off);
|
| 5437 |
|
|
return;
|
| 5438 |
|
|
}
|
| 5439 |
|
|
}
|
| 5440 |
|
|
|
| 5441 |
|
|
/* Annotate LTREL_BASE as well. */
|
| 5442 |
|
|
if (GET_CODE (*x) == UNSPEC
|
| 5443 |
|
|
&& XINT (*x, 1) == UNSPEC_LTREL_BASE)
|
| 5444 |
|
|
{
|
| 5445 |
|
|
rtx base = cfun->machine->base_reg;
|
| 5446 |
|
|
*x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XVECEXP (*x, 0, 0), base),
|
| 5447 |
|
|
UNSPEC_LTREL_BASE);
|
| 5448 |
|
|
return;
|
| 5449 |
|
|
}
|
| 5450 |
|
|
|
| 5451 |
|
|
fmt = GET_RTX_FORMAT (GET_CODE (*x));
|
| 5452 |
|
|
for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
|
| 5453 |
|
|
{
|
| 5454 |
|
|
if (fmt[i] == 'e')
|
| 5455 |
|
|
{
|
| 5456 |
|
|
annotate_constant_pool_refs (&XEXP (*x, i));
|
| 5457 |
|
|
}
|
| 5458 |
|
|
else if (fmt[i] == 'E')
|
| 5459 |
|
|
{
|
| 5460 |
|
|
for (j = 0; j < XVECLEN (*x, i); j++)
|
| 5461 |
|
|
annotate_constant_pool_refs (&XVECEXP (*x, i, j));
|
| 5462 |
|
|
}
|
| 5463 |
|
|
}
|
| 5464 |
|
|
}
|
| 5465 |
|
|
|
| 5466 |
|
|
/* Split all branches that exceed the maximum distance.
|
| 5467 |
|
|
Returns true if this created a new literal pool entry. */
|
| 5468 |
|
|
|
| 5469 |
|
|
static int
|
| 5470 |
|
|
s390_split_branches (void)
|
| 5471 |
|
|
{
|
| 5472 |
|
|
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
|
| 5473 |
|
|
int new_literal = 0, ret;
|
| 5474 |
|
|
rtx insn, pat, tmp, target;
|
| 5475 |
|
|
rtx *label;
|
| 5476 |
|
|
|
| 5477 |
|
|
/* We need correct insn addresses. */
|
| 5478 |
|
|
|
| 5479 |
|
|
shorten_branches (get_insns ());
|
| 5480 |
|
|
|
| 5481 |
|
|
/* Find all branches that exceed 64KB, and split them. */
|
| 5482 |
|
|
|
| 5483 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 5484 |
|
|
{
|
| 5485 |
|
|
if (GET_CODE (insn) != JUMP_INSN)
|
| 5486 |
|
|
continue;
|
| 5487 |
|
|
|
| 5488 |
|
|
pat = PATTERN (insn);
|
| 5489 |
|
|
if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2)
|
| 5490 |
|
|
pat = XVECEXP (pat, 0, 0);
|
| 5491 |
|
|
if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx)
|
| 5492 |
|
|
continue;
|
| 5493 |
|
|
|
| 5494 |
|
|
if (GET_CODE (SET_SRC (pat)) == LABEL_REF)
|
| 5495 |
|
|
{
|
| 5496 |
|
|
label = &SET_SRC (pat);
|
| 5497 |
|
|
}
|
| 5498 |
|
|
else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
|
| 5499 |
|
|
{
|
| 5500 |
|
|
if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
|
| 5501 |
|
|
label = &XEXP (SET_SRC (pat), 1);
|
| 5502 |
|
|
else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF)
|
| 5503 |
|
|
label = &XEXP (SET_SRC (pat), 2);
|
| 5504 |
|
|
else
|
| 5505 |
|
|
continue;
|
| 5506 |
|
|
}
|
| 5507 |
|
|
else
|
| 5508 |
|
|
continue;
|
| 5509 |
|
|
|
| 5510 |
|
|
if (get_attr_length (insn) <= 4)
|
| 5511 |
|
|
continue;
|
| 5512 |
|
|
|
| 5513 |
|
|
/* We are going to use the return register as scratch register,
|
| 5514 |
|
|
make sure it will be saved/restored by the prologue/epilogue. */
|
| 5515 |
|
|
cfun_frame_layout.save_return_addr_p = 1;
|
| 5516 |
|
|
|
| 5517 |
|
|
if (!flag_pic)
|
| 5518 |
|
|
{
|
| 5519 |
|
|
new_literal = 1;
|
| 5520 |
|
|
tmp = force_const_mem (Pmode, *label);
|
| 5521 |
|
|
tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
|
| 5522 |
|
|
INSN_ADDRESSES_NEW (tmp, -1);
|
| 5523 |
|
|
annotate_constant_pool_refs (&PATTERN (tmp));
|
| 5524 |
|
|
|
| 5525 |
|
|
target = temp_reg;
|
| 5526 |
|
|
}
|
| 5527 |
|
|
else
|
| 5528 |
|
|
{
|
| 5529 |
|
|
new_literal = 1;
|
| 5530 |
|
|
target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, *label),
|
| 5531 |
|
|
UNSPEC_LTREL_OFFSET);
|
| 5532 |
|
|
target = gen_rtx_CONST (Pmode, target);
|
| 5533 |
|
|
target = force_const_mem (Pmode, target);
|
| 5534 |
|
|
tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn);
|
| 5535 |
|
|
INSN_ADDRESSES_NEW (tmp, -1);
|
| 5536 |
|
|
annotate_constant_pool_refs (&PATTERN (tmp));
|
| 5537 |
|
|
|
| 5538 |
|
|
target = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XEXP (target, 0),
|
| 5539 |
|
|
cfun->machine->base_reg),
|
| 5540 |
|
|
UNSPEC_LTREL_BASE);
|
| 5541 |
|
|
target = gen_rtx_PLUS (Pmode, temp_reg, target);
|
| 5542 |
|
|
}
|
| 5543 |
|
|
|
| 5544 |
|
|
ret = validate_change (insn, label, target, 0);
|
| 5545 |
|
|
gcc_assert (ret);
|
| 5546 |
|
|
}
|
| 5547 |
|
|
|
| 5548 |
|
|
return new_literal;
|
| 5549 |
|
|
}
|
| 5550 |
|
|
|
| 5551 |
|
|
|
| 5552 |
|
|
/* Find an annotated literal pool symbol referenced in RTX X,
|
| 5553 |
|
|
and store it at REF. Will abort if X contains references to
|
| 5554 |
|
|
more than one such pool symbol; multiple references to the same
|
| 5555 |
|
|
symbol are allowed, however.
|
| 5556 |
|
|
|
| 5557 |
|
|
The rtx pointed to by REF must be initialized to NULL_RTX
|
| 5558 |
|
|
by the caller before calling this routine. */
|
| 5559 |
|
|
|
| 5560 |
|
|
static void
|
| 5561 |
|
|
find_constant_pool_ref (rtx x, rtx *ref)
|
| 5562 |
|
|
{
|
| 5563 |
|
|
int i, j;
|
| 5564 |
|
|
const char *fmt;
|
| 5565 |
|
|
|
| 5566 |
|
|
/* Ignore LTREL_BASE references. */
|
| 5567 |
|
|
if (GET_CODE (x) == UNSPEC
|
| 5568 |
|
|
&& XINT (x, 1) == UNSPEC_LTREL_BASE)
|
| 5569 |
|
|
return;
|
| 5570 |
|
|
/* Likewise POOL_ENTRY insns. */
|
| 5571 |
|
|
if (GET_CODE (x) == UNSPEC_VOLATILE
|
| 5572 |
|
|
&& XINT (x, 1) == UNSPECV_POOL_ENTRY)
|
| 5573 |
|
|
return;
|
| 5574 |
|
|
|
| 5575 |
|
|
gcc_assert (GET_CODE (x) != SYMBOL_REF
|
| 5576 |
|
|
|| !CONSTANT_POOL_ADDRESS_P (x));
|
| 5577 |
|
|
|
| 5578 |
|
|
if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_LTREF)
|
| 5579 |
|
|
{
|
| 5580 |
|
|
rtx sym = XVECEXP (x, 0, 0);
|
| 5581 |
|
|
gcc_assert (GET_CODE (sym) == SYMBOL_REF
|
| 5582 |
|
|
&& CONSTANT_POOL_ADDRESS_P (sym));
|
| 5583 |
|
|
|
| 5584 |
|
|
if (*ref == NULL_RTX)
|
| 5585 |
|
|
*ref = sym;
|
| 5586 |
|
|
else
|
| 5587 |
|
|
gcc_assert (*ref == sym);
|
| 5588 |
|
|
|
| 5589 |
|
|
return;
|
| 5590 |
|
|
}
|
| 5591 |
|
|
|
| 5592 |
|
|
fmt = GET_RTX_FORMAT (GET_CODE (x));
|
| 5593 |
|
|
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
|
| 5594 |
|
|
{
|
| 5595 |
|
|
if (fmt[i] == 'e')
|
| 5596 |
|
|
{
|
| 5597 |
|
|
find_constant_pool_ref (XEXP (x, i), ref);
|
| 5598 |
|
|
}
|
| 5599 |
|
|
else if (fmt[i] == 'E')
|
| 5600 |
|
|
{
|
| 5601 |
|
|
for (j = 0; j < XVECLEN (x, i); j++)
|
| 5602 |
|
|
find_constant_pool_ref (XVECEXP (x, i, j), ref);
|
| 5603 |
|
|
}
|
| 5604 |
|
|
}
|
| 5605 |
|
|
}
|
| 5606 |
|
|
|
| 5607 |
|
|
/* Replace every reference to the annotated literal pool
|
| 5608 |
|
|
symbol REF in X by its base plus OFFSET. */
|
| 5609 |
|
|
|
| 5610 |
|
|
static void
|
| 5611 |
|
|
replace_constant_pool_ref (rtx *x, rtx ref, rtx offset)
|
| 5612 |
|
|
{
|
| 5613 |
|
|
int i, j;
|
| 5614 |
|
|
const char *fmt;
|
| 5615 |
|
|
|
| 5616 |
|
|
gcc_assert (*x != ref);
|
| 5617 |
|
|
|
| 5618 |
|
|
if (GET_CODE (*x) == UNSPEC
|
| 5619 |
|
|
&& XINT (*x, 1) == UNSPEC_LTREF
|
| 5620 |
|
|
&& XVECEXP (*x, 0, 0) == ref)
|
| 5621 |
|
|
{
|
| 5622 |
|
|
*x = gen_rtx_PLUS (Pmode, XVECEXP (*x, 0, 1), offset);
|
| 5623 |
|
|
return;
|
| 5624 |
|
|
}
|
| 5625 |
|
|
|
| 5626 |
|
|
if (GET_CODE (*x) == PLUS
|
| 5627 |
|
|
&& GET_CODE (XEXP (*x, 1)) == CONST_INT
|
| 5628 |
|
|
&& GET_CODE (XEXP (*x, 0)) == UNSPEC
|
| 5629 |
|
|
&& XINT (XEXP (*x, 0), 1) == UNSPEC_LTREF
|
| 5630 |
|
|
&& XVECEXP (XEXP (*x, 0), 0, 0) == ref)
|
| 5631 |
|
|
{
|
| 5632 |
|
|
rtx addr = gen_rtx_PLUS (Pmode, XVECEXP (XEXP (*x, 0), 0, 1), offset);
|
| 5633 |
|
|
*x = plus_constant (addr, INTVAL (XEXP (*x, 1)));
|
| 5634 |
|
|
return;
|
| 5635 |
|
|
}
|
| 5636 |
|
|
|
| 5637 |
|
|
fmt = GET_RTX_FORMAT (GET_CODE (*x));
|
| 5638 |
|
|
for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
|
| 5639 |
|
|
{
|
| 5640 |
|
|
if (fmt[i] == 'e')
|
| 5641 |
|
|
{
|
| 5642 |
|
|
replace_constant_pool_ref (&XEXP (*x, i), ref, offset);
|
| 5643 |
|
|
}
|
| 5644 |
|
|
else if (fmt[i] == 'E')
|
| 5645 |
|
|
{
|
| 5646 |
|
|
for (j = 0; j < XVECLEN (*x, i); j++)
|
| 5647 |
|
|
replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset);
|
| 5648 |
|
|
}
|
| 5649 |
|
|
}
|
| 5650 |
|
|
}
|
| 5651 |
|
|
|
| 5652 |
|
|
/* Check whether X contains an UNSPEC_LTREL_BASE.
|
| 5653 |
|
|
Return its constant pool symbol if found, NULL_RTX otherwise. */
|
| 5654 |
|
|
|
| 5655 |
|
|
static rtx
|
| 5656 |
|
|
find_ltrel_base (rtx x)
|
| 5657 |
|
|
{
|
| 5658 |
|
|
int i, j;
|
| 5659 |
|
|
const char *fmt;
|
| 5660 |
|
|
|
| 5661 |
|
|
if (GET_CODE (x) == UNSPEC
|
| 5662 |
|
|
&& XINT (x, 1) == UNSPEC_LTREL_BASE)
|
| 5663 |
|
|
return XVECEXP (x, 0, 0);
|
| 5664 |
|
|
|
| 5665 |
|
|
fmt = GET_RTX_FORMAT (GET_CODE (x));
|
| 5666 |
|
|
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
|
| 5667 |
|
|
{
|
| 5668 |
|
|
if (fmt[i] == 'e')
|
| 5669 |
|
|
{
|
| 5670 |
|
|
rtx fnd = find_ltrel_base (XEXP (x, i));
|
| 5671 |
|
|
if (fnd)
|
| 5672 |
|
|
return fnd;
|
| 5673 |
|
|
}
|
| 5674 |
|
|
else if (fmt[i] == 'E')
|
| 5675 |
|
|
{
|
| 5676 |
|
|
for (j = 0; j < XVECLEN (x, i); j++)
|
| 5677 |
|
|
{
|
| 5678 |
|
|
rtx fnd = find_ltrel_base (XVECEXP (x, i, j));
|
| 5679 |
|
|
if (fnd)
|
| 5680 |
|
|
return fnd;
|
| 5681 |
|
|
}
|
| 5682 |
|
|
}
|
| 5683 |
|
|
}
|
| 5684 |
|
|
|
| 5685 |
|
|
return NULL_RTX;
|
| 5686 |
|
|
}
|
| 5687 |
|
|
|
| 5688 |
|
|
/* Replace any occurrence of UNSPEC_LTREL_BASE in X with its base. */
|
| 5689 |
|
|
|
| 5690 |
|
|
static void
|
| 5691 |
|
|
replace_ltrel_base (rtx *x)
|
| 5692 |
|
|
{
|
| 5693 |
|
|
int i, j;
|
| 5694 |
|
|
const char *fmt;
|
| 5695 |
|
|
|
| 5696 |
|
|
if (GET_CODE (*x) == UNSPEC
|
| 5697 |
|
|
&& XINT (*x, 1) == UNSPEC_LTREL_BASE)
|
| 5698 |
|
|
{
|
| 5699 |
|
|
*x = XVECEXP (*x, 0, 1);
|
| 5700 |
|
|
return;
|
| 5701 |
|
|
}
|
| 5702 |
|
|
|
| 5703 |
|
|
fmt = GET_RTX_FORMAT (GET_CODE (*x));
|
| 5704 |
|
|
for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
|
| 5705 |
|
|
{
|
| 5706 |
|
|
if (fmt[i] == 'e')
|
| 5707 |
|
|
{
|
| 5708 |
|
|
replace_ltrel_base (&XEXP (*x, i));
|
| 5709 |
|
|
}
|
| 5710 |
|
|
else if (fmt[i] == 'E')
|
| 5711 |
|
|
{
|
| 5712 |
|
|
for (j = 0; j < XVECLEN (*x, i); j++)
|
| 5713 |
|
|
replace_ltrel_base (&XVECEXP (*x, i, j));
|
| 5714 |
|
|
}
|
| 5715 |
|
|
}
|
| 5716 |
|
|
}
|
| 5717 |
|
|
|
| 5718 |
|
|
|
| 5719 |
|
|
/* We keep a list of constants which we have to add to internal
|
| 5720 |
|
|
constant tables in the middle of large functions. */
|
| 5721 |
|
|
|
| 5722 |
|
|
#define NR_C_MODES 11
|
| 5723 |
|
|
enum machine_mode constant_modes[NR_C_MODES] =
|
| 5724 |
|
|
{
|
| 5725 |
|
|
TFmode, TImode, TDmode,
|
| 5726 |
|
|
DFmode, DImode, DDmode,
|
| 5727 |
|
|
SFmode, SImode, SDmode,
|
| 5728 |
|
|
HImode,
|
| 5729 |
|
|
QImode
|
| 5730 |
|
|
};
|
| 5731 |
|
|
|
| 5732 |
|
|
struct constant
|
| 5733 |
|
|
{
|
| 5734 |
|
|
struct constant *next;
|
| 5735 |
|
|
rtx value;
|
| 5736 |
|
|
rtx label;
|
| 5737 |
|
|
};
|
| 5738 |
|
|
|
| 5739 |
|
|
struct constant_pool
|
| 5740 |
|
|
{
|
| 5741 |
|
|
struct constant_pool *next;
|
| 5742 |
|
|
rtx first_insn;
|
| 5743 |
|
|
rtx pool_insn;
|
| 5744 |
|
|
bitmap insns;
|
| 5745 |
|
|
rtx emit_pool_after;
|
| 5746 |
|
|
|
| 5747 |
|
|
struct constant *constants[NR_C_MODES];
|
| 5748 |
|
|
struct constant *execute;
|
| 5749 |
|
|
rtx label;
|
| 5750 |
|
|
int size;
|
| 5751 |
|
|
};
|
| 5752 |
|
|
|
| 5753 |
|
|
/* Allocate new constant_pool structure. */
|
| 5754 |
|
|
|
| 5755 |
|
|
static struct constant_pool *
|
| 5756 |
|
|
s390_alloc_pool (void)
|
| 5757 |
|
|
{
|
| 5758 |
|
|
struct constant_pool *pool;
|
| 5759 |
|
|
int i;
|
| 5760 |
|
|
|
| 5761 |
|
|
pool = (struct constant_pool *) xmalloc (sizeof *pool);
|
| 5762 |
|
|
pool->next = NULL;
|
| 5763 |
|
|
for (i = 0; i < NR_C_MODES; i++)
|
| 5764 |
|
|
pool->constants[i] = NULL;
|
| 5765 |
|
|
|
| 5766 |
|
|
pool->execute = NULL;
|
| 5767 |
|
|
pool->label = gen_label_rtx ();
|
| 5768 |
|
|
pool->first_insn = NULL_RTX;
|
| 5769 |
|
|
pool->pool_insn = NULL_RTX;
|
| 5770 |
|
|
pool->insns = BITMAP_ALLOC (NULL);
|
| 5771 |
|
|
pool->size = 0;
|
| 5772 |
|
|
pool->emit_pool_after = NULL_RTX;
|
| 5773 |
|
|
|
| 5774 |
|
|
return pool;
|
| 5775 |
|
|
}
|
| 5776 |
|
|
|
| 5777 |
|
|
/* Create new constant pool covering instructions starting at INSN
|
| 5778 |
|
|
and chain it to the end of POOL_LIST. */
|
| 5779 |
|
|
|
| 5780 |
|
|
static struct constant_pool *
|
| 5781 |
|
|
s390_start_pool (struct constant_pool **pool_list, rtx insn)
|
| 5782 |
|
|
{
|
| 5783 |
|
|
struct constant_pool *pool, **prev;
|
| 5784 |
|
|
|
| 5785 |
|
|
pool = s390_alloc_pool ();
|
| 5786 |
|
|
pool->first_insn = insn;
|
| 5787 |
|
|
|
| 5788 |
|
|
for (prev = pool_list; *prev; prev = &(*prev)->next)
|
| 5789 |
|
|
;
|
| 5790 |
|
|
*prev = pool;
|
| 5791 |
|
|
|
| 5792 |
|
|
return pool;
|
| 5793 |
|
|
}
|
| 5794 |
|
|
|
| 5795 |
|
|
/* End range of instructions covered by POOL at INSN and emit
|
| 5796 |
|
|
placeholder insn representing the pool. */
|
| 5797 |
|
|
|
| 5798 |
|
|
static void
|
| 5799 |
|
|
s390_end_pool (struct constant_pool *pool, rtx insn)
|
| 5800 |
|
|
{
|
| 5801 |
|
|
rtx pool_size = GEN_INT (pool->size + 8 /* alignment slop */);
|
| 5802 |
|
|
|
| 5803 |
|
|
if (!insn)
|
| 5804 |
|
|
insn = get_last_insn ();
|
| 5805 |
|
|
|
| 5806 |
|
|
pool->pool_insn = emit_insn_after (gen_pool (pool_size), insn);
|
| 5807 |
|
|
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
|
| 5808 |
|
|
}
|
| 5809 |
|
|
|
| 5810 |
|
|
/* Add INSN to the list of insns covered by POOL. */
|
| 5811 |
|
|
|
| 5812 |
|
|
static void
|
| 5813 |
|
|
s390_add_pool_insn (struct constant_pool *pool, rtx insn)
|
| 5814 |
|
|
{
|
| 5815 |
|
|
bitmap_set_bit (pool->insns, INSN_UID (insn));
|
| 5816 |
|
|
}
|
| 5817 |
|
|
|
| 5818 |
|
|
/* Return pool out of POOL_LIST that covers INSN. */
|
| 5819 |
|
|
|
| 5820 |
|
|
static struct constant_pool *
|
| 5821 |
|
|
s390_find_pool (struct constant_pool *pool_list, rtx insn)
|
| 5822 |
|
|
{
|
| 5823 |
|
|
struct constant_pool *pool;
|
| 5824 |
|
|
|
| 5825 |
|
|
for (pool = pool_list; pool; pool = pool->next)
|
| 5826 |
|
|
if (bitmap_bit_p (pool->insns, INSN_UID (insn)))
|
| 5827 |
|
|
break;
|
| 5828 |
|
|
|
| 5829 |
|
|
return pool;
|
| 5830 |
|
|
}
|
| 5831 |
|
|
|
| 5832 |
|
|
/* Add constant VAL of mode MODE to the constant pool POOL. */
|
| 5833 |
|
|
|
| 5834 |
|
|
static void
|
| 5835 |
|
|
s390_add_constant (struct constant_pool *pool, rtx val, enum machine_mode mode)
|
| 5836 |
|
|
{
|
| 5837 |
|
|
struct constant *c;
|
| 5838 |
|
|
int i;
|
| 5839 |
|
|
|
| 5840 |
|
|
for (i = 0; i < NR_C_MODES; i++)
|
| 5841 |
|
|
if (constant_modes[i] == mode)
|
| 5842 |
|
|
break;
|
| 5843 |
|
|
gcc_assert (i != NR_C_MODES);
|
| 5844 |
|
|
|
| 5845 |
|
|
for (c = pool->constants[i]; c != NULL; c = c->next)
|
| 5846 |
|
|
if (rtx_equal_p (val, c->value))
|
| 5847 |
|
|
break;
|
| 5848 |
|
|
|
| 5849 |
|
|
if (c == NULL)
|
| 5850 |
|
|
{
|
| 5851 |
|
|
c = (struct constant *) xmalloc (sizeof *c);
|
| 5852 |
|
|
c->value = val;
|
| 5853 |
|
|
c->label = gen_label_rtx ();
|
| 5854 |
|
|
c->next = pool->constants[i];
|
| 5855 |
|
|
pool->constants[i] = c;
|
| 5856 |
|
|
pool->size += GET_MODE_SIZE (mode);
|
| 5857 |
|
|
}
|
| 5858 |
|
|
}
|
| 5859 |
|
|
|
| 5860 |
|
|
/* Return an rtx that represents the offset of X from the start of
|
| 5861 |
|
|
pool POOL. */
|
| 5862 |
|
|
|
| 5863 |
|
|
static rtx
|
| 5864 |
|
|
s390_pool_offset (struct constant_pool *pool, rtx x)
|
| 5865 |
|
|
{
|
| 5866 |
|
|
rtx label;
|
| 5867 |
|
|
|
| 5868 |
|
|
label = gen_rtx_LABEL_REF (GET_MODE (x), pool->label);
|
| 5869 |
|
|
x = gen_rtx_UNSPEC (GET_MODE (x), gen_rtvec (2, x, label),
|
| 5870 |
|
|
UNSPEC_POOL_OFFSET);
|
| 5871 |
|
|
return gen_rtx_CONST (GET_MODE (x), x);
|
| 5872 |
|
|
}
|
| 5873 |
|
|
|
| 5874 |
|
|
/* Find constant VAL of mode MODE in the constant pool POOL.
|
| 5875 |
|
|
Return an RTX describing the distance from the start of
|
| 5876 |
|
|
the pool to the location of the new constant. */
|
| 5877 |
|
|
|
| 5878 |
|
|
static rtx
|
| 5879 |
|
|
s390_find_constant (struct constant_pool *pool, rtx val,
|
| 5880 |
|
|
enum machine_mode mode)
|
| 5881 |
|
|
{
|
| 5882 |
|
|
struct constant *c;
|
| 5883 |
|
|
int i;
|
| 5884 |
|
|
|
| 5885 |
|
|
for (i = 0; i < NR_C_MODES; i++)
|
| 5886 |
|
|
if (constant_modes[i] == mode)
|
| 5887 |
|
|
break;
|
| 5888 |
|
|
gcc_assert (i != NR_C_MODES);
|
| 5889 |
|
|
|
| 5890 |
|
|
for (c = pool->constants[i]; c != NULL; c = c->next)
|
| 5891 |
|
|
if (rtx_equal_p (val, c->value))
|
| 5892 |
|
|
break;
|
| 5893 |
|
|
|
| 5894 |
|
|
gcc_assert (c);
|
| 5895 |
|
|
|
| 5896 |
|
|
return s390_pool_offset (pool, gen_rtx_LABEL_REF (Pmode, c->label));
|
| 5897 |
|
|
}
|
| 5898 |
|
|
|
| 5899 |
|
|
/* Check whether INSN is an execute. Return the label_ref to its
|
| 5900 |
|
|
execute target template if so, NULL_RTX otherwise. */
|
| 5901 |
|
|
|
| 5902 |
|
|
static rtx
|
| 5903 |
|
|
s390_execute_label (rtx insn)
|
| 5904 |
|
|
{
|
| 5905 |
|
|
if (GET_CODE (insn) == INSN
|
| 5906 |
|
|
&& GET_CODE (PATTERN (insn)) == PARALLEL
|
| 5907 |
|
|
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == UNSPEC
|
| 5908 |
|
|
&& XINT (XVECEXP (PATTERN (insn), 0, 0), 1) == UNSPEC_EXECUTE)
|
| 5909 |
|
|
return XVECEXP (XVECEXP (PATTERN (insn), 0, 0), 0, 2);
|
| 5910 |
|
|
|
| 5911 |
|
|
return NULL_RTX;
|
| 5912 |
|
|
}
|
| 5913 |
|
|
|
| 5914 |
|
|
/* Add execute target for INSN to the constant pool POOL. */
|
| 5915 |
|
|
|
| 5916 |
|
|
static void
|
| 5917 |
|
|
s390_add_execute (struct constant_pool *pool, rtx insn)
|
| 5918 |
|
|
{
|
| 5919 |
|
|
struct constant *c;
|
| 5920 |
|
|
|
| 5921 |
|
|
for (c = pool->execute; c != NULL; c = c->next)
|
| 5922 |
|
|
if (INSN_UID (insn) == INSN_UID (c->value))
|
| 5923 |
|
|
break;
|
| 5924 |
|
|
|
| 5925 |
|
|
if (c == NULL)
|
| 5926 |
|
|
{
|
| 5927 |
|
|
c = (struct constant *) xmalloc (sizeof *c);
|
| 5928 |
|
|
c->value = insn;
|
| 5929 |
|
|
c->label = gen_label_rtx ();
|
| 5930 |
|
|
c->next = pool->execute;
|
| 5931 |
|
|
pool->execute = c;
|
| 5932 |
|
|
pool->size += 6;
|
| 5933 |
|
|
}
|
| 5934 |
|
|
}
|
| 5935 |
|
|
|
| 5936 |
|
|
/* Find execute target for INSN in the constant pool POOL.
|
| 5937 |
|
|
Return an RTX describing the distance from the start of
|
| 5938 |
|
|
the pool to the location of the execute target. */
|
| 5939 |
|
|
|
| 5940 |
|
|
static rtx
|
| 5941 |
|
|
s390_find_execute (struct constant_pool *pool, rtx insn)
|
| 5942 |
|
|
{
|
| 5943 |
|
|
struct constant *c;
|
| 5944 |
|
|
|
| 5945 |
|
|
for (c = pool->execute; c != NULL; c = c->next)
|
| 5946 |
|
|
if (INSN_UID (insn) == INSN_UID (c->value))
|
| 5947 |
|
|
break;
|
| 5948 |
|
|
|
| 5949 |
|
|
gcc_assert (c);
|
| 5950 |
|
|
|
| 5951 |
|
|
return s390_pool_offset (pool, gen_rtx_LABEL_REF (Pmode, c->label));
|
| 5952 |
|
|
}
|
| 5953 |
|
|
|
| 5954 |
|
|
/* For an execute INSN, extract the execute target template. */
|
| 5955 |
|
|
|
| 5956 |
|
|
static rtx
|
| 5957 |
|
|
s390_execute_target (rtx insn)
|
| 5958 |
|
|
{
|
| 5959 |
|
|
rtx pattern = PATTERN (insn);
|
| 5960 |
|
|
gcc_assert (s390_execute_label (insn));
|
| 5961 |
|
|
|
| 5962 |
|
|
if (XVECLEN (pattern, 0) == 2)
|
| 5963 |
|
|
{
|
| 5964 |
|
|
pattern = copy_rtx (XVECEXP (pattern, 0, 1));
|
| 5965 |
|
|
}
|
| 5966 |
|
|
else
|
| 5967 |
|
|
{
|
| 5968 |
|
|
rtvec vec = rtvec_alloc (XVECLEN (pattern, 0) - 1);
|
| 5969 |
|
|
int i;
|
| 5970 |
|
|
|
| 5971 |
|
|
for (i = 0; i < XVECLEN (pattern, 0) - 1; i++)
|
| 5972 |
|
|
RTVEC_ELT (vec, i) = copy_rtx (XVECEXP (pattern, 0, i + 1));
|
| 5973 |
|
|
|
| 5974 |
|
|
pattern = gen_rtx_PARALLEL (VOIDmode, vec);
|
| 5975 |
|
|
}
|
| 5976 |
|
|
|
| 5977 |
|
|
return pattern;
|
| 5978 |
|
|
}
|
| 5979 |
|
|
|
| 5980 |
|
|
/* Indicate that INSN cannot be duplicated. This is the case for
|
| 5981 |
|
|
execute insns that carry a unique label. */
|
| 5982 |
|
|
|
| 5983 |
|
|
static bool
|
| 5984 |
|
|
s390_cannot_copy_insn_p (rtx insn)
|
| 5985 |
|
|
{
|
| 5986 |
|
|
rtx label = s390_execute_label (insn);
|
| 5987 |
|
|
return label && label != const0_rtx;
|
| 5988 |
|
|
}
|
| 5989 |
|
|
|
| 5990 |
|
|
/* Dump out the constants in POOL. If REMOTE_LABEL is true,
|
| 5991 |
|
|
do not emit the pool base label. */
|
| 5992 |
|
|
|
| 5993 |
|
|
static void
|
| 5994 |
|
|
s390_dump_pool (struct constant_pool *pool, bool remote_label)
|
| 5995 |
|
|
{
|
| 5996 |
|
|
struct constant *c;
|
| 5997 |
|
|
rtx insn = pool->pool_insn;
|
| 5998 |
|
|
int i;
|
| 5999 |
|
|
|
| 6000 |
|
|
/* Switch to rodata section. */
|
| 6001 |
|
|
if (TARGET_CPU_ZARCH)
|
| 6002 |
|
|
{
|
| 6003 |
|
|
insn = emit_insn_after (gen_pool_section_start (), insn);
|
| 6004 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6005 |
|
|
}
|
| 6006 |
|
|
|
| 6007 |
|
|
/* Ensure minimum pool alignment. */
|
| 6008 |
|
|
if (TARGET_CPU_ZARCH)
|
| 6009 |
|
|
insn = emit_insn_after (gen_pool_align (GEN_INT (8)), insn);
|
| 6010 |
|
|
else
|
| 6011 |
|
|
insn = emit_insn_after (gen_pool_align (GEN_INT (4)), insn);
|
| 6012 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6013 |
|
|
|
| 6014 |
|
|
/* Emit pool base label. */
|
| 6015 |
|
|
if (!remote_label)
|
| 6016 |
|
|
{
|
| 6017 |
|
|
insn = emit_label_after (pool->label, insn);
|
| 6018 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6019 |
|
|
}
|
| 6020 |
|
|
|
| 6021 |
|
|
/* Dump constants in descending alignment requirement order,
|
| 6022 |
|
|
ensuring proper alignment for every constant. */
|
| 6023 |
|
|
for (i = 0; i < NR_C_MODES; i++)
|
| 6024 |
|
|
for (c = pool->constants[i]; c; c = c->next)
|
| 6025 |
|
|
{
|
| 6026 |
|
|
/* Convert UNSPEC_LTREL_OFFSET unspecs to pool-relative references. */
|
| 6027 |
|
|
rtx value = copy_rtx (c->value);
|
| 6028 |
|
|
if (GET_CODE (value) == CONST
|
| 6029 |
|
|
&& GET_CODE (XEXP (value, 0)) == UNSPEC
|
| 6030 |
|
|
&& XINT (XEXP (value, 0), 1) == UNSPEC_LTREL_OFFSET
|
| 6031 |
|
|
&& XVECLEN (XEXP (value, 0), 0) == 1)
|
| 6032 |
|
|
value = s390_pool_offset (pool, XVECEXP (XEXP (value, 0), 0, 0));
|
| 6033 |
|
|
|
| 6034 |
|
|
insn = emit_label_after (c->label, insn);
|
| 6035 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6036 |
|
|
|
| 6037 |
|
|
value = gen_rtx_UNSPEC_VOLATILE (constant_modes[i],
|
| 6038 |
|
|
gen_rtvec (1, value),
|
| 6039 |
|
|
UNSPECV_POOL_ENTRY);
|
| 6040 |
|
|
insn = emit_insn_after (value, insn);
|
| 6041 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6042 |
|
|
}
|
| 6043 |
|
|
|
| 6044 |
|
|
/* Ensure minimum alignment for instructions. */
|
| 6045 |
|
|
insn = emit_insn_after (gen_pool_align (GEN_INT (2)), insn);
|
| 6046 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6047 |
|
|
|
| 6048 |
|
|
/* Output in-pool execute template insns. */
|
| 6049 |
|
|
for (c = pool->execute; c; c = c->next)
|
| 6050 |
|
|
{
|
| 6051 |
|
|
insn = emit_label_after (c->label, insn);
|
| 6052 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6053 |
|
|
|
| 6054 |
|
|
insn = emit_insn_after (s390_execute_target (c->value), insn);
|
| 6055 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6056 |
|
|
}
|
| 6057 |
|
|
|
| 6058 |
|
|
/* Switch back to previous section. */
|
| 6059 |
|
|
if (TARGET_CPU_ZARCH)
|
| 6060 |
|
|
{
|
| 6061 |
|
|
insn = emit_insn_after (gen_pool_section_end (), insn);
|
| 6062 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6063 |
|
|
}
|
| 6064 |
|
|
|
| 6065 |
|
|
insn = emit_barrier_after (insn);
|
| 6066 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6067 |
|
|
|
| 6068 |
|
|
/* Remove placeholder insn. */
|
| 6069 |
|
|
remove_insn (pool->pool_insn);
|
| 6070 |
|
|
}
|
| 6071 |
|
|
|
| 6072 |
|
|
/* Free all memory used by POOL. */
|
| 6073 |
|
|
|
| 6074 |
|
|
static void
|
| 6075 |
|
|
s390_free_pool (struct constant_pool *pool)
|
| 6076 |
|
|
{
|
| 6077 |
|
|
struct constant *c, *next;
|
| 6078 |
|
|
int i;
|
| 6079 |
|
|
|
| 6080 |
|
|
for (i = 0; i < NR_C_MODES; i++)
|
| 6081 |
|
|
for (c = pool->constants[i]; c; c = next)
|
| 6082 |
|
|
{
|
| 6083 |
|
|
next = c->next;
|
| 6084 |
|
|
free (c);
|
| 6085 |
|
|
}
|
| 6086 |
|
|
|
| 6087 |
|
|
for (c = pool->execute; c; c = next)
|
| 6088 |
|
|
{
|
| 6089 |
|
|
next = c->next;
|
| 6090 |
|
|
free (c);
|
| 6091 |
|
|
}
|
| 6092 |
|
|
|
| 6093 |
|
|
BITMAP_FREE (pool->insns);
|
| 6094 |
|
|
free (pool);
|
| 6095 |
|
|
}
|
| 6096 |
|
|
|
| 6097 |
|
|
|
| 6098 |
|
|
/* Collect main literal pool. Return NULL on overflow. */
|
| 6099 |
|
|
|
| 6100 |
|
|
static struct constant_pool *
|
| 6101 |
|
|
s390_mainpool_start (void)
|
| 6102 |
|
|
{
|
| 6103 |
|
|
struct constant_pool *pool;
|
| 6104 |
|
|
rtx insn;
|
| 6105 |
|
|
|
| 6106 |
|
|
pool = s390_alloc_pool ();
|
| 6107 |
|
|
|
| 6108 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 6109 |
|
|
{
|
| 6110 |
|
|
if (GET_CODE (insn) == INSN
|
| 6111 |
|
|
&& GET_CODE (PATTERN (insn)) == SET
|
| 6112 |
|
|
&& GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE
|
| 6113 |
|
|
&& XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL)
|
| 6114 |
|
|
{
|
| 6115 |
|
|
gcc_assert (!pool->pool_insn);
|
| 6116 |
|
|
pool->pool_insn = insn;
|
| 6117 |
|
|
}
|
| 6118 |
|
|
|
| 6119 |
|
|
if (!TARGET_CPU_ZARCH && s390_execute_label (insn))
|
| 6120 |
|
|
{
|
| 6121 |
|
|
s390_add_execute (pool, insn);
|
| 6122 |
|
|
}
|
| 6123 |
|
|
else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
|
| 6124 |
|
|
{
|
| 6125 |
|
|
rtx pool_ref = NULL_RTX;
|
| 6126 |
|
|
find_constant_pool_ref (PATTERN (insn), &pool_ref);
|
| 6127 |
|
|
if (pool_ref)
|
| 6128 |
|
|
{
|
| 6129 |
|
|
rtx constant = get_pool_constant (pool_ref);
|
| 6130 |
|
|
enum machine_mode mode = get_pool_mode (pool_ref);
|
| 6131 |
|
|
s390_add_constant (pool, constant, mode);
|
| 6132 |
|
|
}
|
| 6133 |
|
|
}
|
| 6134 |
|
|
|
| 6135 |
|
|
/* If hot/cold partitioning is enabled we have to make sure that
|
| 6136 |
|
|
the literal pool is emitted in the same section where the
|
| 6137 |
|
|
initialization of the literal pool base pointer takes place.
|
| 6138 |
|
|
emit_pool_after is only used in the non-overflow case on non
|
| 6139 |
|
|
Z cpus where we can emit the literal pool at the end of the
|
| 6140 |
|
|
function body within the text section. */
|
| 6141 |
|
|
if (NOTE_P (insn)
|
| 6142 |
|
|
&& NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS
|
| 6143 |
|
|
&& !pool->emit_pool_after)
|
| 6144 |
|
|
pool->emit_pool_after = PREV_INSN (insn);
|
| 6145 |
|
|
}
|
| 6146 |
|
|
|
| 6147 |
|
|
gcc_assert (pool->pool_insn || pool->size == 0);
|
| 6148 |
|
|
|
| 6149 |
|
|
if (pool->size >= 4096)
|
| 6150 |
|
|
{
|
| 6151 |
|
|
/* We're going to chunkify the pool, so remove the main
|
| 6152 |
|
|
pool placeholder insn. */
|
| 6153 |
|
|
remove_insn (pool->pool_insn);
|
| 6154 |
|
|
|
| 6155 |
|
|
s390_free_pool (pool);
|
| 6156 |
|
|
pool = NULL;
|
| 6157 |
|
|
}
|
| 6158 |
|
|
|
| 6159 |
|
|
/* If the functions ends with the section where the literal pool
|
| 6160 |
|
|
should be emitted set the marker to its end. */
|
| 6161 |
|
|
if (pool && !pool->emit_pool_after)
|
| 6162 |
|
|
pool->emit_pool_after = get_last_insn ();
|
| 6163 |
|
|
|
| 6164 |
|
|
return pool;
|
| 6165 |
|
|
}
|
| 6166 |
|
|
|
| 6167 |
|
|
/* POOL holds the main literal pool as collected by s390_mainpool_start.
|
| 6168 |
|
|
Modify the current function to output the pool constants as well as
|
| 6169 |
|
|
the pool register setup instruction. */
|
| 6170 |
|
|
|
| 6171 |
|
|
static void
|
| 6172 |
|
|
s390_mainpool_finish (struct constant_pool *pool)
|
| 6173 |
|
|
{
|
| 6174 |
|
|
rtx base_reg = cfun->machine->base_reg;
|
| 6175 |
|
|
rtx insn;
|
| 6176 |
|
|
|
| 6177 |
|
|
/* If the pool is empty, we're done. */
|
| 6178 |
|
|
if (pool->size == 0)
|
| 6179 |
|
|
{
|
| 6180 |
|
|
/* We don't actually need a base register after all. */
|
| 6181 |
|
|
cfun->machine->base_reg = NULL_RTX;
|
| 6182 |
|
|
|
| 6183 |
|
|
if (pool->pool_insn)
|
| 6184 |
|
|
remove_insn (pool->pool_insn);
|
| 6185 |
|
|
s390_free_pool (pool);
|
| 6186 |
|
|
return;
|
| 6187 |
|
|
}
|
| 6188 |
|
|
|
| 6189 |
|
|
/* We need correct insn addresses. */
|
| 6190 |
|
|
shorten_branches (get_insns ());
|
| 6191 |
|
|
|
| 6192 |
|
|
/* On zSeries, we use a LARL to load the pool register. The pool is
|
| 6193 |
|
|
located in the .rodata section, so we emit it after the function. */
|
| 6194 |
|
|
if (TARGET_CPU_ZARCH)
|
| 6195 |
|
|
{
|
| 6196 |
|
|
insn = gen_main_base_64 (base_reg, pool->label);
|
| 6197 |
|
|
insn = emit_insn_after (insn, pool->pool_insn);
|
| 6198 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6199 |
|
|
remove_insn (pool->pool_insn);
|
| 6200 |
|
|
|
| 6201 |
|
|
insn = get_last_insn ();
|
| 6202 |
|
|
pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
|
| 6203 |
|
|
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
|
| 6204 |
|
|
|
| 6205 |
|
|
s390_dump_pool (pool, 0);
|
| 6206 |
|
|
}
|
| 6207 |
|
|
|
| 6208 |
|
|
/* On S/390, if the total size of the function's code plus literal pool
|
| 6209 |
|
|
does not exceed 4096 bytes, we use BASR to set up a function base
|
| 6210 |
|
|
pointer, and emit the literal pool at the end of the function. */
|
| 6211 |
|
|
else if (INSN_ADDRESSES (INSN_UID (pool->emit_pool_after))
|
| 6212 |
|
|
+ pool->size + 8 /* alignment slop */ < 4096)
|
| 6213 |
|
|
{
|
| 6214 |
|
|
insn = gen_main_base_31_small (base_reg, pool->label);
|
| 6215 |
|
|
insn = emit_insn_after (insn, pool->pool_insn);
|
| 6216 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6217 |
|
|
remove_insn (pool->pool_insn);
|
| 6218 |
|
|
|
| 6219 |
|
|
insn = emit_label_after (pool->label, insn);
|
| 6220 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6221 |
|
|
|
| 6222 |
|
|
/* emit_pool_after will be set by s390_mainpool_start to the
|
| 6223 |
|
|
last insn of the section where the literal pool should be
|
| 6224 |
|
|
emitted. */
|
| 6225 |
|
|
insn = pool->emit_pool_after;
|
| 6226 |
|
|
|
| 6227 |
|
|
pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
|
| 6228 |
|
|
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
|
| 6229 |
|
|
|
| 6230 |
|
|
s390_dump_pool (pool, 1);
|
| 6231 |
|
|
}
|
| 6232 |
|
|
|
| 6233 |
|
|
/* Otherwise, we emit an inline literal pool and use BASR to branch
|
| 6234 |
|
|
over it, setting up the pool register at the same time. */
|
| 6235 |
|
|
else
|
| 6236 |
|
|
{
|
| 6237 |
|
|
rtx pool_end = gen_label_rtx ();
|
| 6238 |
|
|
|
| 6239 |
|
|
insn = gen_main_base_31_large (base_reg, pool->label, pool_end);
|
| 6240 |
|
|
insn = emit_insn_after (insn, pool->pool_insn);
|
| 6241 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6242 |
|
|
remove_insn (pool->pool_insn);
|
| 6243 |
|
|
|
| 6244 |
|
|
insn = emit_label_after (pool->label, insn);
|
| 6245 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6246 |
|
|
|
| 6247 |
|
|
pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
|
| 6248 |
|
|
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
|
| 6249 |
|
|
|
| 6250 |
|
|
insn = emit_label_after (pool_end, pool->pool_insn);
|
| 6251 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6252 |
|
|
|
| 6253 |
|
|
s390_dump_pool (pool, 1);
|
| 6254 |
|
|
}
|
| 6255 |
|
|
|
| 6256 |
|
|
|
| 6257 |
|
|
/* Replace all literal pool references. */
|
| 6258 |
|
|
|
| 6259 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 6260 |
|
|
{
|
| 6261 |
|
|
if (INSN_P (insn))
|
| 6262 |
|
|
replace_ltrel_base (&PATTERN (insn));
|
| 6263 |
|
|
|
| 6264 |
|
|
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
|
| 6265 |
|
|
{
|
| 6266 |
|
|
rtx addr, pool_ref = NULL_RTX;
|
| 6267 |
|
|
find_constant_pool_ref (PATTERN (insn), &pool_ref);
|
| 6268 |
|
|
if (pool_ref)
|
| 6269 |
|
|
{
|
| 6270 |
|
|
if (s390_execute_label (insn))
|
| 6271 |
|
|
addr = s390_find_execute (pool, insn);
|
| 6272 |
|
|
else
|
| 6273 |
|
|
addr = s390_find_constant (pool, get_pool_constant (pool_ref),
|
| 6274 |
|
|
get_pool_mode (pool_ref));
|
| 6275 |
|
|
|
| 6276 |
|
|
replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
|
| 6277 |
|
|
INSN_CODE (insn) = -1;
|
| 6278 |
|
|
}
|
| 6279 |
|
|
}
|
| 6280 |
|
|
}
|
| 6281 |
|
|
|
| 6282 |
|
|
|
| 6283 |
|
|
/* Free the pool. */
|
| 6284 |
|
|
s390_free_pool (pool);
|
| 6285 |
|
|
}
|
| 6286 |
|
|
|
| 6287 |
|
|
/* POOL holds the main literal pool as collected by s390_mainpool_start.
|
| 6288 |
|
|
We have decided we cannot use this pool, so revert all changes
|
| 6289 |
|
|
to the current function that were done by s390_mainpool_start. */
|
| 6290 |
|
|
static void
|
| 6291 |
|
|
s390_mainpool_cancel (struct constant_pool *pool)
|
| 6292 |
|
|
{
|
| 6293 |
|
|
/* We didn't actually change the instruction stream, so simply
|
| 6294 |
|
|
free the pool memory. */
|
| 6295 |
|
|
s390_free_pool (pool);
|
| 6296 |
|
|
}
|
| 6297 |
|
|
|
| 6298 |
|
|
|
| 6299 |
|
|
/* Chunkify the literal pool. */
|
| 6300 |
|
|
|
| 6301 |
|
|
#define S390_POOL_CHUNK_MIN 0xc00
|
| 6302 |
|
|
#define S390_POOL_CHUNK_MAX 0xe00
|
| 6303 |
|
|
|
| 6304 |
|
|
static struct constant_pool *
|
| 6305 |
|
|
s390_chunkify_start (void)
|
| 6306 |
|
|
{
|
| 6307 |
|
|
struct constant_pool *curr_pool = NULL, *pool_list = NULL;
|
| 6308 |
|
|
int extra_size = 0;
|
| 6309 |
|
|
bitmap far_labels;
|
| 6310 |
|
|
rtx pending_ltrel = NULL_RTX;
|
| 6311 |
|
|
rtx insn;
|
| 6312 |
|
|
|
| 6313 |
|
|
rtx (*gen_reload_base) (rtx, rtx) =
|
| 6314 |
|
|
TARGET_CPU_ZARCH? gen_reload_base_64 : gen_reload_base_31;
|
| 6315 |
|
|
|
| 6316 |
|
|
|
| 6317 |
|
|
/* We need correct insn addresses. */
|
| 6318 |
|
|
|
| 6319 |
|
|
shorten_branches (get_insns ());
|
| 6320 |
|
|
|
| 6321 |
|
|
/* Scan all insns and move literals to pool chunks. */
|
| 6322 |
|
|
|
| 6323 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 6324 |
|
|
{
|
| 6325 |
|
|
bool section_switch_p = false;
|
| 6326 |
|
|
|
| 6327 |
|
|
/* Check for pending LTREL_BASE. */
|
| 6328 |
|
|
if (INSN_P (insn))
|
| 6329 |
|
|
{
|
| 6330 |
|
|
rtx ltrel_base = find_ltrel_base (PATTERN (insn));
|
| 6331 |
|
|
if (ltrel_base)
|
| 6332 |
|
|
{
|
| 6333 |
|
|
gcc_assert (ltrel_base == pending_ltrel);
|
| 6334 |
|
|
pending_ltrel = NULL_RTX;
|
| 6335 |
|
|
}
|
| 6336 |
|
|
}
|
| 6337 |
|
|
|
| 6338 |
|
|
if (!TARGET_CPU_ZARCH && s390_execute_label (insn))
|
| 6339 |
|
|
{
|
| 6340 |
|
|
if (!curr_pool)
|
| 6341 |
|
|
curr_pool = s390_start_pool (&pool_list, insn);
|
| 6342 |
|
|
|
| 6343 |
|
|
s390_add_execute (curr_pool, insn);
|
| 6344 |
|
|
s390_add_pool_insn (curr_pool, insn);
|
| 6345 |
|
|
}
|
| 6346 |
|
|
else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
|
| 6347 |
|
|
{
|
| 6348 |
|
|
rtx pool_ref = NULL_RTX;
|
| 6349 |
|
|
find_constant_pool_ref (PATTERN (insn), &pool_ref);
|
| 6350 |
|
|
if (pool_ref)
|
| 6351 |
|
|
{
|
| 6352 |
|
|
rtx constant = get_pool_constant (pool_ref);
|
| 6353 |
|
|
enum machine_mode mode = get_pool_mode (pool_ref);
|
| 6354 |
|
|
|
| 6355 |
|
|
if (!curr_pool)
|
| 6356 |
|
|
curr_pool = s390_start_pool (&pool_list, insn);
|
| 6357 |
|
|
|
| 6358 |
|
|
s390_add_constant (curr_pool, constant, mode);
|
| 6359 |
|
|
s390_add_pool_insn (curr_pool, insn);
|
| 6360 |
|
|
|
| 6361 |
|
|
/* Don't split the pool chunk between a LTREL_OFFSET load
|
| 6362 |
|
|
and the corresponding LTREL_BASE. */
|
| 6363 |
|
|
if (GET_CODE (constant) == CONST
|
| 6364 |
|
|
&& GET_CODE (XEXP (constant, 0)) == UNSPEC
|
| 6365 |
|
|
&& XINT (XEXP (constant, 0), 1) == UNSPEC_LTREL_OFFSET)
|
| 6366 |
|
|
{
|
| 6367 |
|
|
gcc_assert (!pending_ltrel);
|
| 6368 |
|
|
pending_ltrel = pool_ref;
|
| 6369 |
|
|
}
|
| 6370 |
|
|
}
|
| 6371 |
|
|
}
|
| 6372 |
|
|
|
| 6373 |
|
|
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL)
|
| 6374 |
|
|
{
|
| 6375 |
|
|
if (curr_pool)
|
| 6376 |
|
|
s390_add_pool_insn (curr_pool, insn);
|
| 6377 |
|
|
/* An LTREL_BASE must follow within the same basic block. */
|
| 6378 |
|
|
gcc_assert (!pending_ltrel);
|
| 6379 |
|
|
}
|
| 6380 |
|
|
|
| 6381 |
|
|
if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
|
| 6382 |
|
|
section_switch_p = true;
|
| 6383 |
|
|
|
| 6384 |
|
|
if (!curr_pool
|
| 6385 |
|
|
|| INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
|
| 6386 |
|
|
|| INSN_ADDRESSES (INSN_UID (insn)) == -1)
|
| 6387 |
|
|
continue;
|
| 6388 |
|
|
|
| 6389 |
|
|
if (TARGET_CPU_ZARCH)
|
| 6390 |
|
|
{
|
| 6391 |
|
|
if (curr_pool->size < S390_POOL_CHUNK_MAX)
|
| 6392 |
|
|
continue;
|
| 6393 |
|
|
|
| 6394 |
|
|
s390_end_pool (curr_pool, NULL_RTX);
|
| 6395 |
|
|
curr_pool = NULL;
|
| 6396 |
|
|
}
|
| 6397 |
|
|
else
|
| 6398 |
|
|
{
|
| 6399 |
|
|
int chunk_size = INSN_ADDRESSES (INSN_UID (insn))
|
| 6400 |
|
|
- INSN_ADDRESSES (INSN_UID (curr_pool->first_insn))
|
| 6401 |
|
|
+ extra_size;
|
| 6402 |
|
|
|
| 6403 |
|
|
/* We will later have to insert base register reload insns.
|
| 6404 |
|
|
Those will have an effect on code size, which we need to
|
| 6405 |
|
|
consider here. This calculation makes rather pessimistic
|
| 6406 |
|
|
worst-case assumptions. */
|
| 6407 |
|
|
if (GET_CODE (insn) == CODE_LABEL)
|
| 6408 |
|
|
extra_size += 6;
|
| 6409 |
|
|
|
| 6410 |
|
|
if (chunk_size < S390_POOL_CHUNK_MIN
|
| 6411 |
|
|
&& curr_pool->size < S390_POOL_CHUNK_MIN
|
| 6412 |
|
|
&& !section_switch_p)
|
| 6413 |
|
|
continue;
|
| 6414 |
|
|
|
| 6415 |
|
|
/* Pool chunks can only be inserted after BARRIERs ... */
|
| 6416 |
|
|
if (GET_CODE (insn) == BARRIER)
|
| 6417 |
|
|
{
|
| 6418 |
|
|
s390_end_pool (curr_pool, insn);
|
| 6419 |
|
|
curr_pool = NULL;
|
| 6420 |
|
|
extra_size = 0;
|
| 6421 |
|
|
}
|
| 6422 |
|
|
|
| 6423 |
|
|
/* ... so if we don't find one in time, create one. */
|
| 6424 |
|
|
else if (chunk_size > S390_POOL_CHUNK_MAX
|
| 6425 |
|
|
|| curr_pool->size > S390_POOL_CHUNK_MAX
|
| 6426 |
|
|
|| section_switch_p)
|
| 6427 |
|
|
{
|
| 6428 |
|
|
rtx label, jump, barrier;
|
| 6429 |
|
|
|
| 6430 |
|
|
if (!section_switch_p)
|
| 6431 |
|
|
{
|
| 6432 |
|
|
/* We can insert the barrier only after a 'real' insn. */
|
| 6433 |
|
|
if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
|
| 6434 |
|
|
continue;
|
| 6435 |
|
|
if (get_attr_length (insn) == 0)
|
| 6436 |
|
|
continue;
|
| 6437 |
|
|
/* Don't separate LTREL_BASE from the corresponding
|
| 6438 |
|
|
LTREL_OFFSET load. */
|
| 6439 |
|
|
if (pending_ltrel)
|
| 6440 |
|
|
continue;
|
| 6441 |
|
|
}
|
| 6442 |
|
|
else
|
| 6443 |
|
|
{
|
| 6444 |
|
|
gcc_assert (!pending_ltrel);
|
| 6445 |
|
|
|
| 6446 |
|
|
/* The old pool has to end before the section switch
|
| 6447 |
|
|
note in order to make it part of the current
|
| 6448 |
|
|
section. */
|
| 6449 |
|
|
insn = PREV_INSN (insn);
|
| 6450 |
|
|
}
|
| 6451 |
|
|
|
| 6452 |
|
|
label = gen_label_rtx ();
|
| 6453 |
|
|
jump = emit_jump_insn_after (gen_jump (label), insn);
|
| 6454 |
|
|
barrier = emit_barrier_after (jump);
|
| 6455 |
|
|
insn = emit_label_after (label, barrier);
|
| 6456 |
|
|
JUMP_LABEL (jump) = label;
|
| 6457 |
|
|
LABEL_NUSES (label) = 1;
|
| 6458 |
|
|
|
| 6459 |
|
|
INSN_ADDRESSES_NEW (jump, -1);
|
| 6460 |
|
|
INSN_ADDRESSES_NEW (barrier, -1);
|
| 6461 |
|
|
INSN_ADDRESSES_NEW (insn, -1);
|
| 6462 |
|
|
|
| 6463 |
|
|
s390_end_pool (curr_pool, barrier);
|
| 6464 |
|
|
curr_pool = NULL;
|
| 6465 |
|
|
extra_size = 0;
|
| 6466 |
|
|
}
|
| 6467 |
|
|
}
|
| 6468 |
|
|
}
|
| 6469 |
|
|
|
| 6470 |
|
|
if (curr_pool)
|
| 6471 |
|
|
s390_end_pool (curr_pool, NULL_RTX);
|
| 6472 |
|
|
gcc_assert (!pending_ltrel);
|
| 6473 |
|
|
|
| 6474 |
|
|
/* Find all labels that are branched into
|
| 6475 |
|
|
from an insn belonging to a different chunk. */
|
| 6476 |
|
|
|
| 6477 |
|
|
far_labels = BITMAP_ALLOC (NULL);
|
| 6478 |
|
|
|
| 6479 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 6480 |
|
|
{
|
| 6481 |
|
|
/* Labels marked with LABEL_PRESERVE_P can be target
|
| 6482 |
|
|
of non-local jumps, so we have to mark them.
|
| 6483 |
|
|
The same holds for named labels.
|
| 6484 |
|
|
|
| 6485 |
|
|
Don't do that, however, if it is the label before
|
| 6486 |
|
|
a jump table. */
|
| 6487 |
|
|
|
| 6488 |
|
|
if (GET_CODE (insn) == CODE_LABEL
|
| 6489 |
|
|
&& (LABEL_PRESERVE_P (insn) || LABEL_NAME (insn)))
|
| 6490 |
|
|
{
|
| 6491 |
|
|
rtx vec_insn = next_real_insn (insn);
|
| 6492 |
|
|
rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
|
| 6493 |
|
|
PATTERN (vec_insn) : NULL_RTX;
|
| 6494 |
|
|
if (!vec_pat
|
| 6495 |
|
|
|| !(GET_CODE (vec_pat) == ADDR_VEC
|
| 6496 |
|
|
|| GET_CODE (vec_pat) == ADDR_DIFF_VEC))
|
| 6497 |
|
|
bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (insn));
|
| 6498 |
|
|
}
|
| 6499 |
|
|
|
| 6500 |
|
|
/* If we have a direct jump (conditional or unconditional)
|
| 6501 |
|
|
or a casesi jump, check all potential targets. */
|
| 6502 |
|
|
else if (GET_CODE (insn) == JUMP_INSN)
|
| 6503 |
|
|
{
|
| 6504 |
|
|
rtx pat = PATTERN (insn);
|
| 6505 |
|
|
if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2)
|
| 6506 |
|
|
pat = XVECEXP (pat, 0, 0);
|
| 6507 |
|
|
|
| 6508 |
|
|
if (GET_CODE (pat) == SET)
|
| 6509 |
|
|
{
|
| 6510 |
|
|
rtx label = JUMP_LABEL (insn);
|
| 6511 |
|
|
if (label)
|
| 6512 |
|
|
{
|
| 6513 |
|
|
if (s390_find_pool (pool_list, label)
|
| 6514 |
|
|
!= s390_find_pool (pool_list, insn))
|
| 6515 |
|
|
bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
|
| 6516 |
|
|
}
|
| 6517 |
|
|
}
|
| 6518 |
|
|
else if (GET_CODE (pat) == PARALLEL
|
| 6519 |
|
|
&& XVECLEN (pat, 0) == 2
|
| 6520 |
|
|
&& GET_CODE (XVECEXP (pat, 0, 0)) == SET
|
| 6521 |
|
|
&& GET_CODE (XVECEXP (pat, 0, 1)) == USE
|
| 6522 |
|
|
&& GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == LABEL_REF)
|
| 6523 |
|
|
{
|
| 6524 |
|
|
/* Find the jump table used by this casesi jump. */
|
| 6525 |
|
|
rtx vec_label = XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0);
|
| 6526 |
|
|
rtx vec_insn = next_real_insn (vec_label);
|
| 6527 |
|
|
rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
|
| 6528 |
|
|
PATTERN (vec_insn) : NULL_RTX;
|
| 6529 |
|
|
if (vec_pat
|
| 6530 |
|
|
&& (GET_CODE (vec_pat) == ADDR_VEC
|
| 6531 |
|
|
|| GET_CODE (vec_pat) == ADDR_DIFF_VEC))
|
| 6532 |
|
|
{
|
| 6533 |
|
|
int i, diff_p = GET_CODE (vec_pat) == ADDR_DIFF_VEC;
|
| 6534 |
|
|
|
| 6535 |
|
|
for (i = 0; i < XVECLEN (vec_pat, diff_p); i++)
|
| 6536 |
|
|
{
|
| 6537 |
|
|
rtx label = XEXP (XVECEXP (vec_pat, diff_p, i), 0);
|
| 6538 |
|
|
|
| 6539 |
|
|
if (s390_find_pool (pool_list, label)
|
| 6540 |
|
|
!= s390_find_pool (pool_list, insn))
|
| 6541 |
|
|
bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
|
| 6542 |
|
|
}
|
| 6543 |
|
|
}
|
| 6544 |
|
|
}
|
| 6545 |
|
|
}
|
| 6546 |
|
|
}
|
| 6547 |
|
|
|
| 6548 |
|
|
/* Insert base register reload insns before every pool. */
|
| 6549 |
|
|
|
| 6550 |
|
|
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
|
| 6551 |
|
|
{
|
| 6552 |
|
|
rtx new_insn = gen_reload_base (cfun->machine->base_reg,
|
| 6553 |
|
|
curr_pool->label);
|
| 6554 |
|
|
rtx insn = curr_pool->first_insn;
|
| 6555 |
|
|
INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
|
| 6556 |
|
|
}
|
| 6557 |
|
|
|
| 6558 |
|
|
/* Insert base register reload insns at every far label. */
|
| 6559 |
|
|
|
| 6560 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 6561 |
|
|
if (GET_CODE (insn) == CODE_LABEL
|
| 6562 |
|
|
&& bitmap_bit_p (far_labels, CODE_LABEL_NUMBER (insn)))
|
| 6563 |
|
|
{
|
| 6564 |
|
|
struct constant_pool *pool = s390_find_pool (pool_list, insn);
|
| 6565 |
|
|
if (pool)
|
| 6566 |
|
|
{
|
| 6567 |
|
|
rtx new_insn = gen_reload_base (cfun->machine->base_reg,
|
| 6568 |
|
|
pool->label);
|
| 6569 |
|
|
INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
|
| 6570 |
|
|
}
|
| 6571 |
|
|
}
|
| 6572 |
|
|
|
| 6573 |
|
|
|
| 6574 |
|
|
BITMAP_FREE (far_labels);
|
| 6575 |
|
|
|
| 6576 |
|
|
|
| 6577 |
|
|
/* Recompute insn addresses. */
|
| 6578 |
|
|
|
| 6579 |
|
|
init_insn_lengths ();
|
| 6580 |
|
|
shorten_branches (get_insns ());
|
| 6581 |
|
|
|
| 6582 |
|
|
return pool_list;
|
| 6583 |
|
|
}
|
| 6584 |
|
|
|
| 6585 |
|
|
/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
|
| 6586 |
|
|
After we have decided to use this list, finish implementing
|
| 6587 |
|
|
all changes to the current function as required. */
|
| 6588 |
|
|
|
| 6589 |
|
|
static void
|
| 6590 |
|
|
s390_chunkify_finish (struct constant_pool *pool_list)
|
| 6591 |
|
|
{
|
| 6592 |
|
|
struct constant_pool *curr_pool = NULL;
|
| 6593 |
|
|
rtx insn;
|
| 6594 |
|
|
|
| 6595 |
|
|
|
| 6596 |
|
|
/* Replace all literal pool references. */
|
| 6597 |
|
|
|
| 6598 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 6599 |
|
|
{
|
| 6600 |
|
|
if (INSN_P (insn))
|
| 6601 |
|
|
replace_ltrel_base (&PATTERN (insn));
|
| 6602 |
|
|
|
| 6603 |
|
|
curr_pool = s390_find_pool (pool_list, insn);
|
| 6604 |
|
|
if (!curr_pool)
|
| 6605 |
|
|
continue;
|
| 6606 |
|
|
|
| 6607 |
|
|
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
|
| 6608 |
|
|
{
|
| 6609 |
|
|
rtx addr, pool_ref = NULL_RTX;
|
| 6610 |
|
|
find_constant_pool_ref (PATTERN (insn), &pool_ref);
|
| 6611 |
|
|
if (pool_ref)
|
| 6612 |
|
|
{
|
| 6613 |
|
|
if (s390_execute_label (insn))
|
| 6614 |
|
|
addr = s390_find_execute (curr_pool, insn);
|
| 6615 |
|
|
else
|
| 6616 |
|
|
addr = s390_find_constant (curr_pool,
|
| 6617 |
|
|
get_pool_constant (pool_ref),
|
| 6618 |
|
|
get_pool_mode (pool_ref));
|
| 6619 |
|
|
|
| 6620 |
|
|
replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
|
| 6621 |
|
|
INSN_CODE (insn) = -1;
|
| 6622 |
|
|
}
|
| 6623 |
|
|
}
|
| 6624 |
|
|
}
|
| 6625 |
|
|
|
| 6626 |
|
|
/* Dump out all literal pools. */
|
| 6627 |
|
|
|
| 6628 |
|
|
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
|
| 6629 |
|
|
s390_dump_pool (curr_pool, 0);
|
| 6630 |
|
|
|
| 6631 |
|
|
/* Free pool list. */
|
| 6632 |
|
|
|
| 6633 |
|
|
while (pool_list)
|
| 6634 |
|
|
{
|
| 6635 |
|
|
struct constant_pool *next = pool_list->next;
|
| 6636 |
|
|
s390_free_pool (pool_list);
|
| 6637 |
|
|
pool_list = next;
|
| 6638 |
|
|
}
|
| 6639 |
|
|
}
|
| 6640 |
|
|
|
| 6641 |
|
|
/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
|
| 6642 |
|
|
We have decided we cannot use this list, so revert all changes
|
| 6643 |
|
|
to the current function that were done by s390_chunkify_start. */
|
| 6644 |
|
|
|
| 6645 |
|
|
static void
|
| 6646 |
|
|
s390_chunkify_cancel (struct constant_pool *pool_list)
|
| 6647 |
|
|
{
|
| 6648 |
|
|
struct constant_pool *curr_pool = NULL;
|
| 6649 |
|
|
rtx insn;
|
| 6650 |
|
|
|
| 6651 |
|
|
/* Remove all pool placeholder insns. */
|
| 6652 |
|
|
|
| 6653 |
|
|
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
|
| 6654 |
|
|
{
|
| 6655 |
|
|
/* Did we insert an extra barrier? Remove it. */
|
| 6656 |
|
|
rtx barrier = PREV_INSN (curr_pool->pool_insn);
|
| 6657 |
|
|
rtx jump = barrier? PREV_INSN (barrier) : NULL_RTX;
|
| 6658 |
|
|
rtx label = NEXT_INSN (curr_pool->pool_insn);
|
| 6659 |
|
|
|
| 6660 |
|
|
if (jump && GET_CODE (jump) == JUMP_INSN
|
| 6661 |
|
|
&& barrier && GET_CODE (barrier) == BARRIER
|
| 6662 |
|
|
&& label && GET_CODE (label) == CODE_LABEL
|
| 6663 |
|
|
&& GET_CODE (PATTERN (jump)) == SET
|
| 6664 |
|
|
&& SET_DEST (PATTERN (jump)) == pc_rtx
|
| 6665 |
|
|
&& GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
|
| 6666 |
|
|
&& XEXP (SET_SRC (PATTERN (jump)), 0) == label)
|
| 6667 |
|
|
{
|
| 6668 |
|
|
remove_insn (jump);
|
| 6669 |
|
|
remove_insn (barrier);
|
| 6670 |
|
|
remove_insn (label);
|
| 6671 |
|
|
}
|
| 6672 |
|
|
|
| 6673 |
|
|
remove_insn (curr_pool->pool_insn);
|
| 6674 |
|
|
}
|
| 6675 |
|
|
|
| 6676 |
|
|
/* Remove all base register reload insns. */
|
| 6677 |
|
|
|
| 6678 |
|
|
for (insn = get_insns (); insn; )
|
| 6679 |
|
|
{
|
| 6680 |
|
|
rtx next_insn = NEXT_INSN (insn);
|
| 6681 |
|
|
|
| 6682 |
|
|
if (GET_CODE (insn) == INSN
|
| 6683 |
|
|
&& GET_CODE (PATTERN (insn)) == SET
|
| 6684 |
|
|
&& GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
|
| 6685 |
|
|
&& XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_RELOAD_BASE)
|
| 6686 |
|
|
remove_insn (insn);
|
| 6687 |
|
|
|
| 6688 |
|
|
insn = next_insn;
|
| 6689 |
|
|
}
|
| 6690 |
|
|
|
| 6691 |
|
|
/* Free pool list. */
|
| 6692 |
|
|
|
| 6693 |
|
|
while (pool_list)
|
| 6694 |
|
|
{
|
| 6695 |
|
|
struct constant_pool *next = pool_list->next;
|
| 6696 |
|
|
s390_free_pool (pool_list);
|
| 6697 |
|
|
pool_list = next;
|
| 6698 |
|
|
}
|
| 6699 |
|
|
}
|
| 6700 |
|
|
|
| 6701 |
|
|
/* Output the constant pool entry EXP in mode MODE with alignment ALIGN. */
|
| 6702 |
|
|
|
| 6703 |
|
|
void
|
| 6704 |
|
|
s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align)
|
| 6705 |
|
|
{
|
| 6706 |
|
|
REAL_VALUE_TYPE r;
|
| 6707 |
|
|
|
| 6708 |
|
|
switch (GET_MODE_CLASS (mode))
|
| 6709 |
|
|
{
|
| 6710 |
|
|
case MODE_FLOAT:
|
| 6711 |
|
|
case MODE_DECIMAL_FLOAT:
|
| 6712 |
|
|
gcc_assert (GET_CODE (exp) == CONST_DOUBLE);
|
| 6713 |
|
|
|
| 6714 |
|
|
REAL_VALUE_FROM_CONST_DOUBLE (r, exp);
|
| 6715 |
|
|
assemble_real (r, mode, align);
|
| 6716 |
|
|
break;
|
| 6717 |
|
|
|
| 6718 |
|
|
case MODE_INT:
|
| 6719 |
|
|
assemble_integer (exp, GET_MODE_SIZE (mode), align, 1);
|
| 6720 |
|
|
mark_symbol_refs_as_used (exp);
|
| 6721 |
|
|
break;
|
| 6722 |
|
|
|
| 6723 |
|
|
default:
|
| 6724 |
|
|
gcc_unreachable ();
|
| 6725 |
|
|
}
|
| 6726 |
|
|
}
|
| 6727 |
|
|
|
| 6728 |
|
|
|
| 6729 |
|
|
/* Return an RTL expression representing the value of the return address
|
| 6730 |
|
|
for the frame COUNT steps up from the current frame. FRAME is the
|
| 6731 |
|
|
frame pointer of that frame. */
|
| 6732 |
|
|
|
| 6733 |
|
|
rtx
|
| 6734 |
|
|
s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
|
| 6735 |
|
|
{
|
| 6736 |
|
|
int offset;
|
| 6737 |
|
|
rtx addr;
|
| 6738 |
|
|
|
| 6739 |
|
|
/* Without backchain, we fail for all but the current frame. */
|
| 6740 |
|
|
|
| 6741 |
|
|
if (!TARGET_BACKCHAIN && count > 0)
|
| 6742 |
|
|
return NULL_RTX;
|
| 6743 |
|
|
|
| 6744 |
|
|
/* For the current frame, we need to make sure the initial
|
| 6745 |
|
|
value of RETURN_REGNUM is actually saved. */
|
| 6746 |
|
|
|
| 6747 |
|
|
if (count == 0)
|
| 6748 |
|
|
{
|
| 6749 |
|
|
/* On non-z architectures branch splitting could overwrite r14. */
|
| 6750 |
|
|
if (TARGET_CPU_ZARCH)
|
| 6751 |
|
|
return get_hard_reg_initial_val (Pmode, RETURN_REGNUM);
|
| 6752 |
|
|
else
|
| 6753 |
|
|
{
|
| 6754 |
|
|
cfun_frame_layout.save_return_addr_p = true;
|
| 6755 |
|
|
return gen_rtx_MEM (Pmode, return_address_pointer_rtx);
|
| 6756 |
|
|
}
|
| 6757 |
|
|
}
|
| 6758 |
|
|
|
| 6759 |
|
|
if (TARGET_PACKED_STACK)
|
| 6760 |
|
|
offset = -2 * UNITS_PER_WORD;
|
| 6761 |
|
|
else
|
| 6762 |
|
|
offset = RETURN_REGNUM * UNITS_PER_WORD;
|
| 6763 |
|
|
|
| 6764 |
|
|
addr = plus_constant (frame, offset);
|
| 6765 |
|
|
addr = memory_address (Pmode, addr);
|
| 6766 |
|
|
return gen_rtx_MEM (Pmode, addr);
|
| 6767 |
|
|
}
|
| 6768 |
|
|
|
| 6769 |
|
|
/* Return an RTL expression representing the back chain stored in
|
| 6770 |
|
|
the current stack frame. */
|
| 6771 |
|
|
|
| 6772 |
|
|
rtx
|
| 6773 |
|
|
s390_back_chain_rtx (void)
|
| 6774 |
|
|
{
|
| 6775 |
|
|
rtx chain;
|
| 6776 |
|
|
|
| 6777 |
|
|
gcc_assert (TARGET_BACKCHAIN);
|
| 6778 |
|
|
|
| 6779 |
|
|
if (TARGET_PACKED_STACK)
|
| 6780 |
|
|
chain = plus_constant (stack_pointer_rtx,
|
| 6781 |
|
|
STACK_POINTER_OFFSET - UNITS_PER_WORD);
|
| 6782 |
|
|
else
|
| 6783 |
|
|
chain = stack_pointer_rtx;
|
| 6784 |
|
|
|
| 6785 |
|
|
chain = gen_rtx_MEM (Pmode, chain);
|
| 6786 |
|
|
return chain;
|
| 6787 |
|
|
}
|
| 6788 |
|
|
|
| 6789 |
|
|
/* Find first call clobbered register unused in a function.
|
| 6790 |
|
|
This could be used as base register in a leaf function
|
| 6791 |
|
|
or for holding the return address before epilogue. */
|
| 6792 |
|
|
|
| 6793 |
|
|
static int
|
| 6794 |
|
|
find_unused_clobbered_reg (void)
|
| 6795 |
|
|
{
|
| 6796 |
|
|
int i;
|
| 6797 |
|
|
for (i = 0; i < 6; i++)
|
| 6798 |
|
|
if (!df_regs_ever_live_p (i))
|
| 6799 |
|
|
return i;
|
| 6800 |
|
|
return 0;
|
| 6801 |
|
|
}
|
| 6802 |
|
|
|
| 6803 |
|
|
|
| 6804 |
|
|
/* Helper function for s390_regs_ever_clobbered. Sets the fields in DATA for all
|
| 6805 |
|
|
clobbered hard regs in SETREG. */
|
| 6806 |
|
|
|
| 6807 |
|
|
static void
|
| 6808 |
|
|
s390_reg_clobbered_rtx (rtx setreg, const_rtx set_insn ATTRIBUTE_UNUSED, void *data)
|
| 6809 |
|
|
{
|
| 6810 |
|
|
int *regs_ever_clobbered = (int *)data;
|
| 6811 |
|
|
unsigned int i, regno;
|
| 6812 |
|
|
enum machine_mode mode = GET_MODE (setreg);
|
| 6813 |
|
|
|
| 6814 |
|
|
if (GET_CODE (setreg) == SUBREG)
|
| 6815 |
|
|
{
|
| 6816 |
|
|
rtx inner = SUBREG_REG (setreg);
|
| 6817 |
|
|
if (!GENERAL_REG_P (inner))
|
| 6818 |
|
|
return;
|
| 6819 |
|
|
regno = subreg_regno (setreg);
|
| 6820 |
|
|
}
|
| 6821 |
|
|
else if (GENERAL_REG_P (setreg))
|
| 6822 |
|
|
regno = REGNO (setreg);
|
| 6823 |
|
|
else
|
| 6824 |
|
|
return;
|
| 6825 |
|
|
|
| 6826 |
|
|
for (i = regno;
|
| 6827 |
|
|
i < regno + HARD_REGNO_NREGS (regno, mode);
|
| 6828 |
|
|
i++)
|
| 6829 |
|
|
regs_ever_clobbered[i] = 1;
|
| 6830 |
|
|
}
|
| 6831 |
|
|
|
| 6832 |
|
|
/* Walks through all basic blocks of the current function looking
|
| 6833 |
|
|
for clobbered hard regs using s390_reg_clobbered_rtx. The fields
|
| 6834 |
|
|
of the passed integer array REGS_EVER_CLOBBERED are set to one for
|
| 6835 |
|
|
each of those regs. */
|
| 6836 |
|
|
|
| 6837 |
|
|
static void
|
| 6838 |
|
|
s390_regs_ever_clobbered (int *regs_ever_clobbered)
|
| 6839 |
|
|
{
|
| 6840 |
|
|
basic_block cur_bb;
|
| 6841 |
|
|
rtx cur_insn;
|
| 6842 |
|
|
unsigned int i;
|
| 6843 |
|
|
|
| 6844 |
|
|
memset (regs_ever_clobbered, 0, 16 * sizeof (int));
|
| 6845 |
|
|
|
| 6846 |
|
|
/* For non-leaf functions we have to consider all call clobbered regs to be
|
| 6847 |
|
|
clobbered. */
|
| 6848 |
|
|
if (!current_function_is_leaf)
|
| 6849 |
|
|
{
|
| 6850 |
|
|
for (i = 0; i < 16; i++)
|
| 6851 |
|
|
regs_ever_clobbered[i] = call_really_used_regs[i];
|
| 6852 |
|
|
}
|
| 6853 |
|
|
|
| 6854 |
|
|
/* Make the "magic" eh_return registers live if necessary. For regs_ever_live
|
| 6855 |
|
|
this work is done by liveness analysis (mark_regs_live_at_end).
|
| 6856 |
|
|
Special care is needed for functions containing landing pads. Landing pads
|
| 6857 |
|
|
may use the eh registers, but the code which sets these registers is not
|
| 6858 |
|
|
contained in that function. Hence s390_regs_ever_clobbered is not able to
|
| 6859 |
|
|
deal with this automatically. */
|
| 6860 |
|
|
if (crtl->calls_eh_return || cfun->machine->has_landing_pad_p)
|
| 6861 |
|
|
for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM ; i++)
|
| 6862 |
|
|
if (crtl->calls_eh_return
|
| 6863 |
|
|
|| (cfun->machine->has_landing_pad_p
|
| 6864 |
|
|
&& df_regs_ever_live_p (EH_RETURN_DATA_REGNO (i))))
|
| 6865 |
|
|
regs_ever_clobbered[EH_RETURN_DATA_REGNO (i)] = 1;
|
| 6866 |
|
|
|
| 6867 |
|
|
/* For nonlocal gotos all call-saved registers have to be saved.
|
| 6868 |
|
|
This flag is also set for the unwinding code in libgcc.
|
| 6869 |
|
|
See expand_builtin_unwind_init. For regs_ever_live this is done by
|
| 6870 |
|
|
reload. */
|
| 6871 |
|
|
if (cfun->has_nonlocal_label)
|
| 6872 |
|
|
for (i = 0; i < 16; i++)
|
| 6873 |
|
|
if (!call_really_used_regs[i])
|
| 6874 |
|
|
regs_ever_clobbered[i] = 1;
|
| 6875 |
|
|
|
| 6876 |
|
|
FOR_EACH_BB (cur_bb)
|
| 6877 |
|
|
{
|
| 6878 |
|
|
FOR_BB_INSNS (cur_bb, cur_insn)
|
| 6879 |
|
|
{
|
| 6880 |
|
|
if (INSN_P (cur_insn))
|
| 6881 |
|
|
note_stores (PATTERN (cur_insn),
|
| 6882 |
|
|
s390_reg_clobbered_rtx,
|
| 6883 |
|
|
regs_ever_clobbered);
|
| 6884 |
|
|
}
|
| 6885 |
|
|
}
|
| 6886 |
|
|
}
|
| 6887 |
|
|
|
| 6888 |
|
|
/* Determine the frame area which actually has to be accessed
|
| 6889 |
|
|
in the function epilogue. The values are stored at the
|
| 6890 |
|
|
given pointers AREA_BOTTOM (address of the lowest used stack
|
| 6891 |
|
|
address) and AREA_TOP (address of the first item which does
|
| 6892 |
|
|
not belong to the stack frame). */
|
| 6893 |
|
|
|
| 6894 |
|
|
static void
|
| 6895 |
|
|
s390_frame_area (int *area_bottom, int *area_top)
|
| 6896 |
|
|
{
|
| 6897 |
|
|
int b, t;
|
| 6898 |
|
|
int i;
|
| 6899 |
|
|
|
| 6900 |
|
|
b = INT_MAX;
|
| 6901 |
|
|
t = INT_MIN;
|
| 6902 |
|
|
|
| 6903 |
|
|
if (cfun_frame_layout.first_restore_gpr != -1)
|
| 6904 |
|
|
{
|
| 6905 |
|
|
b = (cfun_frame_layout.gprs_offset
|
| 6906 |
|
|
+ cfun_frame_layout.first_restore_gpr * UNITS_PER_WORD);
|
| 6907 |
|
|
t = b + (cfun_frame_layout.last_restore_gpr
|
| 6908 |
|
|
- cfun_frame_layout.first_restore_gpr + 1) * UNITS_PER_WORD;
|
| 6909 |
|
|
}
|
| 6910 |
|
|
|
| 6911 |
|
|
if (TARGET_64BIT && cfun_save_high_fprs_p)
|
| 6912 |
|
|
{
|
| 6913 |
|
|
b = MIN (b, cfun_frame_layout.f8_offset);
|
| 6914 |
|
|
t = MAX (t, (cfun_frame_layout.f8_offset
|
| 6915 |
|
|
+ cfun_frame_layout.high_fprs * 8));
|
| 6916 |
|
|
}
|
| 6917 |
|
|
|
| 6918 |
|
|
if (!TARGET_64BIT)
|
| 6919 |
|
|
for (i = 2; i < 4; i++)
|
| 6920 |
|
|
if (cfun_fpr_bit_p (i))
|
| 6921 |
|
|
{
|
| 6922 |
|
|
b = MIN (b, cfun_frame_layout.f4_offset + (i - 2) * 8);
|
| 6923 |
|
|
t = MAX (t, cfun_frame_layout.f4_offset + (i - 1) * 8);
|
| 6924 |
|
|
}
|
| 6925 |
|
|
|
| 6926 |
|
|
*area_bottom = b;
|
| 6927 |
|
|
*area_top = t;
|
| 6928 |
|
|
}
|
| 6929 |
|
|
|
| 6930 |
|
|
/* Fill cfun->machine with info about register usage of current function.
|
| 6931 |
|
|
Return in CLOBBERED_REGS which GPRs are currently considered set. */
|
| 6932 |
|
|
|
| 6933 |
|
|
static void
|
| 6934 |
|
|
s390_register_info (int clobbered_regs[])
|
| 6935 |
|
|
{
|
| 6936 |
|
|
int i, j;
|
| 6937 |
|
|
|
| 6938 |
|
|
/* fprs 8 - 15 are call saved for 64 Bit ABI. */
|
| 6939 |
|
|
cfun_frame_layout.fpr_bitmap = 0;
|
| 6940 |
|
|
cfun_frame_layout.high_fprs = 0;
|
| 6941 |
|
|
if (TARGET_64BIT)
|
| 6942 |
|
|
for (i = 24; i < 32; i++)
|
| 6943 |
|
|
if (df_regs_ever_live_p (i) && !global_regs[i])
|
| 6944 |
|
|
{
|
| 6945 |
|
|
cfun_set_fpr_bit (i - 16);
|
| 6946 |
|
|
cfun_frame_layout.high_fprs++;
|
| 6947 |
|
|
}
|
| 6948 |
|
|
|
| 6949 |
|
|
/* Find first and last gpr to be saved. We trust regs_ever_live
|
| 6950 |
|
|
data, except that we don't save and restore global registers.
|
| 6951 |
|
|
|
| 6952 |
|
|
Also, all registers with special meaning to the compiler need
|
| 6953 |
|
|
to be handled extra. */
|
| 6954 |
|
|
|
| 6955 |
|
|
s390_regs_ever_clobbered (clobbered_regs);
|
| 6956 |
|
|
|
| 6957 |
|
|
for (i = 0; i < 16; i++)
|
| 6958 |
|
|
clobbered_regs[i] = clobbered_regs[i] && !global_regs[i] && !fixed_regs[i];
|
| 6959 |
|
|
|
| 6960 |
|
|
if (frame_pointer_needed)
|
| 6961 |
|
|
clobbered_regs[HARD_FRAME_POINTER_REGNUM] = 1;
|
| 6962 |
|
|
|
| 6963 |
|
|
if (flag_pic)
|
| 6964 |
|
|
clobbered_regs[PIC_OFFSET_TABLE_REGNUM]
|
| 6965 |
|
|
|= df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM);
|
| 6966 |
|
|
|
| 6967 |
|
|
clobbered_regs[BASE_REGNUM]
|
| 6968 |
|
|
|= (cfun->machine->base_reg
|
| 6969 |
|
|
&& REGNO (cfun->machine->base_reg) == BASE_REGNUM);
|
| 6970 |
|
|
|
| 6971 |
|
|
clobbered_regs[RETURN_REGNUM]
|
| 6972 |
|
|
|= (!current_function_is_leaf
|
| 6973 |
|
|
|| TARGET_TPF_PROFILING
|
| 6974 |
|
|
|| cfun->machine->split_branches_pending_p
|
| 6975 |
|
|
|| cfun_frame_layout.save_return_addr_p
|
| 6976 |
|
|
|| crtl->calls_eh_return
|
| 6977 |
|
|
|| cfun->stdarg);
|
| 6978 |
|
|
|
| 6979 |
|
|
clobbered_regs[STACK_POINTER_REGNUM]
|
| 6980 |
|
|
|= (!current_function_is_leaf
|
| 6981 |
|
|
|| TARGET_TPF_PROFILING
|
| 6982 |
|
|
|| cfun_save_high_fprs_p
|
| 6983 |
|
|
|| get_frame_size () > 0
|
| 6984 |
|
|
|| cfun->calls_alloca
|
| 6985 |
|
|
|| cfun->stdarg);
|
| 6986 |
|
|
|
| 6987 |
|
|
for (i = 6; i < 16; i++)
|
| 6988 |
|
|
if (df_regs_ever_live_p (i) || clobbered_regs[i])
|
| 6989 |
|
|
break;
|
| 6990 |
|
|
for (j = 15; j > i; j--)
|
| 6991 |
|
|
if (df_regs_ever_live_p (j) || clobbered_regs[j])
|
| 6992 |
|
|
break;
|
| 6993 |
|
|
|
| 6994 |
|
|
if (i == 16)
|
| 6995 |
|
|
{
|
| 6996 |
|
|
/* Nothing to save/restore. */
|
| 6997 |
|
|
cfun_frame_layout.first_save_gpr_slot = -1;
|
| 6998 |
|
|
cfun_frame_layout.last_save_gpr_slot = -1;
|
| 6999 |
|
|
cfun_frame_layout.first_save_gpr = -1;
|
| 7000 |
|
|
cfun_frame_layout.first_restore_gpr = -1;
|
| 7001 |
|
|
cfun_frame_layout.last_save_gpr = -1;
|
| 7002 |
|
|
cfun_frame_layout.last_restore_gpr = -1;
|
| 7003 |
|
|
}
|
| 7004 |
|
|
else
|
| 7005 |
|
|
{
|
| 7006 |
|
|
/* Save slots for gprs from i to j. */
|
| 7007 |
|
|
cfun_frame_layout.first_save_gpr_slot = i;
|
| 7008 |
|
|
cfun_frame_layout.last_save_gpr_slot = j;
|
| 7009 |
|
|
|
| 7010 |
|
|
for (i = cfun_frame_layout.first_save_gpr_slot;
|
| 7011 |
|
|
i < cfun_frame_layout.last_save_gpr_slot + 1;
|
| 7012 |
|
|
i++)
|
| 7013 |
|
|
if (clobbered_regs[i])
|
| 7014 |
|
|
break;
|
| 7015 |
|
|
|
| 7016 |
|
|
for (j = cfun_frame_layout.last_save_gpr_slot; j > i; j--)
|
| 7017 |
|
|
if (clobbered_regs[j])
|
| 7018 |
|
|
break;
|
| 7019 |
|
|
|
| 7020 |
|
|
if (i == cfun_frame_layout.last_save_gpr_slot + 1)
|
| 7021 |
|
|
{
|
| 7022 |
|
|
/* Nothing to save/restore. */
|
| 7023 |
|
|
cfun_frame_layout.first_save_gpr = -1;
|
| 7024 |
|
|
cfun_frame_layout.first_restore_gpr = -1;
|
| 7025 |
|
|
cfun_frame_layout.last_save_gpr = -1;
|
| 7026 |
|
|
cfun_frame_layout.last_restore_gpr = -1;
|
| 7027 |
|
|
}
|
| 7028 |
|
|
else
|
| 7029 |
|
|
{
|
| 7030 |
|
|
/* Save / Restore from gpr i to j. */
|
| 7031 |
|
|
cfun_frame_layout.first_save_gpr = i;
|
| 7032 |
|
|
cfun_frame_layout.first_restore_gpr = i;
|
| 7033 |
|
|
cfun_frame_layout.last_save_gpr = j;
|
| 7034 |
|
|
cfun_frame_layout.last_restore_gpr = j;
|
| 7035 |
|
|
}
|
| 7036 |
|
|
}
|
| 7037 |
|
|
|
| 7038 |
|
|
if (cfun->stdarg)
|
| 7039 |
|
|
{
|
| 7040 |
|
|
/* Varargs functions need to save gprs 2 to 6. */
|
| 7041 |
|
|
if (cfun->va_list_gpr_size
|
| 7042 |
|
|
&& crtl->args.info.gprs < GP_ARG_NUM_REG)
|
| 7043 |
|
|
{
|
| 7044 |
|
|
int min_gpr = crtl->args.info.gprs;
|
| 7045 |
|
|
int max_gpr = min_gpr + cfun->va_list_gpr_size;
|
| 7046 |
|
|
if (max_gpr > GP_ARG_NUM_REG)
|
| 7047 |
|
|
max_gpr = GP_ARG_NUM_REG;
|
| 7048 |
|
|
|
| 7049 |
|
|
if (cfun_frame_layout.first_save_gpr == -1
|
| 7050 |
|
|
|| cfun_frame_layout.first_save_gpr > 2 + min_gpr)
|
| 7051 |
|
|
{
|
| 7052 |
|
|
cfun_frame_layout.first_save_gpr = 2 + min_gpr;
|
| 7053 |
|
|
cfun_frame_layout.first_save_gpr_slot = 2 + min_gpr;
|
| 7054 |
|
|
}
|
| 7055 |
|
|
|
| 7056 |
|
|
if (cfun_frame_layout.last_save_gpr == -1
|
| 7057 |
|
|
|| cfun_frame_layout.last_save_gpr < 2 + max_gpr - 1)
|
| 7058 |
|
|
{
|
| 7059 |
|
|
cfun_frame_layout.last_save_gpr = 2 + max_gpr - 1;
|
| 7060 |
|
|
cfun_frame_layout.last_save_gpr_slot = 2 + max_gpr - 1;
|
| 7061 |
|
|
}
|
| 7062 |
|
|
}
|
| 7063 |
|
|
|
| 7064 |
|
|
/* Mark f0, f2 for 31 bit and f0-f4 for 64 bit to be saved. */
|
| 7065 |
|
|
if (TARGET_HARD_FLOAT && cfun->va_list_fpr_size
|
| 7066 |
|
|
&& crtl->args.info.fprs < FP_ARG_NUM_REG)
|
| 7067 |
|
|
{
|
| 7068 |
|
|
int min_fpr = crtl->args.info.fprs;
|
| 7069 |
|
|
int max_fpr = min_fpr + cfun->va_list_fpr_size;
|
| 7070 |
|
|
if (max_fpr > FP_ARG_NUM_REG)
|
| 7071 |
|
|
max_fpr = FP_ARG_NUM_REG;
|
| 7072 |
|
|
|
| 7073 |
|
|
/* ??? This is currently required to ensure proper location
|
| 7074 |
|
|
of the fpr save slots within the va_list save area. */
|
| 7075 |
|
|
if (TARGET_PACKED_STACK)
|
| 7076 |
|
|
min_fpr = 0;
|
| 7077 |
|
|
|
| 7078 |
|
|
for (i = min_fpr; i < max_fpr; i++)
|
| 7079 |
|
|
cfun_set_fpr_bit (i);
|
| 7080 |
|
|
}
|
| 7081 |
|
|
}
|
| 7082 |
|
|
|
| 7083 |
|
|
if (!TARGET_64BIT)
|
| 7084 |
|
|
for (i = 2; i < 4; i++)
|
| 7085 |
|
|
if (df_regs_ever_live_p (i + 16) && !global_regs[i + 16])
|
| 7086 |
|
|
cfun_set_fpr_bit (i);
|
| 7087 |
|
|
}
|
| 7088 |
|
|
|
| 7089 |
|
|
/* Fill cfun->machine with info about frame of current function. */
|
| 7090 |
|
|
|
| 7091 |
|
|
static void
|
| 7092 |
|
|
s390_frame_info (void)
|
| 7093 |
|
|
{
|
| 7094 |
|
|
int i;
|
| 7095 |
|
|
|
| 7096 |
|
|
cfun_frame_layout.frame_size = get_frame_size ();
|
| 7097 |
|
|
if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000)
|
| 7098 |
|
|
fatal_error ("total size of local variables exceeds architecture limit");
|
| 7099 |
|
|
|
| 7100 |
|
|
if (!TARGET_PACKED_STACK)
|
| 7101 |
|
|
{
|
| 7102 |
|
|
cfun_frame_layout.backchain_offset = 0;
|
| 7103 |
|
|
cfun_frame_layout.f0_offset = 16 * UNITS_PER_WORD;
|
| 7104 |
|
|
cfun_frame_layout.f4_offset = cfun_frame_layout.f0_offset + 2 * 8;
|
| 7105 |
|
|
cfun_frame_layout.f8_offset = -cfun_frame_layout.high_fprs * 8;
|
| 7106 |
|
|
cfun_frame_layout.gprs_offset = (cfun_frame_layout.first_save_gpr_slot
|
| 7107 |
|
|
* UNITS_PER_WORD);
|
| 7108 |
|
|
}
|
| 7109 |
|
|
else if (TARGET_BACKCHAIN) /* kernel stack layout */
|
| 7110 |
|
|
{
|
| 7111 |
|
|
cfun_frame_layout.backchain_offset = (STACK_POINTER_OFFSET
|
| 7112 |
|
|
- UNITS_PER_WORD);
|
| 7113 |
|
|
cfun_frame_layout.gprs_offset
|
| 7114 |
|
|
= (cfun_frame_layout.backchain_offset
|
| 7115 |
|
|
- (STACK_POINTER_REGNUM - cfun_frame_layout.first_save_gpr_slot + 1)
|
| 7116 |
|
|
* UNITS_PER_WORD);
|
| 7117 |
|
|
|
| 7118 |
|
|
if (TARGET_64BIT)
|
| 7119 |
|
|
{
|
| 7120 |
|
|
cfun_frame_layout.f4_offset
|
| 7121 |
|
|
= (cfun_frame_layout.gprs_offset
|
| 7122 |
|
|
- 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
|
| 7123 |
|
|
|
| 7124 |
|
|
cfun_frame_layout.f0_offset
|
| 7125 |
|
|
= (cfun_frame_layout.f4_offset
|
| 7126 |
|
|
- 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
|
| 7127 |
|
|
}
|
| 7128 |
|
|
else
|
| 7129 |
|
|
{
|
| 7130 |
|
|
/* On 31 bit we have to care about alignment of the
|
| 7131 |
|
|
floating point regs to provide fastest access. */
|
| 7132 |
|
|
cfun_frame_layout.f0_offset
|
| 7133 |
|
|
= ((cfun_frame_layout.gprs_offset
|
| 7134 |
|
|
& ~(STACK_BOUNDARY / BITS_PER_UNIT - 1))
|
| 7135 |
|
|
- 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
|
| 7136 |
|
|
|
| 7137 |
|
|
cfun_frame_layout.f4_offset
|
| 7138 |
|
|
= (cfun_frame_layout.f0_offset
|
| 7139 |
|
|
- 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
|
| 7140 |
|
|
}
|
| 7141 |
|
|
}
|
| 7142 |
|
|
else /* no backchain */
|
| 7143 |
|
|
{
|
| 7144 |
|
|
cfun_frame_layout.f4_offset
|
| 7145 |
|
|
= (STACK_POINTER_OFFSET
|
| 7146 |
|
|
- 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
|
| 7147 |
|
|
|
| 7148 |
|
|
cfun_frame_layout.f0_offset
|
| 7149 |
|
|
= (cfun_frame_layout.f4_offset
|
| 7150 |
|
|
- 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
|
| 7151 |
|
|
|
| 7152 |
|
|
cfun_frame_layout.gprs_offset
|
| 7153 |
|
|
= cfun_frame_layout.f0_offset - cfun_gprs_save_area_size;
|
| 7154 |
|
|
}
|
| 7155 |
|
|
|
| 7156 |
|
|
if (current_function_is_leaf
|
| 7157 |
|
|
&& !TARGET_TPF_PROFILING
|
| 7158 |
|
|
&& cfun_frame_layout.frame_size == 0
|
| 7159 |
|
|
&& !cfun_save_high_fprs_p
|
| 7160 |
|
|
&& !cfun->calls_alloca
|
| 7161 |
|
|
&& !cfun->stdarg)
|
| 7162 |
|
|
return;
|
| 7163 |
|
|
|
| 7164 |
|
|
if (!TARGET_PACKED_STACK)
|
| 7165 |
|
|
cfun_frame_layout.frame_size += (STACK_POINTER_OFFSET
|
| 7166 |
|
|
+ crtl->outgoing_args_size
|
| 7167 |
|
|
+ cfun_frame_layout.high_fprs * 8);
|
| 7168 |
|
|
else
|
| 7169 |
|
|
{
|
| 7170 |
|
|
if (TARGET_BACKCHAIN)
|
| 7171 |
|
|
cfun_frame_layout.frame_size += UNITS_PER_WORD;
|
| 7172 |
|
|
|
| 7173 |
|
|
/* No alignment trouble here because f8-f15 are only saved under
|
| 7174 |
|
|
64 bit. */
|
| 7175 |
|
|
cfun_frame_layout.f8_offset = (MIN (MIN (cfun_frame_layout.f0_offset,
|
| 7176 |
|
|
cfun_frame_layout.f4_offset),
|
| 7177 |
|
|
cfun_frame_layout.gprs_offset)
|
| 7178 |
|
|
- cfun_frame_layout.high_fprs * 8);
|
| 7179 |
|
|
|
| 7180 |
|
|
cfun_frame_layout.frame_size += cfun_frame_layout.high_fprs * 8;
|
| 7181 |
|
|
|
| 7182 |
|
|
for (i = 0; i < 8; i++)
|
| 7183 |
|
|
if (cfun_fpr_bit_p (i))
|
| 7184 |
|
|
cfun_frame_layout.frame_size += 8;
|
| 7185 |
|
|
|
| 7186 |
|
|
cfun_frame_layout.frame_size += cfun_gprs_save_area_size;
|
| 7187 |
|
|
|
| 7188 |
|
|
/* If under 31 bit an odd number of gprs has to be saved we have to adjust
|
| 7189 |
|
|
the frame size to sustain 8 byte alignment of stack frames. */
|
| 7190 |
|
|
cfun_frame_layout.frame_size = ((cfun_frame_layout.frame_size +
|
| 7191 |
|
|
STACK_BOUNDARY / BITS_PER_UNIT - 1)
|
| 7192 |
|
|
& ~(STACK_BOUNDARY / BITS_PER_UNIT - 1));
|
| 7193 |
|
|
|
| 7194 |
|
|
cfun_frame_layout.frame_size += crtl->outgoing_args_size;
|
| 7195 |
|
|
}
|
| 7196 |
|
|
}
|
| 7197 |
|
|
|
| 7198 |
|
|
/* Generate frame layout. Fills in register and frame data for the current
|
| 7199 |
|
|
function in cfun->machine. This routine can be called multiple times;
|
| 7200 |
|
|
it will re-do the complete frame layout every time. */
|
| 7201 |
|
|
|
| 7202 |
|
|
static void
|
| 7203 |
|
|
s390_init_frame_layout (void)
|
| 7204 |
|
|
{
|
| 7205 |
|
|
HOST_WIDE_INT frame_size;
|
| 7206 |
|
|
int base_used;
|
| 7207 |
|
|
int clobbered_regs[16];
|
| 7208 |
|
|
|
| 7209 |
|
|
/* On S/390 machines, we may need to perform branch splitting, which
|
| 7210 |
|
|
will require both base and return address register. We have no
|
| 7211 |
|
|
choice but to assume we're going to need them until right at the
|
| 7212 |
|
|
end of the machine dependent reorg phase. */
|
| 7213 |
|
|
if (!TARGET_CPU_ZARCH)
|
| 7214 |
|
|
cfun->machine->split_branches_pending_p = true;
|
| 7215 |
|
|
|
| 7216 |
|
|
do
|
| 7217 |
|
|
{
|
| 7218 |
|
|
frame_size = cfun_frame_layout.frame_size;
|
| 7219 |
|
|
|
| 7220 |
|
|
/* Try to predict whether we'll need the base register. */
|
| 7221 |
|
|
base_used = cfun->machine->split_branches_pending_p
|
| 7222 |
|
|
|| crtl->uses_const_pool
|
| 7223 |
|
|
|| (!DISP_IN_RANGE (frame_size)
|
| 7224 |
|
|
&& !CONST_OK_FOR_K (frame_size));
|
| 7225 |
|
|
|
| 7226 |
|
|
/* Decide which register to use as literal pool base. In small
|
| 7227 |
|
|
leaf functions, try to use an unused call-clobbered register
|
| 7228 |
|
|
as base register to avoid save/restore overhead. */
|
| 7229 |
|
|
if (!base_used)
|
| 7230 |
|
|
cfun->machine->base_reg = NULL_RTX;
|
| 7231 |
|
|
else if (current_function_is_leaf && !df_regs_ever_live_p (5))
|
| 7232 |
|
|
cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
|
| 7233 |
|
|
else
|
| 7234 |
|
|
cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
|
| 7235 |
|
|
|
| 7236 |
|
|
s390_register_info (clobbered_regs);
|
| 7237 |
|
|
s390_frame_info ();
|
| 7238 |
|
|
}
|
| 7239 |
|
|
while (frame_size != cfun_frame_layout.frame_size);
|
| 7240 |
|
|
}
|
| 7241 |
|
|
|
| 7242 |
|
|
/* Update frame layout. Recompute actual register save data based on
|
| 7243 |
|
|
current info and update regs_ever_live for the special registers.
|
| 7244 |
|
|
May be called multiple times, but may never cause *more* registers
|
| 7245 |
|
|
to be saved than s390_init_frame_layout allocated room for. */
|
| 7246 |
|
|
|
| 7247 |
|
|
static void
|
| 7248 |
|
|
s390_update_frame_layout (void)
|
| 7249 |
|
|
{
|
| 7250 |
|
|
int clobbered_regs[16];
|
| 7251 |
|
|
|
| 7252 |
|
|
s390_register_info (clobbered_regs);
|
| 7253 |
|
|
|
| 7254 |
|
|
df_set_regs_ever_live (BASE_REGNUM,
|
| 7255 |
|
|
clobbered_regs[BASE_REGNUM] ? true : false);
|
| 7256 |
|
|
df_set_regs_ever_live (RETURN_REGNUM,
|
| 7257 |
|
|
clobbered_regs[RETURN_REGNUM] ? true : false);
|
| 7258 |
|
|
df_set_regs_ever_live (STACK_POINTER_REGNUM,
|
| 7259 |
|
|
clobbered_regs[STACK_POINTER_REGNUM] ? true : false);
|
| 7260 |
|
|
|
| 7261 |
|
|
if (cfun->machine->base_reg)
|
| 7262 |
|
|
df_set_regs_ever_live (REGNO (cfun->machine->base_reg), true);
|
| 7263 |
|
|
}
|
| 7264 |
|
|
|
| 7265 |
|
|
/* Return true if it is legal to put a value with MODE into REGNO. */
|
| 7266 |
|
|
|
| 7267 |
|
|
bool
|
| 7268 |
|
|
s390_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
|
| 7269 |
|
|
{
|
| 7270 |
|
|
switch (REGNO_REG_CLASS (regno))
|
| 7271 |
|
|
{
|
| 7272 |
|
|
case FP_REGS:
|
| 7273 |
|
|
if (REGNO_PAIR_OK (regno, mode))
|
| 7274 |
|
|
{
|
| 7275 |
|
|
if (mode == SImode || mode == DImode)
|
| 7276 |
|
|
return true;
|
| 7277 |
|
|
|
| 7278 |
|
|
if (FLOAT_MODE_P (mode) && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT)
|
| 7279 |
|
|
return true;
|
| 7280 |
|
|
}
|
| 7281 |
|
|
break;
|
| 7282 |
|
|
case ADDR_REGS:
|
| 7283 |
|
|
if (FRAME_REGNO_P (regno) && mode == Pmode)
|
| 7284 |
|
|
return true;
|
| 7285 |
|
|
|
| 7286 |
|
|
/* fallthrough */
|
| 7287 |
|
|
case GENERAL_REGS:
|
| 7288 |
|
|
if (REGNO_PAIR_OK (regno, mode))
|
| 7289 |
|
|
{
|
| 7290 |
|
|
if (TARGET_64BIT
|
| 7291 |
|
|
|| (mode != TFmode && mode != TCmode && mode != TDmode))
|
| 7292 |
|
|
return true;
|
| 7293 |
|
|
}
|
| 7294 |
|
|
break;
|
| 7295 |
|
|
case CC_REGS:
|
| 7296 |
|
|
if (GET_MODE_CLASS (mode) == MODE_CC)
|
| 7297 |
|
|
return true;
|
| 7298 |
|
|
break;
|
| 7299 |
|
|
case ACCESS_REGS:
|
| 7300 |
|
|
if (REGNO_PAIR_OK (regno, mode))
|
| 7301 |
|
|
{
|
| 7302 |
|
|
if (mode == SImode || mode == Pmode)
|
| 7303 |
|
|
return true;
|
| 7304 |
|
|
}
|
| 7305 |
|
|
break;
|
| 7306 |
|
|
default:
|
| 7307 |
|
|
return false;
|
| 7308 |
|
|
}
|
| 7309 |
|
|
|
| 7310 |
|
|
return false;
|
| 7311 |
|
|
}
|
| 7312 |
|
|
|
| 7313 |
|
|
/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
|
| 7314 |
|
|
|
| 7315 |
|
|
bool
|
| 7316 |
|
|
s390_hard_regno_rename_ok (unsigned int old_reg, unsigned int new_reg)
|
| 7317 |
|
|
{
|
| 7318 |
|
|
/* Once we've decided upon a register to use as base register, it must
|
| 7319 |
|
|
no longer be used for any other purpose. */
|
| 7320 |
|
|
if (cfun->machine->base_reg)
|
| 7321 |
|
|
if (REGNO (cfun->machine->base_reg) == old_reg
|
| 7322 |
|
|
|| REGNO (cfun->machine->base_reg) == new_reg)
|
| 7323 |
|
|
return false;
|
| 7324 |
|
|
|
| 7325 |
|
|
return true;
|
| 7326 |
|
|
}
|
| 7327 |
|
|
|
| 7328 |
|
|
/* Maximum number of registers to represent a value of mode MODE
|
| 7329 |
|
|
in a register of class RCLASS. */
|
| 7330 |
|
|
|
| 7331 |
|
|
bool
|
| 7332 |
|
|
s390_class_max_nregs (enum reg_class rclass, enum machine_mode mode)
|
| 7333 |
|
|
{
|
| 7334 |
|
|
switch (rclass)
|
| 7335 |
|
|
{
|
| 7336 |
|
|
case FP_REGS:
|
| 7337 |
|
|
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
|
| 7338 |
|
|
return 2 * ((GET_MODE_SIZE (mode) / 2 + 8 - 1) / 8);
|
| 7339 |
|
|
else
|
| 7340 |
|
|
return (GET_MODE_SIZE (mode) + 8 - 1) / 8;
|
| 7341 |
|
|
case ACCESS_REGS:
|
| 7342 |
|
|
return (GET_MODE_SIZE (mode) + 4 - 1) / 4;
|
| 7343 |
|
|
default:
|
| 7344 |
|
|
break;
|
| 7345 |
|
|
}
|
| 7346 |
|
|
return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
|
| 7347 |
|
|
}
|
| 7348 |
|
|
|
| 7349 |
|
|
/* Return true if register FROM can be eliminated via register TO. */
|
| 7350 |
|
|
|
| 7351 |
|
|
static bool
|
| 7352 |
|
|
s390_can_eliminate (const int from, const int to)
|
| 7353 |
|
|
{
|
| 7354 |
|
|
/* On zSeries machines, we have not marked the base register as fixed.
|
| 7355 |
|
|
Instead, we have an elimination rule BASE_REGNUM -> BASE_REGNUM.
|
| 7356 |
|
|
If a function requires the base register, we say here that this
|
| 7357 |
|
|
elimination cannot be performed. This will cause reload to free
|
| 7358 |
|
|
up the base register (as if it were fixed). On the other hand,
|
| 7359 |
|
|
if the current function does *not* require the base register, we
|
| 7360 |
|
|
say here the elimination succeeds, which in turn allows reload
|
| 7361 |
|
|
to allocate the base register for any other purpose. */
|
| 7362 |
|
|
if (from == BASE_REGNUM && to == BASE_REGNUM)
|
| 7363 |
|
|
{
|
| 7364 |
|
|
if (TARGET_CPU_ZARCH)
|
| 7365 |
|
|
{
|
| 7366 |
|
|
s390_init_frame_layout ();
|
| 7367 |
|
|
return cfun->machine->base_reg == NULL_RTX;
|
| 7368 |
|
|
}
|
| 7369 |
|
|
|
| 7370 |
|
|
return false;
|
| 7371 |
|
|
}
|
| 7372 |
|
|
|
| 7373 |
|
|
/* Everything else must point into the stack frame. */
|
| 7374 |
|
|
gcc_assert (to == STACK_POINTER_REGNUM
|
| 7375 |
|
|
|| to == HARD_FRAME_POINTER_REGNUM);
|
| 7376 |
|
|
|
| 7377 |
|
|
gcc_assert (from == FRAME_POINTER_REGNUM
|
| 7378 |
|
|
|| from == ARG_POINTER_REGNUM
|
| 7379 |
|
|
|| from == RETURN_ADDRESS_POINTER_REGNUM);
|
| 7380 |
|
|
|
| 7381 |
|
|
/* Make sure we actually saved the return address. */
|
| 7382 |
|
|
if (from == RETURN_ADDRESS_POINTER_REGNUM)
|
| 7383 |
|
|
if (!crtl->calls_eh_return
|
| 7384 |
|
|
&& !cfun->stdarg
|
| 7385 |
|
|
&& !cfun_frame_layout.save_return_addr_p)
|
| 7386 |
|
|
return false;
|
| 7387 |
|
|
|
| 7388 |
|
|
return true;
|
| 7389 |
|
|
}
|
| 7390 |
|
|
|
| 7391 |
|
|
/* Return offset between register FROM and TO initially after prolog. */
|
| 7392 |
|
|
|
| 7393 |
|
|
HOST_WIDE_INT
|
| 7394 |
|
|
s390_initial_elimination_offset (int from, int to)
|
| 7395 |
|
|
{
|
| 7396 |
|
|
HOST_WIDE_INT offset;
|
| 7397 |
|
|
int index;
|
| 7398 |
|
|
|
| 7399 |
|
|
/* ??? Why are we called for non-eliminable pairs? */
|
| 7400 |
|
|
if (!s390_can_eliminate (from, to))
|
| 7401 |
|
|
return 0;
|
| 7402 |
|
|
|
| 7403 |
|
|
switch (from)
|
| 7404 |
|
|
{
|
| 7405 |
|
|
case FRAME_POINTER_REGNUM:
|
| 7406 |
|
|
offset = (get_frame_size()
|
| 7407 |
|
|
+ STACK_POINTER_OFFSET
|
| 7408 |
|
|
+ crtl->outgoing_args_size);
|
| 7409 |
|
|
break;
|
| 7410 |
|
|
|
| 7411 |
|
|
case ARG_POINTER_REGNUM:
|
| 7412 |
|
|
s390_init_frame_layout ();
|
| 7413 |
|
|
offset = cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
|
| 7414 |
|
|
break;
|
| 7415 |
|
|
|
| 7416 |
|
|
case RETURN_ADDRESS_POINTER_REGNUM:
|
| 7417 |
|
|
s390_init_frame_layout ();
|
| 7418 |
|
|
index = RETURN_REGNUM - cfun_frame_layout.first_save_gpr_slot;
|
| 7419 |
|
|
gcc_assert (index >= 0);
|
| 7420 |
|
|
offset = cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset;
|
| 7421 |
|
|
offset += index * UNITS_PER_WORD;
|
| 7422 |
|
|
break;
|
| 7423 |
|
|
|
| 7424 |
|
|
case BASE_REGNUM:
|
| 7425 |
|
|
offset = 0;
|
| 7426 |
|
|
break;
|
| 7427 |
|
|
|
| 7428 |
|
|
default:
|
| 7429 |
|
|
gcc_unreachable ();
|
| 7430 |
|
|
}
|
| 7431 |
|
|
|
| 7432 |
|
|
return offset;
|
| 7433 |
|
|
}
|
| 7434 |
|
|
|
| 7435 |
|
|
/* Emit insn to save fpr REGNUM at offset OFFSET relative
|
| 7436 |
|
|
to register BASE. Return generated insn. */
|
| 7437 |
|
|
|
| 7438 |
|
|
static rtx
|
| 7439 |
|
|
save_fpr (rtx base, int offset, int regnum)
|
| 7440 |
|
|
{
|
| 7441 |
|
|
rtx addr;
|
| 7442 |
|
|
addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
|
| 7443 |
|
|
|
| 7444 |
|
|
if (regnum >= 16 && regnum <= (16 + FP_ARG_NUM_REG))
|
| 7445 |
|
|
set_mem_alias_set (addr, get_varargs_alias_set ());
|
| 7446 |
|
|
else
|
| 7447 |
|
|
set_mem_alias_set (addr, get_frame_alias_set ());
|
| 7448 |
|
|
|
| 7449 |
|
|
return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum));
|
| 7450 |
|
|
}
|
| 7451 |
|
|
|
| 7452 |
|
|
/* Emit insn to restore fpr REGNUM from offset OFFSET relative
|
| 7453 |
|
|
to register BASE. Return generated insn. */
|
| 7454 |
|
|
|
| 7455 |
|
|
static rtx
|
| 7456 |
|
|
restore_fpr (rtx base, int offset, int regnum)
|
| 7457 |
|
|
{
|
| 7458 |
|
|
rtx addr;
|
| 7459 |
|
|
addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
|
| 7460 |
|
|
set_mem_alias_set (addr, get_frame_alias_set ());
|
| 7461 |
|
|
|
| 7462 |
|
|
return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr);
|
| 7463 |
|
|
}
|
| 7464 |
|
|
|
| 7465 |
|
|
/* Return true if REGNO is a global register, but not one
|
| 7466 |
|
|
of the special ones that need to be saved/restored in anyway. */
|
| 7467 |
|
|
|
| 7468 |
|
|
static inline bool
|
| 7469 |
|
|
global_not_special_regno_p (int regno)
|
| 7470 |
|
|
{
|
| 7471 |
|
|
return (global_regs[regno]
|
| 7472 |
|
|
/* These registers are special and need to be
|
| 7473 |
|
|
restored in any case. */
|
| 7474 |
|
|
&& !(regno == STACK_POINTER_REGNUM
|
| 7475 |
|
|
|| regno == RETURN_REGNUM
|
| 7476 |
|
|
|| regno == BASE_REGNUM
|
| 7477 |
|
|
|| (flag_pic && regno == (int)PIC_OFFSET_TABLE_REGNUM)));
|
| 7478 |
|
|
}
|
| 7479 |
|
|
|
| 7480 |
|
|
/* Generate insn to save registers FIRST to LAST into
|
| 7481 |
|
|
the register save area located at offset OFFSET
|
| 7482 |
|
|
relative to register BASE. */
|
| 7483 |
|
|
|
| 7484 |
|
|
static rtx
|
| 7485 |
|
|
save_gprs (rtx base, int offset, int first, int last)
|
| 7486 |
|
|
{
|
| 7487 |
|
|
rtx addr, insn, note;
|
| 7488 |
|
|
int i;
|
| 7489 |
|
|
|
| 7490 |
|
|
addr = plus_constant (base, offset);
|
| 7491 |
|
|
addr = gen_rtx_MEM (Pmode, addr);
|
| 7492 |
|
|
|
| 7493 |
|
|
set_mem_alias_set (addr, get_frame_alias_set ());
|
| 7494 |
|
|
|
| 7495 |
|
|
/* Special-case single register. */
|
| 7496 |
|
|
if (first == last)
|
| 7497 |
|
|
{
|
| 7498 |
|
|
if (TARGET_64BIT)
|
| 7499 |
|
|
insn = gen_movdi (addr, gen_rtx_REG (Pmode, first));
|
| 7500 |
|
|
else
|
| 7501 |
|
|
insn = gen_movsi (addr, gen_rtx_REG (Pmode, first));
|
| 7502 |
|
|
|
| 7503 |
|
|
if (!global_not_special_regno_p (first))
|
| 7504 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7505 |
|
|
return insn;
|
| 7506 |
|
|
}
|
| 7507 |
|
|
|
| 7508 |
|
|
|
| 7509 |
|
|
insn = gen_store_multiple (addr,
|
| 7510 |
|
|
gen_rtx_REG (Pmode, first),
|
| 7511 |
|
|
GEN_INT (last - first + 1));
|
| 7512 |
|
|
|
| 7513 |
|
|
if (first <= 6 && cfun->stdarg)
|
| 7514 |
|
|
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
|
| 7515 |
|
|
{
|
| 7516 |
|
|
rtx mem = XEXP (XVECEXP (PATTERN (insn), 0, i), 0);
|
| 7517 |
|
|
|
| 7518 |
|
|
if (first + i <= 6)
|
| 7519 |
|
|
set_mem_alias_set (mem, get_varargs_alias_set ());
|
| 7520 |
|
|
}
|
| 7521 |
|
|
|
| 7522 |
|
|
/* We need to set the FRAME_RELATED flag on all SETs
|
| 7523 |
|
|
inside the store-multiple pattern.
|
| 7524 |
|
|
|
| 7525 |
|
|
However, we must not emit DWARF records for registers 2..5
|
| 7526 |
|
|
if they are stored for use by variable arguments ...
|
| 7527 |
|
|
|
| 7528 |
|
|
??? Unfortunately, it is not enough to simply not the
|
| 7529 |
|
|
FRAME_RELATED flags for those SETs, because the first SET
|
| 7530 |
|
|
of the PARALLEL is always treated as if it had the flag
|
| 7531 |
|
|
set, even if it does not. Therefore we emit a new pattern
|
| 7532 |
|
|
without those registers as REG_FRAME_RELATED_EXPR note. */
|
| 7533 |
|
|
|
| 7534 |
|
|
if (first >= 6 && !global_not_special_regno_p (first))
|
| 7535 |
|
|
{
|
| 7536 |
|
|
rtx pat = PATTERN (insn);
|
| 7537 |
|
|
|
| 7538 |
|
|
for (i = 0; i < XVECLEN (pat, 0); i++)
|
| 7539 |
|
|
if (GET_CODE (XVECEXP (pat, 0, i)) == SET
|
| 7540 |
|
|
&& !global_not_special_regno_p (REGNO (SET_SRC (XVECEXP (pat,
|
| 7541 |
|
|
0, i)))))
|
| 7542 |
|
|
RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
|
| 7543 |
|
|
|
| 7544 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7545 |
|
|
}
|
| 7546 |
|
|
else if (last >= 6)
|
| 7547 |
|
|
{
|
| 7548 |
|
|
int start;
|
| 7549 |
|
|
|
| 7550 |
|
|
for (start = first >= 6 ? first : 6; start <= last; start++)
|
| 7551 |
|
|
if (!global_not_special_regno_p (start))
|
| 7552 |
|
|
break;
|
| 7553 |
|
|
|
| 7554 |
|
|
if (start > last)
|
| 7555 |
|
|
return insn;
|
| 7556 |
|
|
|
| 7557 |
|
|
addr = plus_constant (base, offset + (start - first) * UNITS_PER_WORD);
|
| 7558 |
|
|
note = gen_store_multiple (gen_rtx_MEM (Pmode, addr),
|
| 7559 |
|
|
gen_rtx_REG (Pmode, start),
|
| 7560 |
|
|
GEN_INT (last - start + 1));
|
| 7561 |
|
|
note = PATTERN (note);
|
| 7562 |
|
|
|
| 7563 |
|
|
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
|
| 7564 |
|
|
|
| 7565 |
|
|
for (i = 0; i < XVECLEN (note, 0); i++)
|
| 7566 |
|
|
if (GET_CODE (XVECEXP (note, 0, i)) == SET
|
| 7567 |
|
|
&& !global_not_special_regno_p (REGNO (SET_SRC (XVECEXP (note,
|
| 7568 |
|
|
0, i)))))
|
| 7569 |
|
|
RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1;
|
| 7570 |
|
|
|
| 7571 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7572 |
|
|
}
|
| 7573 |
|
|
|
| 7574 |
|
|
return insn;
|
| 7575 |
|
|
}
|
| 7576 |
|
|
|
| 7577 |
|
|
/* Generate insn to restore registers FIRST to LAST from
|
| 7578 |
|
|
the register save area located at offset OFFSET
|
| 7579 |
|
|
relative to register BASE. */
|
| 7580 |
|
|
|
| 7581 |
|
|
static rtx
|
| 7582 |
|
|
restore_gprs (rtx base, int offset, int first, int last)
|
| 7583 |
|
|
{
|
| 7584 |
|
|
rtx addr, insn;
|
| 7585 |
|
|
|
| 7586 |
|
|
addr = plus_constant (base, offset);
|
| 7587 |
|
|
addr = gen_rtx_MEM (Pmode, addr);
|
| 7588 |
|
|
set_mem_alias_set (addr, get_frame_alias_set ());
|
| 7589 |
|
|
|
| 7590 |
|
|
/* Special-case single register. */
|
| 7591 |
|
|
if (first == last)
|
| 7592 |
|
|
{
|
| 7593 |
|
|
if (TARGET_64BIT)
|
| 7594 |
|
|
insn = gen_movdi (gen_rtx_REG (Pmode, first), addr);
|
| 7595 |
|
|
else
|
| 7596 |
|
|
insn = gen_movsi (gen_rtx_REG (Pmode, first), addr);
|
| 7597 |
|
|
|
| 7598 |
|
|
return insn;
|
| 7599 |
|
|
}
|
| 7600 |
|
|
|
| 7601 |
|
|
insn = gen_load_multiple (gen_rtx_REG (Pmode, first),
|
| 7602 |
|
|
addr,
|
| 7603 |
|
|
GEN_INT (last - first + 1));
|
| 7604 |
|
|
return insn;
|
| 7605 |
|
|
}
|
| 7606 |
|
|
|
| 7607 |
|
|
/* Return insn sequence to load the GOT register. */
|
| 7608 |
|
|
|
| 7609 |
|
|
static GTY(()) rtx got_symbol;
|
| 7610 |
|
|
rtx
|
| 7611 |
|
|
s390_load_got (void)
|
| 7612 |
|
|
{
|
| 7613 |
|
|
rtx insns;
|
| 7614 |
|
|
|
| 7615 |
|
|
if (!got_symbol)
|
| 7616 |
|
|
{
|
| 7617 |
|
|
got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
|
| 7618 |
|
|
SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL;
|
| 7619 |
|
|
}
|
| 7620 |
|
|
|
| 7621 |
|
|
start_sequence ();
|
| 7622 |
|
|
|
| 7623 |
|
|
if (TARGET_CPU_ZARCH)
|
| 7624 |
|
|
{
|
| 7625 |
|
|
emit_move_insn (pic_offset_table_rtx, got_symbol);
|
| 7626 |
|
|
}
|
| 7627 |
|
|
else
|
| 7628 |
|
|
{
|
| 7629 |
|
|
rtx offset;
|
| 7630 |
|
|
|
| 7631 |
|
|
offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol),
|
| 7632 |
|
|
UNSPEC_LTREL_OFFSET);
|
| 7633 |
|
|
offset = gen_rtx_CONST (Pmode, offset);
|
| 7634 |
|
|
offset = force_const_mem (Pmode, offset);
|
| 7635 |
|
|
|
| 7636 |
|
|
emit_move_insn (pic_offset_table_rtx, offset);
|
| 7637 |
|
|
|
| 7638 |
|
|
offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)),
|
| 7639 |
|
|
UNSPEC_LTREL_BASE);
|
| 7640 |
|
|
offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset);
|
| 7641 |
|
|
|
| 7642 |
|
|
emit_move_insn (pic_offset_table_rtx, offset);
|
| 7643 |
|
|
}
|
| 7644 |
|
|
|
| 7645 |
|
|
insns = get_insns ();
|
| 7646 |
|
|
end_sequence ();
|
| 7647 |
|
|
return insns;
|
| 7648 |
|
|
}
|
| 7649 |
|
|
|
| 7650 |
|
|
/* This ties together stack memory (MEM with an alias set of frame_alias_set)
|
| 7651 |
|
|
and the change to the stack pointer. */
|
| 7652 |
|
|
|
| 7653 |
|
|
static void
|
| 7654 |
|
|
s390_emit_stack_tie (void)
|
| 7655 |
|
|
{
|
| 7656 |
|
|
rtx mem = gen_frame_mem (BLKmode,
|
| 7657 |
|
|
gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
|
| 7658 |
|
|
|
| 7659 |
|
|
emit_insn (gen_stack_tie (mem));
|
| 7660 |
|
|
}
|
| 7661 |
|
|
|
| 7662 |
|
|
/* Expand the prologue into a bunch of separate insns. */
|
| 7663 |
|
|
|
| 7664 |
|
|
void
|
| 7665 |
|
|
s390_emit_prologue (void)
|
| 7666 |
|
|
{
|
| 7667 |
|
|
rtx insn, addr;
|
| 7668 |
|
|
rtx temp_reg;
|
| 7669 |
|
|
int i;
|
| 7670 |
|
|
int offset;
|
| 7671 |
|
|
int next_fpr = 0;
|
| 7672 |
|
|
|
| 7673 |
|
|
/* Complete frame layout. */
|
| 7674 |
|
|
|
| 7675 |
|
|
s390_update_frame_layout ();
|
| 7676 |
|
|
|
| 7677 |
|
|
/* Annotate all constant pool references to let the scheduler know
|
| 7678 |
|
|
they implicitly use the base register. */
|
| 7679 |
|
|
|
| 7680 |
|
|
push_topmost_sequence ();
|
| 7681 |
|
|
|
| 7682 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 7683 |
|
|
if (INSN_P (insn))
|
| 7684 |
|
|
{
|
| 7685 |
|
|
annotate_constant_pool_refs (&PATTERN (insn));
|
| 7686 |
|
|
df_insn_rescan (insn);
|
| 7687 |
|
|
}
|
| 7688 |
|
|
|
| 7689 |
|
|
pop_topmost_sequence ();
|
| 7690 |
|
|
|
| 7691 |
|
|
/* Choose best register to use for temp use within prologue.
|
| 7692 |
|
|
See below for why TPF must use the register 1. */
|
| 7693 |
|
|
|
| 7694 |
|
|
if (!has_hard_reg_initial_val (Pmode, RETURN_REGNUM)
|
| 7695 |
|
|
&& !current_function_is_leaf
|
| 7696 |
|
|
&& !TARGET_TPF_PROFILING)
|
| 7697 |
|
|
temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
|
| 7698 |
|
|
else
|
| 7699 |
|
|
temp_reg = gen_rtx_REG (Pmode, 1);
|
| 7700 |
|
|
|
| 7701 |
|
|
/* Save call saved gprs. */
|
| 7702 |
|
|
if (cfun_frame_layout.first_save_gpr != -1)
|
| 7703 |
|
|
{
|
| 7704 |
|
|
insn = save_gprs (stack_pointer_rtx,
|
| 7705 |
|
|
cfun_frame_layout.gprs_offset +
|
| 7706 |
|
|
UNITS_PER_WORD * (cfun_frame_layout.first_save_gpr
|
| 7707 |
|
|
- cfun_frame_layout.first_save_gpr_slot),
|
| 7708 |
|
|
cfun_frame_layout.first_save_gpr,
|
| 7709 |
|
|
cfun_frame_layout.last_save_gpr);
|
| 7710 |
|
|
emit_insn (insn);
|
| 7711 |
|
|
}
|
| 7712 |
|
|
|
| 7713 |
|
|
/* Dummy insn to mark literal pool slot. */
|
| 7714 |
|
|
|
| 7715 |
|
|
if (cfun->machine->base_reg)
|
| 7716 |
|
|
emit_insn (gen_main_pool (cfun->machine->base_reg));
|
| 7717 |
|
|
|
| 7718 |
|
|
offset = cfun_frame_layout.f0_offset;
|
| 7719 |
|
|
|
| 7720 |
|
|
/* Save f0 and f2. */
|
| 7721 |
|
|
for (i = 0; i < 2; i++)
|
| 7722 |
|
|
{
|
| 7723 |
|
|
if (cfun_fpr_bit_p (i))
|
| 7724 |
|
|
{
|
| 7725 |
|
|
save_fpr (stack_pointer_rtx, offset, i + 16);
|
| 7726 |
|
|
offset += 8;
|
| 7727 |
|
|
}
|
| 7728 |
|
|
else if (!TARGET_PACKED_STACK)
|
| 7729 |
|
|
offset += 8;
|
| 7730 |
|
|
}
|
| 7731 |
|
|
|
| 7732 |
|
|
/* Save f4 and f6. */
|
| 7733 |
|
|
offset = cfun_frame_layout.f4_offset;
|
| 7734 |
|
|
for (i = 2; i < 4; i++)
|
| 7735 |
|
|
{
|
| 7736 |
|
|
if (cfun_fpr_bit_p (i))
|
| 7737 |
|
|
{
|
| 7738 |
|
|
insn = save_fpr (stack_pointer_rtx, offset, i + 16);
|
| 7739 |
|
|
offset += 8;
|
| 7740 |
|
|
|
| 7741 |
|
|
/* If f4 and f6 are call clobbered they are saved due to stdargs and
|
| 7742 |
|
|
therefore are not frame related. */
|
| 7743 |
|
|
if (!call_really_used_regs[i + 16])
|
| 7744 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7745 |
|
|
}
|
| 7746 |
|
|
else if (!TARGET_PACKED_STACK)
|
| 7747 |
|
|
offset += 8;
|
| 7748 |
|
|
}
|
| 7749 |
|
|
|
| 7750 |
|
|
if (TARGET_PACKED_STACK
|
| 7751 |
|
|
&& cfun_save_high_fprs_p
|
| 7752 |
|
|
&& cfun_frame_layout.f8_offset + cfun_frame_layout.high_fprs * 8 > 0)
|
| 7753 |
|
|
{
|
| 7754 |
|
|
offset = (cfun_frame_layout.f8_offset
|
| 7755 |
|
|
+ (cfun_frame_layout.high_fprs - 1) * 8);
|
| 7756 |
|
|
|
| 7757 |
|
|
for (i = 15; i > 7 && offset >= 0; i--)
|
| 7758 |
|
|
if (cfun_fpr_bit_p (i))
|
| 7759 |
|
|
{
|
| 7760 |
|
|
insn = save_fpr (stack_pointer_rtx, offset, i + 16);
|
| 7761 |
|
|
|
| 7762 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7763 |
|
|
offset -= 8;
|
| 7764 |
|
|
}
|
| 7765 |
|
|
if (offset >= cfun_frame_layout.f8_offset)
|
| 7766 |
|
|
next_fpr = i + 16;
|
| 7767 |
|
|
}
|
| 7768 |
|
|
|
| 7769 |
|
|
if (!TARGET_PACKED_STACK)
|
| 7770 |
|
|
next_fpr = cfun_save_high_fprs_p ? 31 : 0;
|
| 7771 |
|
|
|
| 7772 |
|
|
/* Decrement stack pointer. */
|
| 7773 |
|
|
|
| 7774 |
|
|
if (cfun_frame_layout.frame_size > 0)
|
| 7775 |
|
|
{
|
| 7776 |
|
|
rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size);
|
| 7777 |
|
|
rtx real_frame_off;
|
| 7778 |
|
|
|
| 7779 |
|
|
if (s390_stack_size)
|
| 7780 |
|
|
{
|
| 7781 |
|
|
HOST_WIDE_INT stack_guard;
|
| 7782 |
|
|
|
| 7783 |
|
|
if (s390_stack_guard)
|
| 7784 |
|
|
stack_guard = s390_stack_guard;
|
| 7785 |
|
|
else
|
| 7786 |
|
|
{
|
| 7787 |
|
|
/* If no value for stack guard is provided the smallest power of 2
|
| 7788 |
|
|
larger than the current frame size is chosen. */
|
| 7789 |
|
|
stack_guard = 1;
|
| 7790 |
|
|
while (stack_guard < cfun_frame_layout.frame_size)
|
| 7791 |
|
|
stack_guard <<= 1;
|
| 7792 |
|
|
}
|
| 7793 |
|
|
|
| 7794 |
|
|
if (cfun_frame_layout.frame_size >= s390_stack_size)
|
| 7795 |
|
|
{
|
| 7796 |
|
|
warning (0, "frame size of function %qs is "
|
| 7797 |
|
|
HOST_WIDE_INT_PRINT_DEC
|
| 7798 |
|
|
" bytes exceeding user provided stack limit of "
|
| 7799 |
|
|
HOST_WIDE_INT_PRINT_DEC " bytes. "
|
| 7800 |
|
|
"An unconditional trap is added.",
|
| 7801 |
|
|
current_function_name(), cfun_frame_layout.frame_size,
|
| 7802 |
|
|
s390_stack_size);
|
| 7803 |
|
|
emit_insn (gen_trap ());
|
| 7804 |
|
|
}
|
| 7805 |
|
|
else
|
| 7806 |
|
|
{
|
| 7807 |
|
|
/* stack_guard has to be smaller than s390_stack_size.
|
| 7808 |
|
|
Otherwise we would emit an AND with zero which would
|
| 7809 |
|
|
not match the test under mask pattern. */
|
| 7810 |
|
|
if (stack_guard >= s390_stack_size)
|
| 7811 |
|
|
{
|
| 7812 |
|
|
warning (0, "frame size of function %qs is "
|
| 7813 |
|
|
HOST_WIDE_INT_PRINT_DEC
|
| 7814 |
|
|
" bytes which is more than half the stack size. "
|
| 7815 |
|
|
"The dynamic check would not be reliable. "
|
| 7816 |
|
|
"No check emitted for this function.",
|
| 7817 |
|
|
current_function_name(),
|
| 7818 |
|
|
cfun_frame_layout.frame_size);
|
| 7819 |
|
|
}
|
| 7820 |
|
|
else
|
| 7821 |
|
|
{
|
| 7822 |
|
|
HOST_WIDE_INT stack_check_mask = ((s390_stack_size - 1)
|
| 7823 |
|
|
& ~(stack_guard - 1));
|
| 7824 |
|
|
|
| 7825 |
|
|
rtx t = gen_rtx_AND (Pmode, stack_pointer_rtx,
|
| 7826 |
|
|
GEN_INT (stack_check_mask));
|
| 7827 |
|
|
if (TARGET_64BIT)
|
| 7828 |
|
|
emit_insn (gen_ctrapdi4 (gen_rtx_EQ (VOIDmode,
|
| 7829 |
|
|
t, const0_rtx),
|
| 7830 |
|
|
t, const0_rtx, const0_rtx));
|
| 7831 |
|
|
else
|
| 7832 |
|
|
emit_insn (gen_ctrapsi4 (gen_rtx_EQ (VOIDmode,
|
| 7833 |
|
|
t, const0_rtx),
|
| 7834 |
|
|
t, const0_rtx, const0_rtx));
|
| 7835 |
|
|
}
|
| 7836 |
|
|
}
|
| 7837 |
|
|
}
|
| 7838 |
|
|
|
| 7839 |
|
|
if (s390_warn_framesize > 0
|
| 7840 |
|
|
&& cfun_frame_layout.frame_size >= s390_warn_framesize)
|
| 7841 |
|
|
warning (0, "frame size of %qs is " HOST_WIDE_INT_PRINT_DEC " bytes",
|
| 7842 |
|
|
current_function_name (), cfun_frame_layout.frame_size);
|
| 7843 |
|
|
|
| 7844 |
|
|
if (s390_warn_dynamicstack_p && cfun->calls_alloca)
|
| 7845 |
|
|
warning (0, "%qs uses dynamic stack allocation", current_function_name ());
|
| 7846 |
|
|
|
| 7847 |
|
|
/* Save incoming stack pointer into temp reg. */
|
| 7848 |
|
|
if (TARGET_BACKCHAIN || next_fpr)
|
| 7849 |
|
|
insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
|
| 7850 |
|
|
|
| 7851 |
|
|
/* Subtract frame size from stack pointer. */
|
| 7852 |
|
|
|
| 7853 |
|
|
if (DISP_IN_RANGE (INTVAL (frame_off)))
|
| 7854 |
|
|
{
|
| 7855 |
|
|
insn = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
|
| 7856 |
|
|
gen_rtx_PLUS (Pmode, stack_pointer_rtx,
|
| 7857 |
|
|
frame_off));
|
| 7858 |
|
|
insn = emit_insn (insn);
|
| 7859 |
|
|
}
|
| 7860 |
|
|
else
|
| 7861 |
|
|
{
|
| 7862 |
|
|
if (!CONST_OK_FOR_K (INTVAL (frame_off)))
|
| 7863 |
|
|
frame_off = force_const_mem (Pmode, frame_off);
|
| 7864 |
|
|
|
| 7865 |
|
|
insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
|
| 7866 |
|
|
annotate_constant_pool_refs (&PATTERN (insn));
|
| 7867 |
|
|
}
|
| 7868 |
|
|
|
| 7869 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7870 |
|
|
real_frame_off = GEN_INT (-cfun_frame_layout.frame_size);
|
| 7871 |
|
|
add_reg_note (insn, REG_FRAME_RELATED_EXPR,
|
| 7872 |
|
|
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
|
| 7873 |
|
|
gen_rtx_PLUS (Pmode, stack_pointer_rtx,
|
| 7874 |
|
|
real_frame_off)));
|
| 7875 |
|
|
|
| 7876 |
|
|
/* Set backchain. */
|
| 7877 |
|
|
|
| 7878 |
|
|
if (TARGET_BACKCHAIN)
|
| 7879 |
|
|
{
|
| 7880 |
|
|
if (cfun_frame_layout.backchain_offset)
|
| 7881 |
|
|
addr = gen_rtx_MEM (Pmode,
|
| 7882 |
|
|
plus_constant (stack_pointer_rtx,
|
| 7883 |
|
|
cfun_frame_layout.backchain_offset));
|
| 7884 |
|
|
else
|
| 7885 |
|
|
addr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
|
| 7886 |
|
|
set_mem_alias_set (addr, get_frame_alias_set ());
|
| 7887 |
|
|
insn = emit_insn (gen_move_insn (addr, temp_reg));
|
| 7888 |
|
|
}
|
| 7889 |
|
|
|
| 7890 |
|
|
/* If we support asynchronous exceptions (e.g. for Java),
|
| 7891 |
|
|
we need to make sure the backchain pointer is set up
|
| 7892 |
|
|
before any possibly trapping memory access. */
|
| 7893 |
|
|
|
| 7894 |
|
|
if (TARGET_BACKCHAIN && flag_non_call_exceptions)
|
| 7895 |
|
|
{
|
| 7896 |
|
|
addr = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode));
|
| 7897 |
|
|
emit_clobber (addr);
|
| 7898 |
|
|
}
|
| 7899 |
|
|
}
|
| 7900 |
|
|
|
| 7901 |
|
|
/* Save fprs 8 - 15 (64 bit ABI). */
|
| 7902 |
|
|
|
| 7903 |
|
|
if (cfun_save_high_fprs_p && next_fpr)
|
| 7904 |
|
|
{
|
| 7905 |
|
|
/* If the stack might be accessed through a different register
|
| 7906 |
|
|
we have to make sure that the stack pointer decrement is not
|
| 7907 |
|
|
moved below the use of the stack slots. */
|
| 7908 |
|
|
s390_emit_stack_tie ();
|
| 7909 |
|
|
|
| 7910 |
|
|
insn = emit_insn (gen_add2_insn (temp_reg,
|
| 7911 |
|
|
GEN_INT (cfun_frame_layout.f8_offset)));
|
| 7912 |
|
|
|
| 7913 |
|
|
offset = 0;
|
| 7914 |
|
|
|
| 7915 |
|
|
for (i = 24; i <= next_fpr; i++)
|
| 7916 |
|
|
if (cfun_fpr_bit_p (i - 16))
|
| 7917 |
|
|
{
|
| 7918 |
|
|
rtx addr = plus_constant (stack_pointer_rtx,
|
| 7919 |
|
|
cfun_frame_layout.frame_size
|
| 7920 |
|
|
+ cfun_frame_layout.f8_offset
|
| 7921 |
|
|
+ offset);
|
| 7922 |
|
|
|
| 7923 |
|
|
insn = save_fpr (temp_reg, offset, i);
|
| 7924 |
|
|
offset += 8;
|
| 7925 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7926 |
|
|
add_reg_note (insn, REG_FRAME_RELATED_EXPR,
|
| 7927 |
|
|
gen_rtx_SET (VOIDmode,
|
| 7928 |
|
|
gen_rtx_MEM (DFmode, addr),
|
| 7929 |
|
|
gen_rtx_REG (DFmode, i)));
|
| 7930 |
|
|
}
|
| 7931 |
|
|
}
|
| 7932 |
|
|
|
| 7933 |
|
|
/* Set frame pointer, if needed. */
|
| 7934 |
|
|
|
| 7935 |
|
|
if (frame_pointer_needed)
|
| 7936 |
|
|
{
|
| 7937 |
|
|
insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
|
| 7938 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 7939 |
|
|
}
|
| 7940 |
|
|
|
| 7941 |
|
|
/* Set up got pointer, if needed. */
|
| 7942 |
|
|
|
| 7943 |
|
|
if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
|
| 7944 |
|
|
{
|
| 7945 |
|
|
rtx insns = s390_load_got ();
|
| 7946 |
|
|
|
| 7947 |
|
|
for (insn = insns; insn; insn = NEXT_INSN (insn))
|
| 7948 |
|
|
annotate_constant_pool_refs (&PATTERN (insn));
|
| 7949 |
|
|
|
| 7950 |
|
|
emit_insn (insns);
|
| 7951 |
|
|
}
|
| 7952 |
|
|
|
| 7953 |
|
|
if (TARGET_TPF_PROFILING)
|
| 7954 |
|
|
{
|
| 7955 |
|
|
/* Generate a BAS instruction to serve as a function
|
| 7956 |
|
|
entry intercept to facilitate the use of tracing
|
| 7957 |
|
|
algorithms located at the branch target. */
|
| 7958 |
|
|
emit_insn (gen_prologue_tpf ());
|
| 7959 |
|
|
|
| 7960 |
|
|
/* Emit a blockage here so that all code
|
| 7961 |
|
|
lies between the profiling mechanisms. */
|
| 7962 |
|
|
emit_insn (gen_blockage ());
|
| 7963 |
|
|
}
|
| 7964 |
|
|
}
|
| 7965 |
|
|
|
| 7966 |
|
|
/* Expand the epilogue into a bunch of separate insns. */
|
| 7967 |
|
|
|
| 7968 |
|
|
void
|
| 7969 |
|
|
s390_emit_epilogue (bool sibcall)
|
| 7970 |
|
|
{
|
| 7971 |
|
|
rtx frame_pointer, return_reg, cfa_restores = NULL_RTX;
|
| 7972 |
|
|
int area_bottom, area_top, offset = 0;
|
| 7973 |
|
|
int next_offset;
|
| 7974 |
|
|
rtvec p;
|
| 7975 |
|
|
int i;
|
| 7976 |
|
|
|
| 7977 |
|
|
if (TARGET_TPF_PROFILING)
|
| 7978 |
|
|
{
|
| 7979 |
|
|
|
| 7980 |
|
|
/* Generate a BAS instruction to serve as a function
|
| 7981 |
|
|
entry intercept to facilitate the use of tracing
|
| 7982 |
|
|
algorithms located at the branch target. */
|
| 7983 |
|
|
|
| 7984 |
|
|
/* Emit a blockage here so that all code
|
| 7985 |
|
|
lies between the profiling mechanisms. */
|
| 7986 |
|
|
emit_insn (gen_blockage ());
|
| 7987 |
|
|
|
| 7988 |
|
|
emit_insn (gen_epilogue_tpf ());
|
| 7989 |
|
|
}
|
| 7990 |
|
|
|
| 7991 |
|
|
/* Check whether to use frame or stack pointer for restore. */
|
| 7992 |
|
|
|
| 7993 |
|
|
frame_pointer = (frame_pointer_needed
|
| 7994 |
|
|
? hard_frame_pointer_rtx : stack_pointer_rtx);
|
| 7995 |
|
|
|
| 7996 |
|
|
s390_frame_area (&area_bottom, &area_top);
|
| 7997 |
|
|
|
| 7998 |
|
|
/* Check whether we can access the register save area.
|
| 7999 |
|
|
If not, increment the frame pointer as required. */
|
| 8000 |
|
|
|
| 8001 |
|
|
if (area_top <= area_bottom)
|
| 8002 |
|
|
{
|
| 8003 |
|
|
/* Nothing to restore. */
|
| 8004 |
|
|
}
|
| 8005 |
|
|
else if (DISP_IN_RANGE (cfun_frame_layout.frame_size + area_bottom)
|
| 8006 |
|
|
&& DISP_IN_RANGE (cfun_frame_layout.frame_size + area_top - 1))
|
| 8007 |
|
|
{
|
| 8008 |
|
|
/* Area is in range. */
|
| 8009 |
|
|
offset = cfun_frame_layout.frame_size;
|
| 8010 |
|
|
}
|
| 8011 |
|
|
else
|
| 8012 |
|
|
{
|
| 8013 |
|
|
rtx insn, frame_off, cfa;
|
| 8014 |
|
|
|
| 8015 |
|
|
offset = area_bottom < 0 ? -area_bottom : 0;
|
| 8016 |
|
|
frame_off = GEN_INT (cfun_frame_layout.frame_size - offset);
|
| 8017 |
|
|
|
| 8018 |
|
|
cfa = gen_rtx_SET (VOIDmode, frame_pointer,
|
| 8019 |
|
|
gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
|
| 8020 |
|
|
if (DISP_IN_RANGE (INTVAL (frame_off)))
|
| 8021 |
|
|
{
|
| 8022 |
|
|
insn = gen_rtx_SET (VOIDmode, frame_pointer,
|
| 8023 |
|
|
gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
|
| 8024 |
|
|
insn = emit_insn (insn);
|
| 8025 |
|
|
}
|
| 8026 |
|
|
else
|
| 8027 |
|
|
{
|
| 8028 |
|
|
if (!CONST_OK_FOR_K (INTVAL (frame_off)))
|
| 8029 |
|
|
frame_off = force_const_mem (Pmode, frame_off);
|
| 8030 |
|
|
|
| 8031 |
|
|
insn = emit_insn (gen_add2_insn (frame_pointer, frame_off));
|
| 8032 |
|
|
annotate_constant_pool_refs (&PATTERN (insn));
|
| 8033 |
|
|
}
|
| 8034 |
|
|
add_reg_note (insn, REG_CFA_ADJUST_CFA, cfa);
|
| 8035 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 8036 |
|
|
}
|
| 8037 |
|
|
|
| 8038 |
|
|
/* Restore call saved fprs. */
|
| 8039 |
|
|
|
| 8040 |
|
|
if (TARGET_64BIT)
|
| 8041 |
|
|
{
|
| 8042 |
|
|
if (cfun_save_high_fprs_p)
|
| 8043 |
|
|
{
|
| 8044 |
|
|
next_offset = cfun_frame_layout.f8_offset;
|
| 8045 |
|
|
for (i = 24; i < 32; i++)
|
| 8046 |
|
|
{
|
| 8047 |
|
|
if (cfun_fpr_bit_p (i - 16))
|
| 8048 |
|
|
{
|
| 8049 |
|
|
restore_fpr (frame_pointer,
|
| 8050 |
|
|
offset + next_offset, i);
|
| 8051 |
|
|
cfa_restores
|
| 8052 |
|
|
= alloc_reg_note (REG_CFA_RESTORE,
|
| 8053 |
|
|
gen_rtx_REG (DFmode, i), cfa_restores);
|
| 8054 |
|
|
next_offset += 8;
|
| 8055 |
|
|
}
|
| 8056 |
|
|
}
|
| 8057 |
|
|
}
|
| 8058 |
|
|
|
| 8059 |
|
|
}
|
| 8060 |
|
|
else
|
| 8061 |
|
|
{
|
| 8062 |
|
|
next_offset = cfun_frame_layout.f4_offset;
|
| 8063 |
|
|
for (i = 18; i < 20; i++)
|
| 8064 |
|
|
{
|
| 8065 |
|
|
if (cfun_fpr_bit_p (i - 16))
|
| 8066 |
|
|
{
|
| 8067 |
|
|
restore_fpr (frame_pointer,
|
| 8068 |
|
|
offset + next_offset, i);
|
| 8069 |
|
|
cfa_restores
|
| 8070 |
|
|
= alloc_reg_note (REG_CFA_RESTORE,
|
| 8071 |
|
|
gen_rtx_REG (DFmode, i), cfa_restores);
|
| 8072 |
|
|
next_offset += 8;
|
| 8073 |
|
|
}
|
| 8074 |
|
|
else if (!TARGET_PACKED_STACK)
|
| 8075 |
|
|
next_offset += 8;
|
| 8076 |
|
|
}
|
| 8077 |
|
|
|
| 8078 |
|
|
}
|
| 8079 |
|
|
|
| 8080 |
|
|
/* Return register. */
|
| 8081 |
|
|
|
| 8082 |
|
|
return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
|
| 8083 |
|
|
|
| 8084 |
|
|
/* Restore call saved gprs. */
|
| 8085 |
|
|
|
| 8086 |
|
|
if (cfun_frame_layout.first_restore_gpr != -1)
|
| 8087 |
|
|
{
|
| 8088 |
|
|
rtx insn, addr;
|
| 8089 |
|
|
int i;
|
| 8090 |
|
|
|
| 8091 |
|
|
/* Check for global register and save them
|
| 8092 |
|
|
to stack location from where they get restored. */
|
| 8093 |
|
|
|
| 8094 |
|
|
for (i = cfun_frame_layout.first_restore_gpr;
|
| 8095 |
|
|
i <= cfun_frame_layout.last_restore_gpr;
|
| 8096 |
|
|
i++)
|
| 8097 |
|
|
{
|
| 8098 |
|
|
if (global_not_special_regno_p (i))
|
| 8099 |
|
|
{
|
| 8100 |
|
|
addr = plus_constant (frame_pointer,
|
| 8101 |
|
|
offset + cfun_frame_layout.gprs_offset
|
| 8102 |
|
|
+ (i - cfun_frame_layout.first_save_gpr_slot)
|
| 8103 |
|
|
* UNITS_PER_WORD);
|
| 8104 |
|
|
addr = gen_rtx_MEM (Pmode, addr);
|
| 8105 |
|
|
set_mem_alias_set (addr, get_frame_alias_set ());
|
| 8106 |
|
|
emit_move_insn (addr, gen_rtx_REG (Pmode, i));
|
| 8107 |
|
|
}
|
| 8108 |
|
|
else
|
| 8109 |
|
|
cfa_restores
|
| 8110 |
|
|
= alloc_reg_note (REG_CFA_RESTORE,
|
| 8111 |
|
|
gen_rtx_REG (Pmode, i), cfa_restores);
|
| 8112 |
|
|
}
|
| 8113 |
|
|
|
| 8114 |
|
|
if (! sibcall)
|
| 8115 |
|
|
{
|
| 8116 |
|
|
/* Fetch return address from stack before load multiple,
|
| 8117 |
|
|
this will do good for scheduling. */
|
| 8118 |
|
|
|
| 8119 |
|
|
if (cfun_frame_layout.save_return_addr_p
|
| 8120 |
|
|
|| (cfun_frame_layout.first_restore_gpr < BASE_REGNUM
|
| 8121 |
|
|
&& cfun_frame_layout.last_restore_gpr > RETURN_REGNUM))
|
| 8122 |
|
|
{
|
| 8123 |
|
|
int return_regnum = find_unused_clobbered_reg();
|
| 8124 |
|
|
if (!return_regnum)
|
| 8125 |
|
|
return_regnum = 4;
|
| 8126 |
|
|
return_reg = gen_rtx_REG (Pmode, return_regnum);
|
| 8127 |
|
|
|
| 8128 |
|
|
addr = plus_constant (frame_pointer,
|
| 8129 |
|
|
offset + cfun_frame_layout.gprs_offset
|
| 8130 |
|
|
+ (RETURN_REGNUM
|
| 8131 |
|
|
- cfun_frame_layout.first_save_gpr_slot)
|
| 8132 |
|
|
* UNITS_PER_WORD);
|
| 8133 |
|
|
addr = gen_rtx_MEM (Pmode, addr);
|
| 8134 |
|
|
set_mem_alias_set (addr, get_frame_alias_set ());
|
| 8135 |
|
|
emit_move_insn (return_reg, addr);
|
| 8136 |
|
|
}
|
| 8137 |
|
|
}
|
| 8138 |
|
|
|
| 8139 |
|
|
insn = restore_gprs (frame_pointer,
|
| 8140 |
|
|
offset + cfun_frame_layout.gprs_offset
|
| 8141 |
|
|
+ (cfun_frame_layout.first_restore_gpr
|
| 8142 |
|
|
- cfun_frame_layout.first_save_gpr_slot)
|
| 8143 |
|
|
* UNITS_PER_WORD,
|
| 8144 |
|
|
cfun_frame_layout.first_restore_gpr,
|
| 8145 |
|
|
cfun_frame_layout.last_restore_gpr);
|
| 8146 |
|
|
insn = emit_insn (insn);
|
| 8147 |
|
|
REG_NOTES (insn) = cfa_restores;
|
| 8148 |
|
|
add_reg_note (insn, REG_CFA_DEF_CFA,
|
| 8149 |
|
|
plus_constant (stack_pointer_rtx, STACK_POINTER_OFFSET));
|
| 8150 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
| 8151 |
|
|
}
|
| 8152 |
|
|
|
| 8153 |
|
|
if (! sibcall)
|
| 8154 |
|
|
{
|
| 8155 |
|
|
|
| 8156 |
|
|
/* Return to caller. */
|
| 8157 |
|
|
|
| 8158 |
|
|
p = rtvec_alloc (2);
|
| 8159 |
|
|
|
| 8160 |
|
|
RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
|
| 8161 |
|
|
RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
|
| 8162 |
|
|
emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
|
| 8163 |
|
|
}
|
| 8164 |
|
|
}
|
| 8165 |
|
|
|
| 8166 |
|
|
|
| 8167 |
|
|
/* Return the size in bytes of a function argument of
|
| 8168 |
|
|
type TYPE and/or mode MODE. At least one of TYPE or
|
| 8169 |
|
|
MODE must be specified. */
|
| 8170 |
|
|
|
| 8171 |
|
|
static int
|
| 8172 |
|
|
s390_function_arg_size (enum machine_mode mode, const_tree type)
|
| 8173 |
|
|
{
|
| 8174 |
|
|
if (type)
|
| 8175 |
|
|
return int_size_in_bytes (type);
|
| 8176 |
|
|
|
| 8177 |
|
|
/* No type info available for some library calls ... */
|
| 8178 |
|
|
if (mode != BLKmode)
|
| 8179 |
|
|
return GET_MODE_SIZE (mode);
|
| 8180 |
|
|
|
| 8181 |
|
|
/* If we have neither type nor mode, abort */
|
| 8182 |
|
|
gcc_unreachable ();
|
| 8183 |
|
|
}
|
| 8184 |
|
|
|
| 8185 |
|
|
/* Return true if a function argument of type TYPE and mode MODE
|
| 8186 |
|
|
is to be passed in a floating-point register, if available. */
|
| 8187 |
|
|
|
| 8188 |
|
|
static bool
|
| 8189 |
|
|
s390_function_arg_float (enum machine_mode mode, tree type)
|
| 8190 |
|
|
{
|
| 8191 |
|
|
int size = s390_function_arg_size (mode, type);
|
| 8192 |
|
|
if (size > 8)
|
| 8193 |
|
|
return false;
|
| 8194 |
|
|
|
| 8195 |
|
|
/* Soft-float changes the ABI: no floating-point registers are used. */
|
| 8196 |
|
|
if (TARGET_SOFT_FLOAT)
|
| 8197 |
|
|
return false;
|
| 8198 |
|
|
|
| 8199 |
|
|
/* No type info available for some library calls ... */
|
| 8200 |
|
|
if (!type)
|
| 8201 |
|
|
return mode == SFmode || mode == DFmode || mode == SDmode || mode == DDmode;
|
| 8202 |
|
|
|
| 8203 |
|
|
/* The ABI says that record types with a single member are treated
|
| 8204 |
|
|
just like that member would be. */
|
| 8205 |
|
|
while (TREE_CODE (type) == RECORD_TYPE)
|
| 8206 |
|
|
{
|
| 8207 |
|
|
tree field, single = NULL_TREE;
|
| 8208 |
|
|
|
| 8209 |
|
|
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
|
| 8210 |
|
|
{
|
| 8211 |
|
|
if (TREE_CODE (field) != FIELD_DECL)
|
| 8212 |
|
|
continue;
|
| 8213 |
|
|
|
| 8214 |
|
|
if (single == NULL_TREE)
|
| 8215 |
|
|
single = TREE_TYPE (field);
|
| 8216 |
|
|
else
|
| 8217 |
|
|
return false;
|
| 8218 |
|
|
}
|
| 8219 |
|
|
|
| 8220 |
|
|
if (single == NULL_TREE)
|
| 8221 |
|
|
return false;
|
| 8222 |
|
|
else
|
| 8223 |
|
|
type = single;
|
| 8224 |
|
|
}
|
| 8225 |
|
|
|
| 8226 |
|
|
return TREE_CODE (type) == REAL_TYPE;
|
| 8227 |
|
|
}
|
| 8228 |
|
|
|
| 8229 |
|
|
/* Return true if a function argument of type TYPE and mode MODE
|
| 8230 |
|
|
is to be passed in an integer register, or a pair of integer
|
| 8231 |
|
|
registers, if available. */
|
| 8232 |
|
|
|
| 8233 |
|
|
static bool
|
| 8234 |
|
|
s390_function_arg_integer (enum machine_mode mode, tree type)
|
| 8235 |
|
|
{
|
| 8236 |
|
|
int size = s390_function_arg_size (mode, type);
|
| 8237 |
|
|
if (size > 8)
|
| 8238 |
|
|
return false;
|
| 8239 |
|
|
|
| 8240 |
|
|
/* No type info available for some library calls ... */
|
| 8241 |
|
|
if (!type)
|
| 8242 |
|
|
return GET_MODE_CLASS (mode) == MODE_INT
|
| 8243 |
|
|
|| (TARGET_SOFT_FLOAT && SCALAR_FLOAT_MODE_P (mode));
|
| 8244 |
|
|
|
| 8245 |
|
|
/* We accept small integral (and similar) types. */
|
| 8246 |
|
|
if (INTEGRAL_TYPE_P (type)
|
| 8247 |
|
|
|| POINTER_TYPE_P (type)
|
| 8248 |
|
|
|| TREE_CODE (type) == OFFSET_TYPE
|
| 8249 |
|
|
|| (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE))
|
| 8250 |
|
|
return true;
|
| 8251 |
|
|
|
| 8252 |
|
|
/* We also accept structs of size 1, 2, 4, 8 that are not
|
| 8253 |
|
|
passed in floating-point registers. */
|
| 8254 |
|
|
if (AGGREGATE_TYPE_P (type)
|
| 8255 |
|
|
&& exact_log2 (size) >= 0
|
| 8256 |
|
|
&& !s390_function_arg_float (mode, type))
|
| 8257 |
|
|
return true;
|
| 8258 |
|
|
|
| 8259 |
|
|
return false;
|
| 8260 |
|
|
}
|
| 8261 |
|
|
|
| 8262 |
|
|
/* Return 1 if a function argument of type TYPE and mode MODE
|
| 8263 |
|
|
is to be passed by reference. The ABI specifies that only
|
| 8264 |
|
|
structures of size 1, 2, 4, or 8 bytes are passed by value,
|
| 8265 |
|
|
all other structures (and complex numbers) are passed by
|
| 8266 |
|
|
reference. */
|
| 8267 |
|
|
|
| 8268 |
|
|
static bool
|
| 8269 |
|
|
s390_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
|
| 8270 |
|
|
enum machine_mode mode, const_tree type,
|
| 8271 |
|
|
bool named ATTRIBUTE_UNUSED)
|
| 8272 |
|
|
{
|
| 8273 |
|
|
int size = s390_function_arg_size (mode, type);
|
| 8274 |
|
|
if (size > 8)
|
| 8275 |
|
|
return true;
|
| 8276 |
|
|
|
| 8277 |
|
|
if (type)
|
| 8278 |
|
|
{
|
| 8279 |
|
|
if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0)
|
| 8280 |
|
|
return 1;
|
| 8281 |
|
|
|
| 8282 |
|
|
if (TREE_CODE (type) == COMPLEX_TYPE
|
| 8283 |
|
|
|| TREE_CODE (type) == VECTOR_TYPE)
|
| 8284 |
|
|
return 1;
|
| 8285 |
|
|
}
|
| 8286 |
|
|
|
| 8287 |
|
|
return 0;
|
| 8288 |
|
|
}
|
| 8289 |
|
|
|
| 8290 |
|
|
/* Update the data in CUM to advance over an argument of mode MODE and
|
| 8291 |
|
|
data type TYPE. (TYPE is null for libcalls where that information
|
| 8292 |
|
|
may not be available.). The boolean NAMED specifies whether the
|
| 8293 |
|
|
argument is a named argument (as opposed to an unnamed argument
|
| 8294 |
|
|
matching an ellipsis). */
|
| 8295 |
|
|
|
| 8296 |
|
|
void
|
| 8297 |
|
|
s390_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
| 8298 |
|
|
tree type, int named ATTRIBUTE_UNUSED)
|
| 8299 |
|
|
{
|
| 8300 |
|
|
if (s390_function_arg_float (mode, type))
|
| 8301 |
|
|
{
|
| 8302 |
|
|
cum->fprs += 1;
|
| 8303 |
|
|
}
|
| 8304 |
|
|
else if (s390_function_arg_integer (mode, type))
|
| 8305 |
|
|
{
|
| 8306 |
|
|
int size = s390_function_arg_size (mode, type);
|
| 8307 |
|
|
cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
|
| 8308 |
|
|
}
|
| 8309 |
|
|
else
|
| 8310 |
|
|
gcc_unreachable ();
|
| 8311 |
|
|
}
|
| 8312 |
|
|
|
| 8313 |
|
|
/* Define where to put the arguments to a function.
|
| 8314 |
|
|
Value is zero to push the argument on the stack,
|
| 8315 |
|
|
or a hard register in which to store the argument.
|
| 8316 |
|
|
|
| 8317 |
|
|
MODE is the argument's machine mode.
|
| 8318 |
|
|
TYPE is the data type of the argument (as a tree).
|
| 8319 |
|
|
This is null for libcalls where that information may
|
| 8320 |
|
|
not be available.
|
| 8321 |
|
|
CUM is a variable of type CUMULATIVE_ARGS which gives info about
|
| 8322 |
|
|
the preceding args and about the function being called.
|
| 8323 |
|
|
NAMED is nonzero if this argument is a named parameter
|
| 8324 |
|
|
(otherwise it is an extra parameter matching an ellipsis).
|
| 8325 |
|
|
|
| 8326 |
|
|
On S/390, we use general purpose registers 2 through 6 to
|
| 8327 |
|
|
pass integer, pointer, and certain structure arguments, and
|
| 8328 |
|
|
floating point registers 0 and 2 (0, 2, 4, and 6 on 64-bit)
|
| 8329 |
|
|
to pass floating point arguments. All remaining arguments
|
| 8330 |
|
|
are pushed to the stack. */
|
| 8331 |
|
|
|
| 8332 |
|
|
rtx
|
| 8333 |
|
|
s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
|
| 8334 |
|
|
int named ATTRIBUTE_UNUSED)
|
| 8335 |
|
|
{
|
| 8336 |
|
|
if (s390_function_arg_float (mode, type))
|
| 8337 |
|
|
{
|
| 8338 |
|
|
if (cum->fprs + 1 > FP_ARG_NUM_REG)
|
| 8339 |
|
|
return 0;
|
| 8340 |
|
|
else
|
| 8341 |
|
|
return gen_rtx_REG (mode, cum->fprs + 16);
|
| 8342 |
|
|
}
|
| 8343 |
|
|
else if (s390_function_arg_integer (mode, type))
|
| 8344 |
|
|
{
|
| 8345 |
|
|
int size = s390_function_arg_size (mode, type);
|
| 8346 |
|
|
int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD;
|
| 8347 |
|
|
|
| 8348 |
|
|
if (cum->gprs + n_gprs > GP_ARG_NUM_REG)
|
| 8349 |
|
|
return 0;
|
| 8350 |
|
|
else
|
| 8351 |
|
|
return gen_rtx_REG (mode, cum->gprs + 2);
|
| 8352 |
|
|
}
|
| 8353 |
|
|
|
| 8354 |
|
|
/* After the real arguments, expand_call calls us once again
|
| 8355 |
|
|
with a void_type_node type. Whatever we return here is
|
| 8356 |
|
|
passed as operand 2 to the call expanders.
|
| 8357 |
|
|
|
| 8358 |
|
|
We don't need this feature ... */
|
| 8359 |
|
|
else if (type == void_type_node)
|
| 8360 |
|
|
return const0_rtx;
|
| 8361 |
|
|
|
| 8362 |
|
|
gcc_unreachable ();
|
| 8363 |
|
|
}
|
| 8364 |
|
|
|
| 8365 |
|
|
/* Return true if return values of type TYPE should be returned
|
| 8366 |
|
|
in a memory buffer whose address is passed by the caller as
|
| 8367 |
|
|
hidden first argument. */
|
| 8368 |
|
|
|
| 8369 |
|
|
static bool
|
| 8370 |
|
|
s390_return_in_memory (const_tree type, const_tree fundecl ATTRIBUTE_UNUSED)
|
| 8371 |
|
|
{
|
| 8372 |
|
|
/* We accept small integral (and similar) types. */
|
| 8373 |
|
|
if (INTEGRAL_TYPE_P (type)
|
| 8374 |
|
|
|| POINTER_TYPE_P (type)
|
| 8375 |
|
|
|| TREE_CODE (type) == OFFSET_TYPE
|
| 8376 |
|
|
|| TREE_CODE (type) == REAL_TYPE)
|
| 8377 |
|
|
return int_size_in_bytes (type) > 8;
|
| 8378 |
|
|
|
| 8379 |
|
|
/* Aggregates and similar constructs are always returned
|
| 8380 |
|
|
in memory. */
|
| 8381 |
|
|
if (AGGREGATE_TYPE_P (type)
|
| 8382 |
|
|
|| TREE_CODE (type) == COMPLEX_TYPE
|
| 8383 |
|
|
|| TREE_CODE (type) == VECTOR_TYPE)
|
| 8384 |
|
|
return true;
|
| 8385 |
|
|
|
| 8386 |
|
|
/* ??? We get called on all sorts of random stuff from
|
| 8387 |
|
|
aggregate_value_p. We can't abort, but it's not clear
|
| 8388 |
|
|
what's safe to return. Pretend it's a struct I guess. */
|
| 8389 |
|
|
return true;
|
| 8390 |
|
|
}
|
| 8391 |
|
|
|
| 8392 |
|
|
/* Function arguments and return values are promoted to word size. */
|
| 8393 |
|
|
|
| 8394 |
|
|
static enum machine_mode
|
| 8395 |
|
|
s390_promote_function_mode (const_tree type, enum machine_mode mode,
|
| 8396 |
|
|
int *punsignedp,
|
| 8397 |
|
|
const_tree fntype ATTRIBUTE_UNUSED,
|
| 8398 |
|
|
int for_return ATTRIBUTE_UNUSED)
|
| 8399 |
|
|
{
|
| 8400 |
|
|
if (INTEGRAL_MODE_P (mode)
|
| 8401 |
|
|
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
|
| 8402 |
|
|
{
|
| 8403 |
|
|
if (POINTER_TYPE_P (type))
|
| 8404 |
|
|
*punsignedp = POINTERS_EXTEND_UNSIGNED;
|
| 8405 |
|
|
return Pmode;
|
| 8406 |
|
|
}
|
| 8407 |
|
|
|
| 8408 |
|
|
return mode;
|
| 8409 |
|
|
}
|
| 8410 |
|
|
|
| 8411 |
|
|
/* Define where to return a (scalar) value of type TYPE.
|
| 8412 |
|
|
If TYPE is null, define where to return a (scalar)
|
| 8413 |
|
|
value of mode MODE from a libcall. */
|
| 8414 |
|
|
|
| 8415 |
|
|
rtx
|
| 8416 |
|
|
s390_function_value (const_tree type, const_tree fn, enum machine_mode mode)
|
| 8417 |
|
|
{
|
| 8418 |
|
|
if (type)
|
| 8419 |
|
|
{
|
| 8420 |
|
|
int unsignedp = TYPE_UNSIGNED (type);
|
| 8421 |
|
|
mode = promote_function_mode (type, TYPE_MODE (type), &unsignedp, fn, 1);
|
| 8422 |
|
|
}
|
| 8423 |
|
|
|
| 8424 |
|
|
gcc_assert (GET_MODE_CLASS (mode) == MODE_INT || SCALAR_FLOAT_MODE_P (mode));
|
| 8425 |
|
|
gcc_assert (GET_MODE_SIZE (mode) <= 8);
|
| 8426 |
|
|
|
| 8427 |
|
|
if (TARGET_HARD_FLOAT && SCALAR_FLOAT_MODE_P (mode))
|
| 8428 |
|
|
return gen_rtx_REG (mode, 16);
|
| 8429 |
|
|
else
|
| 8430 |
|
|
return gen_rtx_REG (mode, 2);
|
| 8431 |
|
|
}
|
| 8432 |
|
|
|
| 8433 |
|
|
|
| 8434 |
|
|
/* Create and return the va_list datatype.
|
| 8435 |
|
|
|
| 8436 |
|
|
On S/390, va_list is an array type equivalent to
|
| 8437 |
|
|
|
| 8438 |
|
|
typedef struct __va_list_tag
|
| 8439 |
|
|
{
|
| 8440 |
|
|
long __gpr;
|
| 8441 |
|
|
long __fpr;
|
| 8442 |
|
|
void *__overflow_arg_area;
|
| 8443 |
|
|
void *__reg_save_area;
|
| 8444 |
|
|
} va_list[1];
|
| 8445 |
|
|
|
| 8446 |
|
|
where __gpr and __fpr hold the number of general purpose
|
| 8447 |
|
|
or floating point arguments used up to now, respectively,
|
| 8448 |
|
|
__overflow_arg_area points to the stack location of the
|
| 8449 |
|
|
next argument passed on the stack, and __reg_save_area
|
| 8450 |
|
|
always points to the start of the register area in the
|
| 8451 |
|
|
call frame of the current function. The function prologue
|
| 8452 |
|
|
saves all registers used for argument passing into this
|
| 8453 |
|
|
area if the function uses variable arguments. */
|
| 8454 |
|
|
|
| 8455 |
|
|
static tree
|
| 8456 |
|
|
s390_build_builtin_va_list (void)
|
| 8457 |
|
|
{
|
| 8458 |
|
|
tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
|
| 8459 |
|
|
|
| 8460 |
|
|
record = lang_hooks.types.make_type (RECORD_TYPE);
|
| 8461 |
|
|
|
| 8462 |
|
|
type_decl =
|
| 8463 |
|
|
build_decl (BUILTINS_LOCATION,
|
| 8464 |
|
|
TYPE_DECL, get_identifier ("__va_list_tag"), record);
|
| 8465 |
|
|
|
| 8466 |
|
|
f_gpr = build_decl (BUILTINS_LOCATION,
|
| 8467 |
|
|
FIELD_DECL, get_identifier ("__gpr"),
|
| 8468 |
|
|
long_integer_type_node);
|
| 8469 |
|
|
f_fpr = build_decl (BUILTINS_LOCATION,
|
| 8470 |
|
|
FIELD_DECL, get_identifier ("__fpr"),
|
| 8471 |
|
|
long_integer_type_node);
|
| 8472 |
|
|
f_ovf = build_decl (BUILTINS_LOCATION,
|
| 8473 |
|
|
FIELD_DECL, get_identifier ("__overflow_arg_area"),
|
| 8474 |
|
|
ptr_type_node);
|
| 8475 |
|
|
f_sav = build_decl (BUILTINS_LOCATION,
|
| 8476 |
|
|
FIELD_DECL, get_identifier ("__reg_save_area"),
|
| 8477 |
|
|
ptr_type_node);
|
| 8478 |
|
|
|
| 8479 |
|
|
va_list_gpr_counter_field = f_gpr;
|
| 8480 |
|
|
va_list_fpr_counter_field = f_fpr;
|
| 8481 |
|
|
|
| 8482 |
|
|
DECL_FIELD_CONTEXT (f_gpr) = record;
|
| 8483 |
|
|
DECL_FIELD_CONTEXT (f_fpr) = record;
|
| 8484 |
|
|
DECL_FIELD_CONTEXT (f_ovf) = record;
|
| 8485 |
|
|
DECL_FIELD_CONTEXT (f_sav) = record;
|
| 8486 |
|
|
|
| 8487 |
|
|
TREE_CHAIN (record) = type_decl;
|
| 8488 |
|
|
TYPE_NAME (record) = type_decl;
|
| 8489 |
|
|
TYPE_FIELDS (record) = f_gpr;
|
| 8490 |
|
|
TREE_CHAIN (f_gpr) = f_fpr;
|
| 8491 |
|
|
TREE_CHAIN (f_fpr) = f_ovf;
|
| 8492 |
|
|
TREE_CHAIN (f_ovf) = f_sav;
|
| 8493 |
|
|
|
| 8494 |
|
|
layout_type (record);
|
| 8495 |
|
|
|
| 8496 |
|
|
/* The correct type is an array type of one element. */
|
| 8497 |
|
|
return build_array_type (record, build_index_type (size_zero_node));
|
| 8498 |
|
|
}
|
| 8499 |
|
|
|
| 8500 |
|
|
/* Implement va_start by filling the va_list structure VALIST.
|
| 8501 |
|
|
STDARG_P is always true, and ignored.
|
| 8502 |
|
|
NEXTARG points to the first anonymous stack argument.
|
| 8503 |
|
|
|
| 8504 |
|
|
The following global variables are used to initialize
|
| 8505 |
|
|
the va_list structure:
|
| 8506 |
|
|
|
| 8507 |
|
|
crtl->args.info:
|
| 8508 |
|
|
holds number of gprs and fprs used for named arguments.
|
| 8509 |
|
|
crtl->args.arg_offset_rtx:
|
| 8510 |
|
|
holds the offset of the first anonymous stack argument
|
| 8511 |
|
|
(relative to the virtual arg pointer). */
|
| 8512 |
|
|
|
| 8513 |
|
|
static void
|
| 8514 |
|
|
s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
|
| 8515 |
|
|
{
|
| 8516 |
|
|
HOST_WIDE_INT n_gpr, n_fpr;
|
| 8517 |
|
|
int off;
|
| 8518 |
|
|
tree f_gpr, f_fpr, f_ovf, f_sav;
|
| 8519 |
|
|
tree gpr, fpr, ovf, sav, t;
|
| 8520 |
|
|
|
| 8521 |
|
|
f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
|
| 8522 |
|
|
f_fpr = TREE_CHAIN (f_gpr);
|
| 8523 |
|
|
f_ovf = TREE_CHAIN (f_fpr);
|
| 8524 |
|
|
f_sav = TREE_CHAIN (f_ovf);
|
| 8525 |
|
|
|
| 8526 |
|
|
valist = build_va_arg_indirect_ref (valist);
|
| 8527 |
|
|
gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
|
| 8528 |
|
|
fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
|
| 8529 |
|
|
ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
|
| 8530 |
|
|
sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
|
| 8531 |
|
|
|
| 8532 |
|
|
/* Count number of gp and fp argument registers used. */
|
| 8533 |
|
|
|
| 8534 |
|
|
n_gpr = crtl->args.info.gprs;
|
| 8535 |
|
|
n_fpr = crtl->args.info.fprs;
|
| 8536 |
|
|
|
| 8537 |
|
|
if (cfun->va_list_gpr_size)
|
| 8538 |
|
|
{
|
| 8539 |
|
|
t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
|
| 8540 |
|
|
build_int_cst (NULL_TREE, n_gpr));
|
| 8541 |
|
|
TREE_SIDE_EFFECTS (t) = 1;
|
| 8542 |
|
|
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
| 8543 |
|
|
}
|
| 8544 |
|
|
|
| 8545 |
|
|
if (cfun->va_list_fpr_size)
|
| 8546 |
|
|
{
|
| 8547 |
|
|
t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
|
| 8548 |
|
|
build_int_cst (NULL_TREE, n_fpr));
|
| 8549 |
|
|
TREE_SIDE_EFFECTS (t) = 1;
|
| 8550 |
|
|
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
| 8551 |
|
|
}
|
| 8552 |
|
|
|
| 8553 |
|
|
/* Find the overflow area. */
|
| 8554 |
|
|
if (n_gpr + cfun->va_list_gpr_size > GP_ARG_NUM_REG
|
| 8555 |
|
|
|| n_fpr + cfun->va_list_fpr_size > FP_ARG_NUM_REG)
|
| 8556 |
|
|
{
|
| 8557 |
|
|
t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
|
| 8558 |
|
|
|
| 8559 |
|
|
off = INTVAL (crtl->args.arg_offset_rtx);
|
| 8560 |
|
|
off = off < 0 ? 0 : off;
|
| 8561 |
|
|
if (TARGET_DEBUG_ARG)
|
| 8562 |
|
|
fprintf (stderr, "va_start: n_gpr = %d, n_fpr = %d off %d\n",
|
| 8563 |
|
|
(int)n_gpr, (int)n_fpr, off);
|
| 8564 |
|
|
|
| 8565 |
|
|
t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovf), t, size_int (off));
|
| 8566 |
|
|
|
| 8567 |
|
|
t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
|
| 8568 |
|
|
TREE_SIDE_EFFECTS (t) = 1;
|
| 8569 |
|
|
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
| 8570 |
|
|
}
|
| 8571 |
|
|
|
| 8572 |
|
|
/* Find the register save area. */
|
| 8573 |
|
|
if ((cfun->va_list_gpr_size && n_gpr < GP_ARG_NUM_REG)
|
| 8574 |
|
|
|| (cfun->va_list_fpr_size && n_fpr < FP_ARG_NUM_REG))
|
| 8575 |
|
|
{
|
| 8576 |
|
|
t = make_tree (TREE_TYPE (sav), return_address_pointer_rtx);
|
| 8577 |
|
|
t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (sav), t,
|
| 8578 |
|
|
size_int (-RETURN_REGNUM * UNITS_PER_WORD));
|
| 8579 |
|
|
|
| 8580 |
|
|
t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
|
| 8581 |
|
|
TREE_SIDE_EFFECTS (t) = 1;
|
| 8582 |
|
|
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
| 8583 |
|
|
}
|
| 8584 |
|
|
}
|
| 8585 |
|
|
|
| 8586 |
|
|
/* Implement va_arg by updating the va_list structure
|
| 8587 |
|
|
VALIST as required to retrieve an argument of type
|
| 8588 |
|
|
TYPE, and returning that argument.
|
| 8589 |
|
|
|
| 8590 |
|
|
Generates code equivalent to:
|
| 8591 |
|
|
|
| 8592 |
|
|
if (integral value) {
|
| 8593 |
|
|
if (size <= 4 && args.gpr < 5 ||
|
| 8594 |
|
|
size > 4 && args.gpr < 4 )
|
| 8595 |
|
|
ret = args.reg_save_area[args.gpr+8]
|
| 8596 |
|
|
else
|
| 8597 |
|
|
ret = *args.overflow_arg_area++;
|
| 8598 |
|
|
} else if (float value) {
|
| 8599 |
|
|
if (args.fgpr < 2)
|
| 8600 |
|
|
ret = args.reg_save_area[args.fpr+64]
|
| 8601 |
|
|
else
|
| 8602 |
|
|
ret = *args.overflow_arg_area++;
|
| 8603 |
|
|
} else if (aggregate value) {
|
| 8604 |
|
|
if (args.gpr < 5)
|
| 8605 |
|
|
ret = *args.reg_save_area[args.gpr]
|
| 8606 |
|
|
else
|
| 8607 |
|
|
ret = **args.overflow_arg_area++;
|
| 8608 |
|
|
} */
|
| 8609 |
|
|
|
| 8610 |
|
|
static tree
|
| 8611 |
|
|
s390_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
|
| 8612 |
|
|
gimple_seq *post_p ATTRIBUTE_UNUSED)
|
| 8613 |
|
|
{
|
| 8614 |
|
|
tree f_gpr, f_fpr, f_ovf, f_sav;
|
| 8615 |
|
|
tree gpr, fpr, ovf, sav, reg, t, u;
|
| 8616 |
|
|
int indirect_p, size, n_reg, sav_ofs, sav_scale, max_reg;
|
| 8617 |
|
|
tree lab_false, lab_over, addr;
|
| 8618 |
|
|
|
| 8619 |
|
|
f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
|
| 8620 |
|
|
f_fpr = TREE_CHAIN (f_gpr);
|
| 8621 |
|
|
f_ovf = TREE_CHAIN (f_fpr);
|
| 8622 |
|
|
f_sav = TREE_CHAIN (f_ovf);
|
| 8623 |
|
|
|
| 8624 |
|
|
valist = build_va_arg_indirect_ref (valist);
|
| 8625 |
|
|
gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
|
| 8626 |
|
|
fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
|
| 8627 |
|
|
sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
|
| 8628 |
|
|
|
| 8629 |
|
|
/* The tree for args* cannot be shared between gpr/fpr and ovf since
|
| 8630 |
|
|
both appear on a lhs. */
|
| 8631 |
|
|
valist = unshare_expr (valist);
|
| 8632 |
|
|
ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
|
| 8633 |
|
|
|
| 8634 |
|
|
size = int_size_in_bytes (type);
|
| 8635 |
|
|
|
| 8636 |
|
|
if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
|
| 8637 |
|
|
{
|
| 8638 |
|
|
if (TARGET_DEBUG_ARG)
|
| 8639 |
|
|
{
|
| 8640 |
|
|
fprintf (stderr, "va_arg: aggregate type");
|
| 8641 |
|
|
debug_tree (type);
|
| 8642 |
|
|
}
|
| 8643 |
|
|
|
| 8644 |
|
|
/* Aggregates are passed by reference. */
|
| 8645 |
|
|
indirect_p = 1;
|
| 8646 |
|
|
reg = gpr;
|
| 8647 |
|
|
n_reg = 1;
|
| 8648 |
|
|
|
| 8649 |
|
|
/* kernel stack layout on 31 bit: It is assumed here that no padding
|
| 8650 |
|
|
will be added by s390_frame_info because for va_args always an even
|
| 8651 |
|
|
number of gprs has to be saved r15-r2 = 14 regs. */
|
| 8652 |
|
|
sav_ofs = 2 * UNITS_PER_WORD;
|
| 8653 |
|
|
sav_scale = UNITS_PER_WORD;
|
| 8654 |
|
|
size = UNITS_PER_WORD;
|
| 8655 |
|
|
max_reg = GP_ARG_NUM_REG - n_reg;
|
| 8656 |
|
|
}
|
| 8657 |
|
|
else if (s390_function_arg_float (TYPE_MODE (type), type))
|
| 8658 |
|
|
{
|
| 8659 |
|
|
if (TARGET_DEBUG_ARG)
|
| 8660 |
|
|
{
|
| 8661 |
|
|
fprintf (stderr, "va_arg: float type");
|
| 8662 |
|
|
debug_tree (type);
|
| 8663 |
|
|
}
|
| 8664 |
|
|
|
| 8665 |
|
|
/* FP args go in FP registers, if present. */
|
| 8666 |
|
|
indirect_p = 0;
|
| 8667 |
|
|
reg = fpr;
|
| 8668 |
|
|
n_reg = 1;
|
| 8669 |
|
|
sav_ofs = 16 * UNITS_PER_WORD;
|
| 8670 |
|
|
sav_scale = 8;
|
| 8671 |
|
|
max_reg = FP_ARG_NUM_REG - n_reg;
|
| 8672 |
|
|
}
|
| 8673 |
|
|
else
|
| 8674 |
|
|
{
|
| 8675 |
|
|
if (TARGET_DEBUG_ARG)
|
| 8676 |
|
|
{
|
| 8677 |
|
|
fprintf (stderr, "va_arg: other type");
|
| 8678 |
|
|
debug_tree (type);
|
| 8679 |
|
|
}
|
| 8680 |
|
|
|
| 8681 |
|
|
/* Otherwise into GP registers. */
|
| 8682 |
|
|
indirect_p = 0;
|
| 8683 |
|
|
reg = gpr;
|
| 8684 |
|
|
n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
|
| 8685 |
|
|
|
| 8686 |
|
|
/* kernel stack layout on 31 bit: It is assumed here that no padding
|
| 8687 |
|
|
will be added by s390_frame_info because for va_args always an even
|
| 8688 |
|
|
number of gprs has to be saved r15-r2 = 14 regs. */
|
| 8689 |
|
|
sav_ofs = 2 * UNITS_PER_WORD;
|
| 8690 |
|
|
|
| 8691 |
|
|
if (size < UNITS_PER_WORD)
|
| 8692 |
|
|
sav_ofs += UNITS_PER_WORD - size;
|
| 8693 |
|
|
|
| 8694 |
|
|
sav_scale = UNITS_PER_WORD;
|
| 8695 |
|
|
max_reg = GP_ARG_NUM_REG - n_reg;
|
| 8696 |
|
|
}
|
| 8697 |
|
|
|
| 8698 |
|
|
/* Pull the value out of the saved registers ... */
|
| 8699 |
|
|
|
| 8700 |
|
|
lab_false = create_artificial_label (UNKNOWN_LOCATION);
|
| 8701 |
|
|
lab_over = create_artificial_label (UNKNOWN_LOCATION);
|
| 8702 |
|
|
addr = create_tmp_var (ptr_type_node, "addr");
|
| 8703 |
|
|
|
| 8704 |
|
|
t = fold_convert (TREE_TYPE (reg), size_int (max_reg));
|
| 8705 |
|
|
t = build2 (GT_EXPR, boolean_type_node, reg, t);
|
| 8706 |
|
|
u = build1 (GOTO_EXPR, void_type_node, lab_false);
|
| 8707 |
|
|
t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
|
| 8708 |
|
|
gimplify_and_add (t, pre_p);
|
| 8709 |
|
|
|
| 8710 |
|
|
t = build2 (POINTER_PLUS_EXPR, ptr_type_node, sav,
|
| 8711 |
|
|
size_int (sav_ofs));
|
| 8712 |
|
|
u = build2 (MULT_EXPR, TREE_TYPE (reg), reg,
|
| 8713 |
|
|
fold_convert (TREE_TYPE (reg), size_int (sav_scale)));
|
| 8714 |
|
|
t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t, fold_convert (sizetype, u));
|
| 8715 |
|
|
|
| 8716 |
|
|
gimplify_assign (addr, t, pre_p);
|
| 8717 |
|
|
|
| 8718 |
|
|
gimple_seq_add_stmt (pre_p, gimple_build_goto (lab_over));
|
| 8719 |
|
|
|
| 8720 |
|
|
gimple_seq_add_stmt (pre_p, gimple_build_label (lab_false));
|
| 8721 |
|
|
|
| 8722 |
|
|
|
| 8723 |
|
|
/* ... Otherwise out of the overflow area. */
|
| 8724 |
|
|
|
| 8725 |
|
|
t = ovf;
|
| 8726 |
|
|
if (size < UNITS_PER_WORD)
|
| 8727 |
|
|
t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t,
|
| 8728 |
|
|
size_int (UNITS_PER_WORD - size));
|
| 8729 |
|
|
|
| 8730 |
|
|
gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
|
| 8731 |
|
|
|
| 8732 |
|
|
gimplify_assign (addr, t, pre_p);
|
| 8733 |
|
|
|
| 8734 |
|
|
t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t,
|
| 8735 |
|
|
size_int (size));
|
| 8736 |
|
|
gimplify_assign (ovf, t, pre_p);
|
| 8737 |
|
|
|
| 8738 |
|
|
gimple_seq_add_stmt (pre_p, gimple_build_label (lab_over));
|
| 8739 |
|
|
|
| 8740 |
|
|
|
| 8741 |
|
|
/* Increment register save count. */
|
| 8742 |
|
|
|
| 8743 |
|
|
u = build2 (PREINCREMENT_EXPR, TREE_TYPE (reg), reg,
|
| 8744 |
|
|
fold_convert (TREE_TYPE (reg), size_int (n_reg)));
|
| 8745 |
|
|
gimplify_and_add (u, pre_p);
|
| 8746 |
|
|
|
| 8747 |
|
|
if (indirect_p)
|
| 8748 |
|
|
{
|
| 8749 |
|
|
t = build_pointer_type_for_mode (build_pointer_type (type),
|
| 8750 |
|
|
ptr_mode, true);
|
| 8751 |
|
|
addr = fold_convert (t, addr);
|
| 8752 |
|
|
addr = build_va_arg_indirect_ref (addr);
|
| 8753 |
|
|
}
|
| 8754 |
|
|
else
|
| 8755 |
|
|
{
|
| 8756 |
|
|
t = build_pointer_type_for_mode (type, ptr_mode, true);
|
| 8757 |
|
|
addr = fold_convert (t, addr);
|
| 8758 |
|
|
}
|
| 8759 |
|
|
|
| 8760 |
|
|
return build_va_arg_indirect_ref (addr);
|
| 8761 |
|
|
}
|
| 8762 |
|
|
|
| 8763 |
|
|
|
| 8764 |
|
|
/* Builtins. */
|
| 8765 |
|
|
|
| 8766 |
|
|
enum s390_builtin
|
| 8767 |
|
|
{
|
| 8768 |
|
|
S390_BUILTIN_THREAD_POINTER,
|
| 8769 |
|
|
S390_BUILTIN_SET_THREAD_POINTER,
|
| 8770 |
|
|
|
| 8771 |
|
|
S390_BUILTIN_max
|
| 8772 |
|
|
};
|
| 8773 |
|
|
|
| 8774 |
|
|
static enum insn_code const code_for_builtin_64[S390_BUILTIN_max] = {
|
| 8775 |
|
|
CODE_FOR_get_tp_64,
|
| 8776 |
|
|
CODE_FOR_set_tp_64
|
| 8777 |
|
|
};
|
| 8778 |
|
|
|
| 8779 |
|
|
static enum insn_code const code_for_builtin_31[S390_BUILTIN_max] = {
|
| 8780 |
|
|
CODE_FOR_get_tp_31,
|
| 8781 |
|
|
CODE_FOR_set_tp_31
|
| 8782 |
|
|
};
|
| 8783 |
|
|
|
| 8784 |
|
|
static void
|
| 8785 |
|
|
s390_init_builtins (void)
|
| 8786 |
|
|
{
|
| 8787 |
|
|
tree ftype;
|
| 8788 |
|
|
|
| 8789 |
|
|
ftype = build_function_type (ptr_type_node, void_list_node);
|
| 8790 |
|
|
add_builtin_function ("__builtin_thread_pointer", ftype,
|
| 8791 |
|
|
S390_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
|
| 8792 |
|
|
NULL, NULL_TREE);
|
| 8793 |
|
|
|
| 8794 |
|
|
ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
|
| 8795 |
|
|
add_builtin_function ("__builtin_set_thread_pointer", ftype,
|
| 8796 |
|
|
S390_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
|
| 8797 |
|
|
NULL, NULL_TREE);
|
| 8798 |
|
|
}
|
| 8799 |
|
|
|
| 8800 |
|
|
/* Expand an expression EXP that calls a built-in function,
|
| 8801 |
|
|
with result going to TARGET if that's convenient
|
| 8802 |
|
|
(and in mode MODE if that's convenient).
|
| 8803 |
|
|
SUBTARGET may be used as the target for computing one of EXP's operands.
|
| 8804 |
|
|
IGNORE is nonzero if the value is to be ignored. */
|
| 8805 |
|
|
|
| 8806 |
|
|
static rtx
|
| 8807 |
|
|
s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
|
| 8808 |
|
|
enum machine_mode mode ATTRIBUTE_UNUSED,
|
| 8809 |
|
|
int ignore ATTRIBUTE_UNUSED)
|
| 8810 |
|
|
{
|
| 8811 |
|
|
#define MAX_ARGS 2
|
| 8812 |
|
|
|
| 8813 |
|
|
enum insn_code const *code_for_builtin =
|
| 8814 |
|
|
TARGET_64BIT ? code_for_builtin_64 : code_for_builtin_31;
|
| 8815 |
|
|
|
| 8816 |
|
|
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
|
| 8817 |
|
|
unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
|
| 8818 |
|
|
enum insn_code icode;
|
| 8819 |
|
|
rtx op[MAX_ARGS], pat;
|
| 8820 |
|
|
int arity;
|
| 8821 |
|
|
bool nonvoid;
|
| 8822 |
|
|
tree arg;
|
| 8823 |
|
|
call_expr_arg_iterator iter;
|
| 8824 |
|
|
|
| 8825 |
|
|
if (fcode >= S390_BUILTIN_max)
|
| 8826 |
|
|
internal_error ("bad builtin fcode");
|
| 8827 |
|
|
icode = code_for_builtin[fcode];
|
| 8828 |
|
|
if (icode == 0)
|
| 8829 |
|
|
internal_error ("bad builtin fcode");
|
| 8830 |
|
|
|
| 8831 |
|
|
nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
|
| 8832 |
|
|
|
| 8833 |
|
|
arity = 0;
|
| 8834 |
|
|
FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
|
| 8835 |
|
|
{
|
| 8836 |
|
|
const struct insn_operand_data *insn_op;
|
| 8837 |
|
|
|
| 8838 |
|
|
if (arg == error_mark_node)
|
| 8839 |
|
|
return NULL_RTX;
|
| 8840 |
|
|
if (arity > MAX_ARGS)
|
| 8841 |
|
|
return NULL_RTX;
|
| 8842 |
|
|
|
| 8843 |
|
|
insn_op = &insn_data[icode].operand[arity + nonvoid];
|
| 8844 |
|
|
|
| 8845 |
|
|
op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
|
| 8846 |
|
|
|
| 8847 |
|
|
if (!(*insn_op->predicate) (op[arity], insn_op->mode))
|
| 8848 |
|
|
op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
|
| 8849 |
|
|
arity++;
|
| 8850 |
|
|
}
|
| 8851 |
|
|
|
| 8852 |
|
|
if (nonvoid)
|
| 8853 |
|
|
{
|
| 8854 |
|
|
enum machine_mode tmode = insn_data[icode].operand[0].mode;
|
| 8855 |
|
|
if (!target
|
| 8856 |
|
|
|| GET_MODE (target) != tmode
|
| 8857 |
|
|
|| !(*insn_data[icode].operand[0].predicate) (target, tmode))
|
| 8858 |
|
|
target = gen_reg_rtx (tmode);
|
| 8859 |
|
|
}
|
| 8860 |
|
|
|
| 8861 |
|
|
switch (arity)
|
| 8862 |
|
|
{
|
| 8863 |
|
|
case 0:
|
| 8864 |
|
|
pat = GEN_FCN (icode) (target);
|
| 8865 |
|
|
break;
|
| 8866 |
|
|
case 1:
|
| 8867 |
|
|
if (nonvoid)
|
| 8868 |
|
|
pat = GEN_FCN (icode) (target, op[0]);
|
| 8869 |
|
|
else
|
| 8870 |
|
|
pat = GEN_FCN (icode) (op[0]);
|
| 8871 |
|
|
break;
|
| 8872 |
|
|
case 2:
|
| 8873 |
|
|
pat = GEN_FCN (icode) (target, op[0], op[1]);
|
| 8874 |
|
|
break;
|
| 8875 |
|
|
default:
|
| 8876 |
|
|
gcc_unreachable ();
|
| 8877 |
|
|
}
|
| 8878 |
|
|
if (!pat)
|
| 8879 |
|
|
return NULL_RTX;
|
| 8880 |
|
|
emit_insn (pat);
|
| 8881 |
|
|
|
| 8882 |
|
|
if (nonvoid)
|
| 8883 |
|
|
return target;
|
| 8884 |
|
|
else
|
| 8885 |
|
|
return const0_rtx;
|
| 8886 |
|
|
}
|
| 8887 |
|
|
|
| 8888 |
|
|
|
| 8889 |
|
|
/* Output assembly code for the trampoline template to
|
| 8890 |
|
|
stdio stream FILE.
|
| 8891 |
|
|
|
| 8892 |
|
|
On S/390, we use gpr 1 internally in the trampoline code;
|
| 8893 |
|
|
gpr 0 is used to hold the static chain. */
|
| 8894 |
|
|
|
| 8895 |
|
|
static void
|
| 8896 |
|
|
s390_asm_trampoline_template (FILE *file)
|
| 8897 |
|
|
{
|
| 8898 |
|
|
rtx op[2];
|
| 8899 |
|
|
op[0] = gen_rtx_REG (Pmode, 0);
|
| 8900 |
|
|
op[1] = gen_rtx_REG (Pmode, 1);
|
| 8901 |
|
|
|
| 8902 |
|
|
if (TARGET_64BIT)
|
| 8903 |
|
|
{
|
| 8904 |
|
|
output_asm_insn ("basr\t%1,0", op);
|
| 8905 |
|
|
output_asm_insn ("lmg\t%0,%1,14(%1)", op);
|
| 8906 |
|
|
output_asm_insn ("br\t%1", op);
|
| 8907 |
|
|
ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 10));
|
| 8908 |
|
|
}
|
| 8909 |
|
|
else
|
| 8910 |
|
|
{
|
| 8911 |
|
|
output_asm_insn ("basr\t%1,0", op);
|
| 8912 |
|
|
output_asm_insn ("lm\t%0,%1,6(%1)", op);
|
| 8913 |
|
|
output_asm_insn ("br\t%1", op);
|
| 8914 |
|
|
ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 8));
|
| 8915 |
|
|
}
|
| 8916 |
|
|
}
|
| 8917 |
|
|
|
| 8918 |
|
|
/* Emit RTL insns to initialize the variable parts of a trampoline.
|
| 8919 |
|
|
FNADDR is an RTX for the address of the function's pure code.
|
| 8920 |
|
|
CXT is an RTX for the static chain value for the function. */
|
| 8921 |
|
|
|
| 8922 |
|
|
static void
|
| 8923 |
|
|
s390_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
|
| 8924 |
|
|
{
|
| 8925 |
|
|
rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
|
| 8926 |
|
|
rtx mem;
|
| 8927 |
|
|
|
| 8928 |
|
|
emit_block_move (m_tramp, assemble_trampoline_template (),
|
| 8929 |
|
|
GEN_INT (2*UNITS_PER_WORD), BLOCK_OP_NORMAL);
|
| 8930 |
|
|
|
| 8931 |
|
|
mem = adjust_address (m_tramp, Pmode, 2*UNITS_PER_WORD);
|
| 8932 |
|
|
emit_move_insn (mem, cxt);
|
| 8933 |
|
|
mem = adjust_address (m_tramp, Pmode, 3*UNITS_PER_WORD);
|
| 8934 |
|
|
emit_move_insn (mem, fnaddr);
|
| 8935 |
|
|
}
|
| 8936 |
|
|
|
| 8937 |
|
|
/* Output assembler code to FILE to increment profiler label # LABELNO
|
| 8938 |
|
|
for profiling a function entry. */
|
| 8939 |
|
|
|
| 8940 |
|
|
void
|
| 8941 |
|
|
s390_function_profiler (FILE *file, int labelno)
|
| 8942 |
|
|
{
|
| 8943 |
|
|
rtx op[7];
|
| 8944 |
|
|
|
| 8945 |
|
|
char label[128];
|
| 8946 |
|
|
ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
|
| 8947 |
|
|
|
| 8948 |
|
|
fprintf (file, "# function profiler \n");
|
| 8949 |
|
|
|
| 8950 |
|
|
op[0] = gen_rtx_REG (Pmode, RETURN_REGNUM);
|
| 8951 |
|
|
op[1] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
|
| 8952 |
|
|
op[1] = gen_rtx_MEM (Pmode, plus_constant (op[1], UNITS_PER_WORD));
|
| 8953 |
|
|
|
| 8954 |
|
|
op[2] = gen_rtx_REG (Pmode, 1);
|
| 8955 |
|
|
op[3] = gen_rtx_SYMBOL_REF (Pmode, label);
|
| 8956 |
|
|
SYMBOL_REF_FLAGS (op[3]) = SYMBOL_FLAG_LOCAL;
|
| 8957 |
|
|
|
| 8958 |
|
|
op[4] = gen_rtx_SYMBOL_REF (Pmode, "_mcount");
|
| 8959 |
|
|
if (flag_pic)
|
| 8960 |
|
|
{
|
| 8961 |
|
|
op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), UNSPEC_PLT);
|
| 8962 |
|
|
op[4] = gen_rtx_CONST (Pmode, op[4]);
|
| 8963 |
|
|
}
|
| 8964 |
|
|
|
| 8965 |
|
|
if (TARGET_64BIT)
|
| 8966 |
|
|
{
|
| 8967 |
|
|
output_asm_insn ("stg\t%0,%1", op);
|
| 8968 |
|
|
output_asm_insn ("larl\t%2,%3", op);
|
| 8969 |
|
|
output_asm_insn ("brasl\t%0,%4", op);
|
| 8970 |
|
|
output_asm_insn ("lg\t%0,%1", op);
|
| 8971 |
|
|
}
|
| 8972 |
|
|
else if (!flag_pic)
|
| 8973 |
|
|
{
|
| 8974 |
|
|
op[6] = gen_label_rtx ();
|
| 8975 |
|
|
|
| 8976 |
|
|
output_asm_insn ("st\t%0,%1", op);
|
| 8977 |
|
|
output_asm_insn ("bras\t%2,%l6", op);
|
| 8978 |
|
|
output_asm_insn (".long\t%4", op);
|
| 8979 |
|
|
output_asm_insn (".long\t%3", op);
|
| 8980 |
|
|
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6]));
|
| 8981 |
|
|
output_asm_insn ("l\t%0,0(%2)", op);
|
| 8982 |
|
|
output_asm_insn ("l\t%2,4(%2)", op);
|
| 8983 |
|
|
output_asm_insn ("basr\t%0,%0", op);
|
| 8984 |
|
|
output_asm_insn ("l\t%0,%1", op);
|
| 8985 |
|
|
}
|
| 8986 |
|
|
else
|
| 8987 |
|
|
{
|
| 8988 |
|
|
op[5] = gen_label_rtx ();
|
| 8989 |
|
|
op[6] = gen_label_rtx ();
|
| 8990 |
|
|
|
| 8991 |
|
|
output_asm_insn ("st\t%0,%1", op);
|
| 8992 |
|
|
output_asm_insn ("bras\t%2,%l6", op);
|
| 8993 |
|
|
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[5]));
|
| 8994 |
|
|
output_asm_insn (".long\t%4-%l5", op);
|
| 8995 |
|
|
output_asm_insn (".long\t%3-%l5", op);
|
| 8996 |
|
|
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6]));
|
| 8997 |
|
|
output_asm_insn ("lr\t%0,%2", op);
|
| 8998 |
|
|
output_asm_insn ("a\t%0,0(%2)", op);
|
| 8999 |
|
|
output_asm_insn ("a\t%2,4(%2)", op);
|
| 9000 |
|
|
output_asm_insn ("basr\t%0,%0", op);
|
| 9001 |
|
|
output_asm_insn ("l\t%0,%1", op);
|
| 9002 |
|
|
}
|
| 9003 |
|
|
}
|
| 9004 |
|
|
|
| 9005 |
|
|
/* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF
|
| 9006 |
|
|
into its SYMBOL_REF_FLAGS. */
|
| 9007 |
|
|
|
| 9008 |
|
|
static void
|
| 9009 |
|
|
s390_encode_section_info (tree decl, rtx rtl, int first)
|
| 9010 |
|
|
{
|
| 9011 |
|
|
default_encode_section_info (decl, rtl, first);
|
| 9012 |
|
|
|
| 9013 |
|
|
if (TREE_CODE (decl) == VAR_DECL)
|
| 9014 |
|
|
{
|
| 9015 |
|
|
/* If a variable has a forced alignment to < 2 bytes, mark it
|
| 9016 |
|
|
with SYMBOL_FLAG_ALIGN1 to prevent it from being used as LARL
|
| 9017 |
|
|
operand. */
|
| 9018 |
|
|
if (DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16)
|
| 9019 |
|
|
SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1;
|
| 9020 |
|
|
if (!DECL_SIZE (decl)
|
| 9021 |
|
|
|| !DECL_ALIGN (decl)
|
| 9022 |
|
|
|| !host_integerp (DECL_SIZE (decl), 0)
|
| 9023 |
|
|
|| (DECL_ALIGN (decl) <= 64
|
| 9024 |
|
|
&& DECL_ALIGN (decl) != tree_low_cst (DECL_SIZE (decl), 0)))
|
| 9025 |
|
|
SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED;
|
| 9026 |
|
|
}
|
| 9027 |
|
|
|
| 9028 |
|
|
/* Literal pool references don't have a decl so they are handled
|
| 9029 |
|
|
differently here. We rely on the information in the MEM_ALIGN
|
| 9030 |
|
|
entry to decide upon natural alignment. */
|
| 9031 |
|
|
if (MEM_P (rtl)
|
| 9032 |
|
|
&& GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
|
| 9033 |
|
|
&& TREE_CONSTANT_POOL_ADDRESS_P (XEXP (rtl, 0))
|
| 9034 |
|
|
&& (MEM_ALIGN (rtl) == 0
|
| 9035 |
|
|
|| GET_MODE_BITSIZE (GET_MODE (rtl)) == 0
|
| 9036 |
|
|
|| MEM_ALIGN (rtl) < GET_MODE_BITSIZE (GET_MODE (rtl))))
|
| 9037 |
|
|
SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED;
|
| 9038 |
|
|
}
|
| 9039 |
|
|
|
| 9040 |
|
|
/* Output thunk to FILE that implements a C++ virtual function call (with
|
| 9041 |
|
|
multiple inheritance) to FUNCTION. The thunk adjusts the this pointer
|
| 9042 |
|
|
by DELTA, and unless VCALL_OFFSET is zero, applies an additional adjustment
|
| 9043 |
|
|
stored at VCALL_OFFSET in the vtable whose address is located at offset 0
|
| 9044 |
|
|
relative to the resulting this pointer. */
|
| 9045 |
|
|
|
| 9046 |
|
|
static void
|
| 9047 |
|
|
s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
|
| 9048 |
|
|
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
|
| 9049 |
|
|
tree function)
|
| 9050 |
|
|
{
|
| 9051 |
|
|
rtx op[10];
|
| 9052 |
|
|
int nonlocal = 0;
|
| 9053 |
|
|
|
| 9054 |
|
|
/* Make sure unwind info is emitted for the thunk if needed. */
|
| 9055 |
|
|
final_start_function (emit_barrier (), file, 1);
|
| 9056 |
|
|
|
| 9057 |
|
|
/* Operand 0 is the target function. */
|
| 9058 |
|
|
op[0] = XEXP (DECL_RTL (function), 0);
|
| 9059 |
|
|
if (flag_pic && !SYMBOL_REF_LOCAL_P (op[0]))
|
| 9060 |
|
|
{
|
| 9061 |
|
|
nonlocal = 1;
|
| 9062 |
|
|
op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]),
|
| 9063 |
|
|
TARGET_64BIT ? UNSPEC_PLT : UNSPEC_GOT);
|
| 9064 |
|
|
op[0] = gen_rtx_CONST (Pmode, op[0]);
|
| 9065 |
|
|
}
|
| 9066 |
|
|
|
| 9067 |
|
|
/* Operand 1 is the 'this' pointer. */
|
| 9068 |
|
|
if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
|
| 9069 |
|
|
op[1] = gen_rtx_REG (Pmode, 3);
|
| 9070 |
|
|
else
|
| 9071 |
|
|
op[1] = gen_rtx_REG (Pmode, 2);
|
| 9072 |
|
|
|
| 9073 |
|
|
/* Operand 2 is the delta. */
|
| 9074 |
|
|
op[2] = GEN_INT (delta);
|
| 9075 |
|
|
|
| 9076 |
|
|
/* Operand 3 is the vcall_offset. */
|
| 9077 |
|
|
op[3] = GEN_INT (vcall_offset);
|
| 9078 |
|
|
|
| 9079 |
|
|
/* Operand 4 is the temporary register. */
|
| 9080 |
|
|
op[4] = gen_rtx_REG (Pmode, 1);
|
| 9081 |
|
|
|
| 9082 |
|
|
/* Operands 5 to 8 can be used as labels. */
|
| 9083 |
|
|
op[5] = NULL_RTX;
|
| 9084 |
|
|
op[6] = NULL_RTX;
|
| 9085 |
|
|
op[7] = NULL_RTX;
|
| 9086 |
|
|
op[8] = NULL_RTX;
|
| 9087 |
|
|
|
| 9088 |
|
|
/* Operand 9 can be used for temporary register. */
|
| 9089 |
|
|
op[9] = NULL_RTX;
|
| 9090 |
|
|
|
| 9091 |
|
|
/* Generate code. */
|
| 9092 |
|
|
if (TARGET_64BIT)
|
| 9093 |
|
|
{
|
| 9094 |
|
|
/* Setup literal pool pointer if required. */
|
| 9095 |
|
|
if ((!DISP_IN_RANGE (delta)
|
| 9096 |
|
|
&& !CONST_OK_FOR_K (delta)
|
| 9097 |
|
|
&& !CONST_OK_FOR_Os (delta))
|
| 9098 |
|
|
|| (!DISP_IN_RANGE (vcall_offset)
|
| 9099 |
|
|
&& !CONST_OK_FOR_K (vcall_offset)
|
| 9100 |
|
|
&& !CONST_OK_FOR_Os (vcall_offset)))
|
| 9101 |
|
|
{
|
| 9102 |
|
|
op[5] = gen_label_rtx ();
|
| 9103 |
|
|
output_asm_insn ("larl\t%4,%5", op);
|
| 9104 |
|
|
}
|
| 9105 |
|
|
|
| 9106 |
|
|
/* Add DELTA to this pointer. */
|
| 9107 |
|
|
if (delta)
|
| 9108 |
|
|
{
|
| 9109 |
|
|
if (CONST_OK_FOR_J (delta))
|
| 9110 |
|
|
output_asm_insn ("la\t%1,%2(%1)", op);
|
| 9111 |
|
|
else if (DISP_IN_RANGE (delta))
|
| 9112 |
|
|
output_asm_insn ("lay\t%1,%2(%1)", op);
|
| 9113 |
|
|
else if (CONST_OK_FOR_K (delta))
|
| 9114 |
|
|
output_asm_insn ("aghi\t%1,%2", op);
|
| 9115 |
|
|
else if (CONST_OK_FOR_Os (delta))
|
| 9116 |
|
|
output_asm_insn ("agfi\t%1,%2", op);
|
| 9117 |
|
|
else
|
| 9118 |
|
|
{
|
| 9119 |
|
|
op[6] = gen_label_rtx ();
|
| 9120 |
|
|
output_asm_insn ("agf\t%1,%6-%5(%4)", op);
|
| 9121 |
|
|
}
|
| 9122 |
|
|
}
|
| 9123 |
|
|
|
| 9124 |
|
|
/* Perform vcall adjustment. */
|
| 9125 |
|
|
if (vcall_offset)
|
| 9126 |
|
|
{
|
| 9127 |
|
|
if (DISP_IN_RANGE (vcall_offset))
|
| 9128 |
|
|
{
|
| 9129 |
|
|
output_asm_insn ("lg\t%4,0(%1)", op);
|
| 9130 |
|
|
output_asm_insn ("ag\t%1,%3(%4)", op);
|
| 9131 |
|
|
}
|
| 9132 |
|
|
else if (CONST_OK_FOR_K (vcall_offset))
|
| 9133 |
|
|
{
|
| 9134 |
|
|
output_asm_insn ("lghi\t%4,%3", op);
|
| 9135 |
|
|
output_asm_insn ("ag\t%4,0(%1)", op);
|
| 9136 |
|
|
output_asm_insn ("ag\t%1,0(%4)", op);
|
| 9137 |
|
|
}
|
| 9138 |
|
|
else if (CONST_OK_FOR_Os (vcall_offset))
|
| 9139 |
|
|
{
|
| 9140 |
|
|
output_asm_insn ("lgfi\t%4,%3", op);
|
| 9141 |
|
|
output_asm_insn ("ag\t%4,0(%1)", op);
|
| 9142 |
|
|
output_asm_insn ("ag\t%1,0(%4)", op);
|
| 9143 |
|
|
}
|
| 9144 |
|
|
else
|
| 9145 |
|
|
{
|
| 9146 |
|
|
op[7] = gen_label_rtx ();
|
| 9147 |
|
|
output_asm_insn ("llgf\t%4,%7-%5(%4)", op);
|
| 9148 |
|
|
output_asm_insn ("ag\t%4,0(%1)", op);
|
| 9149 |
|
|
output_asm_insn ("ag\t%1,0(%4)", op);
|
| 9150 |
|
|
}
|
| 9151 |
|
|
}
|
| 9152 |
|
|
|
| 9153 |
|
|
/* Jump to target. */
|
| 9154 |
|
|
output_asm_insn ("jg\t%0", op);
|
| 9155 |
|
|
|
| 9156 |
|
|
/* Output literal pool if required. */
|
| 9157 |
|
|
if (op[5])
|
| 9158 |
|
|
{
|
| 9159 |
|
|
output_asm_insn (".align\t4", op);
|
| 9160 |
|
|
targetm.asm_out.internal_label (file, "L",
|
| 9161 |
|
|
CODE_LABEL_NUMBER (op[5]));
|
| 9162 |
|
|
}
|
| 9163 |
|
|
if (op[6])
|
| 9164 |
|
|
{
|
| 9165 |
|
|
targetm.asm_out.internal_label (file, "L",
|
| 9166 |
|
|
CODE_LABEL_NUMBER (op[6]));
|
| 9167 |
|
|
output_asm_insn (".long\t%2", op);
|
| 9168 |
|
|
}
|
| 9169 |
|
|
if (op[7])
|
| 9170 |
|
|
{
|
| 9171 |
|
|
targetm.asm_out.internal_label (file, "L",
|
| 9172 |
|
|
CODE_LABEL_NUMBER (op[7]));
|
| 9173 |
|
|
output_asm_insn (".long\t%3", op);
|
| 9174 |
|
|
}
|
| 9175 |
|
|
}
|
| 9176 |
|
|
else
|
| 9177 |
|
|
{
|
| 9178 |
|
|
/* Setup base pointer if required. */
|
| 9179 |
|
|
if (!vcall_offset
|
| 9180 |
|
|
|| (!DISP_IN_RANGE (delta)
|
| 9181 |
|
|
&& !CONST_OK_FOR_K (delta)
|
| 9182 |
|
|
&& !CONST_OK_FOR_Os (delta))
|
| 9183 |
|
|
|| (!DISP_IN_RANGE (delta)
|
| 9184 |
|
|
&& !CONST_OK_FOR_K (vcall_offset)
|
| 9185 |
|
|
&& !CONST_OK_FOR_Os (vcall_offset)))
|
| 9186 |
|
|
{
|
| 9187 |
|
|
op[5] = gen_label_rtx ();
|
| 9188 |
|
|
output_asm_insn ("basr\t%4,0", op);
|
| 9189 |
|
|
targetm.asm_out.internal_label (file, "L",
|
| 9190 |
|
|
CODE_LABEL_NUMBER (op[5]));
|
| 9191 |
|
|
}
|
| 9192 |
|
|
|
| 9193 |
|
|
/* Add DELTA to this pointer. */
|
| 9194 |
|
|
if (delta)
|
| 9195 |
|
|
{
|
| 9196 |
|
|
if (CONST_OK_FOR_J (delta))
|
| 9197 |
|
|
output_asm_insn ("la\t%1,%2(%1)", op);
|
| 9198 |
|
|
else if (DISP_IN_RANGE (delta))
|
| 9199 |
|
|
output_asm_insn ("lay\t%1,%2(%1)", op);
|
| 9200 |
|
|
else if (CONST_OK_FOR_K (delta))
|
| 9201 |
|
|
output_asm_insn ("ahi\t%1,%2", op);
|
| 9202 |
|
|
else if (CONST_OK_FOR_Os (delta))
|
| 9203 |
|
|
output_asm_insn ("afi\t%1,%2", op);
|
| 9204 |
|
|
else
|
| 9205 |
|
|
{
|
| 9206 |
|
|
op[6] = gen_label_rtx ();
|
| 9207 |
|
|
output_asm_insn ("a\t%1,%6-%5(%4)", op);
|
| 9208 |
|
|
}
|
| 9209 |
|
|
}
|
| 9210 |
|
|
|
| 9211 |
|
|
/* Perform vcall adjustment. */
|
| 9212 |
|
|
if (vcall_offset)
|
| 9213 |
|
|
{
|
| 9214 |
|
|
if (CONST_OK_FOR_J (vcall_offset))
|
| 9215 |
|
|
{
|
| 9216 |
|
|
output_asm_insn ("l\t%4,0(%1)", op);
|
| 9217 |
|
|
output_asm_insn ("a\t%1,%3(%4)", op);
|
| 9218 |
|
|
}
|
| 9219 |
|
|
else if (DISP_IN_RANGE (vcall_offset))
|
| 9220 |
|
|
{
|
| 9221 |
|
|
output_asm_insn ("l\t%4,0(%1)", op);
|
| 9222 |
|
|
output_asm_insn ("ay\t%1,%3(%4)", op);
|
| 9223 |
|
|
}
|
| 9224 |
|
|
else if (CONST_OK_FOR_K (vcall_offset))
|
| 9225 |
|
|
{
|
| 9226 |
|
|
output_asm_insn ("lhi\t%4,%3", op);
|
| 9227 |
|
|
output_asm_insn ("a\t%4,0(%1)", op);
|
| 9228 |
|
|
output_asm_insn ("a\t%1,0(%4)", op);
|
| 9229 |
|
|
}
|
| 9230 |
|
|
else if (CONST_OK_FOR_Os (vcall_offset))
|
| 9231 |
|
|
{
|
| 9232 |
|
|
output_asm_insn ("iilf\t%4,%3", op);
|
| 9233 |
|
|
output_asm_insn ("a\t%4,0(%1)", op);
|
| 9234 |
|
|
output_asm_insn ("a\t%1,0(%4)", op);
|
| 9235 |
|
|
}
|
| 9236 |
|
|
else
|
| 9237 |
|
|
{
|
| 9238 |
|
|
op[7] = gen_label_rtx ();
|
| 9239 |
|
|
output_asm_insn ("l\t%4,%7-%5(%4)", op);
|
| 9240 |
|
|
output_asm_insn ("a\t%4,0(%1)", op);
|
| 9241 |
|
|
output_asm_insn ("a\t%1,0(%4)", op);
|
| 9242 |
|
|
}
|
| 9243 |
|
|
|
| 9244 |
|
|
/* We had to clobber the base pointer register.
|
| 9245 |
|
|
Re-setup the base pointer (with a different base). */
|
| 9246 |
|
|
op[5] = gen_label_rtx ();
|
| 9247 |
|
|
output_asm_insn ("basr\t%4,0", op);
|
| 9248 |
|
|
targetm.asm_out.internal_label (file, "L",
|
| 9249 |
|
|
CODE_LABEL_NUMBER (op[5]));
|
| 9250 |
|
|
}
|
| 9251 |
|
|
|
| 9252 |
|
|
/* Jump to target. */
|
| 9253 |
|
|
op[8] = gen_label_rtx ();
|
| 9254 |
|
|
|
| 9255 |
|
|
if (!flag_pic)
|
| 9256 |
|
|
output_asm_insn ("l\t%4,%8-%5(%4)", op);
|
| 9257 |
|
|
else if (!nonlocal)
|
| 9258 |
|
|
output_asm_insn ("a\t%4,%8-%5(%4)", op);
|
| 9259 |
|
|
/* We cannot call through .plt, since .plt requires %r12 loaded. */
|
| 9260 |
|
|
else if (flag_pic == 1)
|
| 9261 |
|
|
{
|
| 9262 |
|
|
output_asm_insn ("a\t%4,%8-%5(%4)", op);
|
| 9263 |
|
|
output_asm_insn ("l\t%4,%0(%4)", op);
|
| 9264 |
|
|
}
|
| 9265 |
|
|
else if (flag_pic == 2)
|
| 9266 |
|
|
{
|
| 9267 |
|
|
op[9] = gen_rtx_REG (Pmode, 0);
|
| 9268 |
|
|
output_asm_insn ("l\t%9,%8-4-%5(%4)", op);
|
| 9269 |
|
|
output_asm_insn ("a\t%4,%8-%5(%4)", op);
|
| 9270 |
|
|
output_asm_insn ("ar\t%4,%9", op);
|
| 9271 |
|
|
output_asm_insn ("l\t%4,0(%4)", op);
|
| 9272 |
|
|
}
|
| 9273 |
|
|
|
| 9274 |
|
|
output_asm_insn ("br\t%4", op);
|
| 9275 |
|
|
|
| 9276 |
|
|
/* Output literal pool. */
|
| 9277 |
|
|
output_asm_insn (".align\t4", op);
|
| 9278 |
|
|
|
| 9279 |
|
|
if (nonlocal && flag_pic == 2)
|
| 9280 |
|
|
output_asm_insn (".long\t%0", op);
|
| 9281 |
|
|
if (nonlocal)
|
| 9282 |
|
|
{
|
| 9283 |
|
|
op[0] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
|
| 9284 |
|
|
SYMBOL_REF_FLAGS (op[0]) = SYMBOL_FLAG_LOCAL;
|
| 9285 |
|
|
}
|
| 9286 |
|
|
|
| 9287 |
|
|
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[8]));
|
| 9288 |
|
|
if (!flag_pic)
|
| 9289 |
|
|
output_asm_insn (".long\t%0", op);
|
| 9290 |
|
|
else
|
| 9291 |
|
|
output_asm_insn (".long\t%0-%5", op);
|
| 9292 |
|
|
|
| 9293 |
|
|
if (op[6])
|
| 9294 |
|
|
{
|
| 9295 |
|
|
targetm.asm_out.internal_label (file, "L",
|
| 9296 |
|
|
CODE_LABEL_NUMBER (op[6]));
|
| 9297 |
|
|
output_asm_insn (".long\t%2", op);
|
| 9298 |
|
|
}
|
| 9299 |
|
|
if (op[7])
|
| 9300 |
|
|
{
|
| 9301 |
|
|
targetm.asm_out.internal_label (file, "L",
|
| 9302 |
|
|
CODE_LABEL_NUMBER (op[7]));
|
| 9303 |
|
|
output_asm_insn (".long\t%3", op);
|
| 9304 |
|
|
}
|
| 9305 |
|
|
}
|
| 9306 |
|
|
final_end_function ();
|
| 9307 |
|
|
}
|
| 9308 |
|
|
|
| 9309 |
|
|
static bool
|
| 9310 |
|
|
s390_valid_pointer_mode (enum machine_mode mode)
|
| 9311 |
|
|
{
|
| 9312 |
|
|
return (mode == SImode || (TARGET_64BIT && mode == DImode));
|
| 9313 |
|
|
}
|
| 9314 |
|
|
|
| 9315 |
|
|
/* Checks whether the given CALL_EXPR would use a caller
|
| 9316 |
|
|
saved register. This is used to decide whether sibling call
|
| 9317 |
|
|
optimization could be performed on the respective function
|
| 9318 |
|
|
call. */
|
| 9319 |
|
|
|
| 9320 |
|
|
static bool
|
| 9321 |
|
|
s390_call_saved_register_used (tree call_expr)
|
| 9322 |
|
|
{
|
| 9323 |
|
|
CUMULATIVE_ARGS cum;
|
| 9324 |
|
|
tree parameter;
|
| 9325 |
|
|
enum machine_mode mode;
|
| 9326 |
|
|
tree type;
|
| 9327 |
|
|
rtx parm_rtx;
|
| 9328 |
|
|
int reg, i;
|
| 9329 |
|
|
|
| 9330 |
|
|
INIT_CUMULATIVE_ARGS (cum, NULL, NULL, 0, 0);
|
| 9331 |
|
|
|
| 9332 |
|
|
for (i = 0; i < call_expr_nargs (call_expr); i++)
|
| 9333 |
|
|
{
|
| 9334 |
|
|
parameter = CALL_EXPR_ARG (call_expr, i);
|
| 9335 |
|
|
gcc_assert (parameter);
|
| 9336 |
|
|
|
| 9337 |
|
|
/* For an undeclared variable passed as parameter we will get
|
| 9338 |
|
|
an ERROR_MARK node here. */
|
| 9339 |
|
|
if (TREE_CODE (parameter) == ERROR_MARK)
|
| 9340 |
|
|
return true;
|
| 9341 |
|
|
|
| 9342 |
|
|
type = TREE_TYPE (parameter);
|
| 9343 |
|
|
gcc_assert (type);
|
| 9344 |
|
|
|
| 9345 |
|
|
mode = TYPE_MODE (type);
|
| 9346 |
|
|
gcc_assert (mode);
|
| 9347 |
|
|
|
| 9348 |
|
|
if (pass_by_reference (&cum, mode, type, true))
|
| 9349 |
|
|
{
|
| 9350 |
|
|
mode = Pmode;
|
| 9351 |
|
|
type = build_pointer_type (type);
|
| 9352 |
|
|
}
|
| 9353 |
|
|
|
| 9354 |
|
|
parm_rtx = s390_function_arg (&cum, mode, type, 0);
|
| 9355 |
|
|
|
| 9356 |
|
|
s390_function_arg_advance (&cum, mode, type, 0);
|
| 9357 |
|
|
|
| 9358 |
|
|
if (parm_rtx && REG_P (parm_rtx))
|
| 9359 |
|
|
{
|
| 9360 |
|
|
for (reg = 0;
|
| 9361 |
|
|
reg < HARD_REGNO_NREGS (REGNO (parm_rtx), GET_MODE (parm_rtx));
|
| 9362 |
|
|
reg++)
|
| 9363 |
|
|
if (! call_used_regs[reg + REGNO (parm_rtx)])
|
| 9364 |
|
|
return true;
|
| 9365 |
|
|
}
|
| 9366 |
|
|
}
|
| 9367 |
|
|
return false;
|
| 9368 |
|
|
}
|
| 9369 |
|
|
|
| 9370 |
|
|
/* Return true if the given call expression can be
|
| 9371 |
|
|
turned into a sibling call.
|
| 9372 |
|
|
DECL holds the declaration of the function to be called whereas
|
| 9373 |
|
|
EXP is the call expression itself. */
|
| 9374 |
|
|
|
| 9375 |
|
|
static bool
|
| 9376 |
|
|
s390_function_ok_for_sibcall (tree decl, tree exp)
|
| 9377 |
|
|
{
|
| 9378 |
|
|
/* The TPF epilogue uses register 1. */
|
| 9379 |
|
|
if (TARGET_TPF_PROFILING)
|
| 9380 |
|
|
return false;
|
| 9381 |
|
|
|
| 9382 |
|
|
/* The 31 bit PLT code uses register 12 (GOT pointer - caller saved)
|
| 9383 |
|
|
which would have to be restored before the sibcall. */
|
| 9384 |
|
|
if (!TARGET_64BIT && flag_pic && decl && !targetm.binds_local_p (decl))
|
| 9385 |
|
|
return false;
|
| 9386 |
|
|
|
| 9387 |
|
|
/* Register 6 on s390 is available as an argument register but unfortunately
|
| 9388 |
|
|
"caller saved". This makes functions needing this register for arguments
|
| 9389 |
|
|
not suitable for sibcalls. */
|
| 9390 |
|
|
return !s390_call_saved_register_used (exp);
|
| 9391 |
|
|
}
|
| 9392 |
|
|
|
| 9393 |
|
|
/* Return the fixed registers used for condition codes. */
|
| 9394 |
|
|
|
| 9395 |
|
|
static bool
|
| 9396 |
|
|
s390_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
|
| 9397 |
|
|
{
|
| 9398 |
|
|
*p1 = CC_REGNUM;
|
| 9399 |
|
|
*p2 = INVALID_REGNUM;
|
| 9400 |
|
|
|
| 9401 |
|
|
return true;
|
| 9402 |
|
|
}
|
| 9403 |
|
|
|
| 9404 |
|
|
/* This function is used by the call expanders of the machine description.
|
| 9405 |
|
|
It emits the call insn itself together with the necessary operations
|
| 9406 |
|
|
to adjust the target address and returns the emitted insn.
|
| 9407 |
|
|
ADDR_LOCATION is the target address rtx
|
| 9408 |
|
|
TLS_CALL the location of the thread-local symbol
|
| 9409 |
|
|
RESULT_REG the register where the result of the call should be stored
|
| 9410 |
|
|
RETADDR_REG the register where the return address should be stored
|
| 9411 |
|
|
If this parameter is NULL_RTX the call is considered
|
| 9412 |
|
|
to be a sibling call. */
|
| 9413 |
|
|
|
| 9414 |
|
|
rtx
|
| 9415 |
|
|
s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg,
|
| 9416 |
|
|
rtx retaddr_reg)
|
| 9417 |
|
|
{
|
| 9418 |
|
|
bool plt_call = false;
|
| 9419 |
|
|
rtx insn;
|
| 9420 |
|
|
rtx call;
|
| 9421 |
|
|
rtx clobber;
|
| 9422 |
|
|
rtvec vec;
|
| 9423 |
|
|
|
| 9424 |
|
|
/* Direct function calls need special treatment. */
|
| 9425 |
|
|
if (GET_CODE (addr_location) == SYMBOL_REF)
|
| 9426 |
|
|
{
|
| 9427 |
|
|
/* When calling a global routine in PIC mode, we must
|
| 9428 |
|
|
replace the symbol itself with the PLT stub. */
|
| 9429 |
|
|
if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location))
|
| 9430 |
|
|
{
|
| 9431 |
|
|
if (retaddr_reg != NULL_RTX)
|
| 9432 |
|
|
{
|
| 9433 |
|
|
addr_location = gen_rtx_UNSPEC (Pmode,
|
| 9434 |
|
|
gen_rtvec (1, addr_location),
|
| 9435 |
|
|
UNSPEC_PLT);
|
| 9436 |
|
|
addr_location = gen_rtx_CONST (Pmode, addr_location);
|
| 9437 |
|
|
plt_call = true;
|
| 9438 |
|
|
}
|
| 9439 |
|
|
else
|
| 9440 |
|
|
/* For -fpic code the PLT entries might use r12 which is
|
| 9441 |
|
|
call-saved. Therefore we cannot do a sibcall when
|
| 9442 |
|
|
calling directly using a symbol ref. When reaching
|
| 9443 |
|
|
this point we decided (in s390_function_ok_for_sibcall)
|
| 9444 |
|
|
to do a sibcall for a function pointer but one of the
|
| 9445 |
|
|
optimizers was able to get rid of the function pointer
|
| 9446 |
|
|
by propagating the symbol ref into the call. This
|
| 9447 |
|
|
optimization is illegal for S/390 so we turn the direct
|
| 9448 |
|
|
call into a indirect call again. */
|
| 9449 |
|
|
addr_location = force_reg (Pmode, addr_location);
|
| 9450 |
|
|
}
|
| 9451 |
|
|
|
| 9452 |
|
|
/* Unless we can use the bras(l) insn, force the
|
| 9453 |
|
|
routine address into a register. */
|
| 9454 |
|
|
if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
|
| 9455 |
|
|
{
|
| 9456 |
|
|
if (flag_pic)
|
| 9457 |
|
|
addr_location = legitimize_pic_address (addr_location, 0);
|
| 9458 |
|
|
else
|
| 9459 |
|
|
addr_location = force_reg (Pmode, addr_location);
|
| 9460 |
|
|
}
|
| 9461 |
|
|
}
|
| 9462 |
|
|
|
| 9463 |
|
|
/* If it is already an indirect call or the code above moved the
|
| 9464 |
|
|
SYMBOL_REF to somewhere else make sure the address can be found in
|
| 9465 |
|
|
register 1. */
|
| 9466 |
|
|
if (retaddr_reg == NULL_RTX
|
| 9467 |
|
|
&& GET_CODE (addr_location) != SYMBOL_REF
|
| 9468 |
|
|
&& !plt_call)
|
| 9469 |
|
|
{
|
| 9470 |
|
|
emit_move_insn (gen_rtx_REG (Pmode, SIBCALL_REGNUM), addr_location);
|
| 9471 |
|
|
addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM);
|
| 9472 |
|
|
}
|
| 9473 |
|
|
|
| 9474 |
|
|
addr_location = gen_rtx_MEM (QImode, addr_location);
|
| 9475 |
|
|
call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx);
|
| 9476 |
|
|
|
| 9477 |
|
|
if (result_reg != NULL_RTX)
|
| 9478 |
|
|
call = gen_rtx_SET (VOIDmode, result_reg, call);
|
| 9479 |
|
|
|
| 9480 |
|
|
if (retaddr_reg != NULL_RTX)
|
| 9481 |
|
|
{
|
| 9482 |
|
|
clobber = gen_rtx_CLOBBER (VOIDmode, retaddr_reg);
|
| 9483 |
|
|
|
| 9484 |
|
|
if (tls_call != NULL_RTX)
|
| 9485 |
|
|
vec = gen_rtvec (3, call, clobber,
|
| 9486 |
|
|
gen_rtx_USE (VOIDmode, tls_call));
|
| 9487 |
|
|
else
|
| 9488 |
|
|
vec = gen_rtvec (2, call, clobber);
|
| 9489 |
|
|
|
| 9490 |
|
|
call = gen_rtx_PARALLEL (VOIDmode, vec);
|
| 9491 |
|
|
}
|
| 9492 |
|
|
|
| 9493 |
|
|
insn = emit_call_insn (call);
|
| 9494 |
|
|
|
| 9495 |
|
|
/* 31-bit PLT stubs and tls calls use the GOT register implicitly. */
|
| 9496 |
|
|
if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX)
|
| 9497 |
|
|
{
|
| 9498 |
|
|
/* s390_function_ok_for_sibcall should
|
| 9499 |
|
|
have denied sibcalls in this case. */
|
| 9500 |
|
|
gcc_assert (retaddr_reg != NULL_RTX);
|
| 9501 |
|
|
|
| 9502 |
|
|
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
|
| 9503 |
|
|
}
|
| 9504 |
|
|
return insn;
|
| 9505 |
|
|
}
|
| 9506 |
|
|
|
| 9507 |
|
|
/* Implement CONDITIONAL_REGISTER_USAGE. */
|
| 9508 |
|
|
|
| 9509 |
|
|
void
|
| 9510 |
|
|
s390_conditional_register_usage (void)
|
| 9511 |
|
|
{
|
| 9512 |
|
|
int i;
|
| 9513 |
|
|
|
| 9514 |
|
|
if (flag_pic)
|
| 9515 |
|
|
{
|
| 9516 |
|
|
fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
|
| 9517 |
|
|
call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
|
| 9518 |
|
|
}
|
| 9519 |
|
|
if (TARGET_CPU_ZARCH)
|
| 9520 |
|
|
{
|
| 9521 |
|
|
fixed_regs[BASE_REGNUM] = 0;
|
| 9522 |
|
|
call_used_regs[BASE_REGNUM] = 0;
|
| 9523 |
|
|
fixed_regs[RETURN_REGNUM] = 0;
|
| 9524 |
|
|
call_used_regs[RETURN_REGNUM] = 0;
|
| 9525 |
|
|
}
|
| 9526 |
|
|
if (TARGET_64BIT)
|
| 9527 |
|
|
{
|
| 9528 |
|
|
for (i = 24; i < 32; i++)
|
| 9529 |
|
|
call_used_regs[i] = call_really_used_regs[i] = 0;
|
| 9530 |
|
|
}
|
| 9531 |
|
|
else
|
| 9532 |
|
|
{
|
| 9533 |
|
|
for (i = 18; i < 20; i++)
|
| 9534 |
|
|
call_used_regs[i] = call_really_used_regs[i] = 0;
|
| 9535 |
|
|
}
|
| 9536 |
|
|
|
| 9537 |
|
|
if (TARGET_SOFT_FLOAT)
|
| 9538 |
|
|
{
|
| 9539 |
|
|
for (i = 16; i < 32; i++)
|
| 9540 |
|
|
call_used_regs[i] = fixed_regs[i] = 1;
|
| 9541 |
|
|
}
|
| 9542 |
|
|
}
|
| 9543 |
|
|
|
| 9544 |
|
|
/* Corresponding function to eh_return expander. */
|
| 9545 |
|
|
|
| 9546 |
|
|
static GTY(()) rtx s390_tpf_eh_return_symbol;
|
| 9547 |
|
|
void
|
| 9548 |
|
|
s390_emit_tpf_eh_return (rtx target)
|
| 9549 |
|
|
{
|
| 9550 |
|
|
rtx insn, reg;
|
| 9551 |
|
|
|
| 9552 |
|
|
if (!s390_tpf_eh_return_symbol)
|
| 9553 |
|
|
s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return");
|
| 9554 |
|
|
|
| 9555 |
|
|
reg = gen_rtx_REG (Pmode, 2);
|
| 9556 |
|
|
|
| 9557 |
|
|
emit_move_insn (reg, target);
|
| 9558 |
|
|
insn = s390_emit_call (s390_tpf_eh_return_symbol, NULL_RTX, reg,
|
| 9559 |
|
|
gen_rtx_REG (Pmode, RETURN_REGNUM));
|
| 9560 |
|
|
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg);
|
| 9561 |
|
|
|
| 9562 |
|
|
emit_move_insn (EH_RETURN_HANDLER_RTX, reg);
|
| 9563 |
|
|
}
|
| 9564 |
|
|
|
| 9565 |
|
|
/* Rework the prologue/epilogue to avoid saving/restoring
|
| 9566 |
|
|
registers unnecessarily. */
|
| 9567 |
|
|
|
| 9568 |
|
|
static void
|
| 9569 |
|
|
s390_optimize_prologue (void)
|
| 9570 |
|
|
{
|
| 9571 |
|
|
rtx insn, new_insn, next_insn;
|
| 9572 |
|
|
|
| 9573 |
|
|
/* Do a final recompute of the frame-related data. */
|
| 9574 |
|
|
|
| 9575 |
|
|
s390_update_frame_layout ();
|
| 9576 |
|
|
|
| 9577 |
|
|
/* If all special registers are in fact used, there's nothing we
|
| 9578 |
|
|
can do, so no point in walking the insn list. */
|
| 9579 |
|
|
|
| 9580 |
|
|
if (cfun_frame_layout.first_save_gpr <= BASE_REGNUM
|
| 9581 |
|
|
&& cfun_frame_layout.last_save_gpr >= BASE_REGNUM
|
| 9582 |
|
|
&& (TARGET_CPU_ZARCH
|
| 9583 |
|
|
|| (cfun_frame_layout.first_save_gpr <= RETURN_REGNUM
|
| 9584 |
|
|
&& cfun_frame_layout.last_save_gpr >= RETURN_REGNUM)))
|
| 9585 |
|
|
return;
|
| 9586 |
|
|
|
| 9587 |
|
|
/* Search for prologue/epilogue insns and replace them. */
|
| 9588 |
|
|
|
| 9589 |
|
|
for (insn = get_insns (); insn; insn = next_insn)
|
| 9590 |
|
|
{
|
| 9591 |
|
|
int first, last, off;
|
| 9592 |
|
|
rtx set, base, offset;
|
| 9593 |
|
|
|
| 9594 |
|
|
next_insn = NEXT_INSN (insn);
|
| 9595 |
|
|
|
| 9596 |
|
|
if (GET_CODE (insn) != INSN)
|
| 9597 |
|
|
continue;
|
| 9598 |
|
|
|
| 9599 |
|
|
if (GET_CODE (PATTERN (insn)) == PARALLEL
|
| 9600 |
|
|
&& store_multiple_operation (PATTERN (insn), VOIDmode))
|
| 9601 |
|
|
{
|
| 9602 |
|
|
set = XVECEXP (PATTERN (insn), 0, 0);
|
| 9603 |
|
|
first = REGNO (SET_SRC (set));
|
| 9604 |
|
|
last = first + XVECLEN (PATTERN (insn), 0) - 1;
|
| 9605 |
|
|
offset = const0_rtx;
|
| 9606 |
|
|
base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
|
| 9607 |
|
|
off = INTVAL (offset);
|
| 9608 |
|
|
|
| 9609 |
|
|
if (GET_CODE (base) != REG || off < 0)
|
| 9610 |
|
|
continue;
|
| 9611 |
|
|
if (cfun_frame_layout.first_save_gpr != -1
|
| 9612 |
|
|
&& (cfun_frame_layout.first_save_gpr < first
|
| 9613 |
|
|
|| cfun_frame_layout.last_save_gpr > last))
|
| 9614 |
|
|
continue;
|
| 9615 |
|
|
if (REGNO (base) != STACK_POINTER_REGNUM
|
| 9616 |
|
|
&& REGNO (base) != HARD_FRAME_POINTER_REGNUM)
|
| 9617 |
|
|
continue;
|
| 9618 |
|
|
if (first > BASE_REGNUM || last < BASE_REGNUM)
|
| 9619 |
|
|
continue;
|
| 9620 |
|
|
|
| 9621 |
|
|
if (cfun_frame_layout.first_save_gpr != -1)
|
| 9622 |
|
|
{
|
| 9623 |
|
|
new_insn = save_gprs (base,
|
| 9624 |
|
|
off + (cfun_frame_layout.first_save_gpr
|
| 9625 |
|
|
- first) * UNITS_PER_WORD,
|
| 9626 |
|
|
cfun_frame_layout.first_save_gpr,
|
| 9627 |
|
|
cfun_frame_layout.last_save_gpr);
|
| 9628 |
|
|
new_insn = emit_insn_before (new_insn, insn);
|
| 9629 |
|
|
INSN_ADDRESSES_NEW (new_insn, -1);
|
| 9630 |
|
|
}
|
| 9631 |
|
|
|
| 9632 |
|
|
remove_insn (insn);
|
| 9633 |
|
|
continue;
|
| 9634 |
|
|
}
|
| 9635 |
|
|
|
| 9636 |
|
|
if (cfun_frame_layout.first_save_gpr == -1
|
| 9637 |
|
|
&& GET_CODE (PATTERN (insn)) == SET
|
| 9638 |
|
|
&& GET_CODE (SET_SRC (PATTERN (insn))) == REG
|
| 9639 |
|
|
&& (REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM
|
| 9640 |
|
|
|| (!TARGET_CPU_ZARCH
|
| 9641 |
|
|
&& REGNO (SET_SRC (PATTERN (insn))) == RETURN_REGNUM))
|
| 9642 |
|
|
&& GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
|
| 9643 |
|
|
{
|
| 9644 |
|
|
set = PATTERN (insn);
|
| 9645 |
|
|
first = REGNO (SET_SRC (set));
|
| 9646 |
|
|
offset = const0_rtx;
|
| 9647 |
|
|
base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
|
| 9648 |
|
|
off = INTVAL (offset);
|
| 9649 |
|
|
|
| 9650 |
|
|
if (GET_CODE (base) != REG || off < 0)
|
| 9651 |
|
|
continue;
|
| 9652 |
|
|
if (REGNO (base) != STACK_POINTER_REGNUM
|
| 9653 |
|
|
&& REGNO (base) != HARD_FRAME_POINTER_REGNUM)
|
| 9654 |
|
|
continue;
|
| 9655 |
|
|
|
| 9656 |
|
|
remove_insn (insn);
|
| 9657 |
|
|
continue;
|
| 9658 |
|
|
}
|
| 9659 |
|
|
|
| 9660 |
|
|
if (GET_CODE (PATTERN (insn)) == PARALLEL
|
| 9661 |
|
|
&& load_multiple_operation (PATTERN (insn), VOIDmode))
|
| 9662 |
|
|
{
|
| 9663 |
|
|
set = XVECEXP (PATTERN (insn), 0, 0);
|
| 9664 |
|
|
first = REGNO (SET_DEST (set));
|
| 9665 |
|
|
last = first + XVECLEN (PATTERN (insn), 0) - 1;
|
| 9666 |
|
|
offset = const0_rtx;
|
| 9667 |
|
|
base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
|
| 9668 |
|
|
off = INTVAL (offset);
|
| 9669 |
|
|
|
| 9670 |
|
|
if (GET_CODE (base) != REG || off < 0)
|
| 9671 |
|
|
continue;
|
| 9672 |
|
|
if (cfun_frame_layout.first_restore_gpr != -1
|
| 9673 |
|
|
&& (cfun_frame_layout.first_restore_gpr < first
|
| 9674 |
|
|
|| cfun_frame_layout.last_restore_gpr > last))
|
| 9675 |
|
|
continue;
|
| 9676 |
|
|
if (REGNO (base) != STACK_POINTER_REGNUM
|
| 9677 |
|
|
&& REGNO (base) != HARD_FRAME_POINTER_REGNUM)
|
| 9678 |
|
|
continue;
|
| 9679 |
|
|
if (first > BASE_REGNUM || last < BASE_REGNUM)
|
| 9680 |
|
|
continue;
|
| 9681 |
|
|
|
| 9682 |
|
|
if (cfun_frame_layout.first_restore_gpr != -1)
|
| 9683 |
|
|
{
|
| 9684 |
|
|
new_insn = restore_gprs (base,
|
| 9685 |
|
|
off + (cfun_frame_layout.first_restore_gpr
|
| 9686 |
|
|
- first) * UNITS_PER_WORD,
|
| 9687 |
|
|
cfun_frame_layout.first_restore_gpr,
|
| 9688 |
|
|
cfun_frame_layout.last_restore_gpr);
|
| 9689 |
|
|
new_insn = emit_insn_before (new_insn, insn);
|
| 9690 |
|
|
INSN_ADDRESSES_NEW (new_insn, -1);
|
| 9691 |
|
|
}
|
| 9692 |
|
|
|
| 9693 |
|
|
remove_insn (insn);
|
| 9694 |
|
|
continue;
|
| 9695 |
|
|
}
|
| 9696 |
|
|
|
| 9697 |
|
|
if (cfun_frame_layout.first_restore_gpr == -1
|
| 9698 |
|
|
&& GET_CODE (PATTERN (insn)) == SET
|
| 9699 |
|
|
&& GET_CODE (SET_DEST (PATTERN (insn))) == REG
|
| 9700 |
|
|
&& (REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM
|
| 9701 |
|
|
|| (!TARGET_CPU_ZARCH
|
| 9702 |
|
|
&& REGNO (SET_DEST (PATTERN (insn))) == RETURN_REGNUM))
|
| 9703 |
|
|
&& GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
|
| 9704 |
|
|
{
|
| 9705 |
|
|
set = PATTERN (insn);
|
| 9706 |
|
|
first = REGNO (SET_DEST (set));
|
| 9707 |
|
|
offset = const0_rtx;
|
| 9708 |
|
|
base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
|
| 9709 |
|
|
off = INTVAL (offset);
|
| 9710 |
|
|
|
| 9711 |
|
|
if (GET_CODE (base) != REG || off < 0)
|
| 9712 |
|
|
continue;
|
| 9713 |
|
|
if (REGNO (base) != STACK_POINTER_REGNUM
|
| 9714 |
|
|
&& REGNO (base) != HARD_FRAME_POINTER_REGNUM)
|
| 9715 |
|
|
continue;
|
| 9716 |
|
|
|
| 9717 |
|
|
remove_insn (insn);
|
| 9718 |
|
|
continue;
|
| 9719 |
|
|
}
|
| 9720 |
|
|
}
|
| 9721 |
|
|
}
|
| 9722 |
|
|
|
| 9723 |
|
|
/* On z10 the dynamic branch prediction must see the backward jump in
|
| 9724 |
|
|
a window of 384 bytes. If not it falls back to the static
|
| 9725 |
|
|
prediction. This function rearranges the loop backward branch in a
|
| 9726 |
|
|
way which makes the static prediction always correct. The function
|
| 9727 |
|
|
returns true if it added an instruction. */
|
| 9728 |
|
|
static bool
|
| 9729 |
|
|
s390_z10_fix_long_loop_prediction (rtx insn)
|
| 9730 |
|
|
{
|
| 9731 |
|
|
rtx set = single_set (insn);
|
| 9732 |
|
|
rtx code_label, label_ref, new_label;
|
| 9733 |
|
|
rtx uncond_jump;
|
| 9734 |
|
|
rtx cur_insn;
|
| 9735 |
|
|
rtx tmp;
|
| 9736 |
|
|
int distance;
|
| 9737 |
|
|
|
| 9738 |
|
|
/* This will exclude branch on count and branch on index patterns
|
| 9739 |
|
|
since these are correctly statically predicted. */
|
| 9740 |
|
|
if (!set
|
| 9741 |
|
|
|| SET_DEST (set) != pc_rtx
|
| 9742 |
|
|
|| GET_CODE (SET_SRC(set)) != IF_THEN_ELSE)
|
| 9743 |
|
|
return false;
|
| 9744 |
|
|
|
| 9745 |
|
|
label_ref = (GET_CODE (XEXP (SET_SRC (set), 1)) == LABEL_REF ?
|
| 9746 |
|
|
XEXP (SET_SRC (set), 1) : XEXP (SET_SRC (set), 2));
|
| 9747 |
|
|
|
| 9748 |
|
|
gcc_assert (GET_CODE (label_ref) == LABEL_REF);
|
| 9749 |
|
|
|
| 9750 |
|
|
code_label = XEXP (label_ref, 0);
|
| 9751 |
|
|
|
| 9752 |
|
|
if (INSN_ADDRESSES (INSN_UID (code_label)) == -1
|
| 9753 |
|
|
|| INSN_ADDRESSES (INSN_UID (insn)) == -1
|
| 9754 |
|
|
|| (INSN_ADDRESSES (INSN_UID (insn))
|
| 9755 |
|
|
- INSN_ADDRESSES (INSN_UID (code_label)) < Z10_PREDICT_DISTANCE))
|
| 9756 |
|
|
return false;
|
| 9757 |
|
|
|
| 9758 |
|
|
for (distance = 0, cur_insn = PREV_INSN (insn);
|
| 9759 |
|
|
distance < Z10_PREDICT_DISTANCE - 6;
|
| 9760 |
|
|
distance += get_attr_length (cur_insn), cur_insn = PREV_INSN (cur_insn))
|
| 9761 |
|
|
if (!cur_insn || JUMP_P (cur_insn) || LABEL_P (cur_insn))
|
| 9762 |
|
|
return false;
|
| 9763 |
|
|
|
| 9764 |
|
|
new_label = gen_label_rtx ();
|
| 9765 |
|
|
uncond_jump = emit_jump_insn_after (
|
| 9766 |
|
|
gen_rtx_SET (VOIDmode, pc_rtx,
|
| 9767 |
|
|
gen_rtx_LABEL_REF (VOIDmode, code_label)),
|
| 9768 |
|
|
insn);
|
| 9769 |
|
|
emit_label_after (new_label, uncond_jump);
|
| 9770 |
|
|
|
| 9771 |
|
|
tmp = XEXP (SET_SRC (set), 1);
|
| 9772 |
|
|
XEXP (SET_SRC (set), 1) = XEXP (SET_SRC (set), 2);
|
| 9773 |
|
|
XEXP (SET_SRC (set), 2) = tmp;
|
| 9774 |
|
|
INSN_CODE (insn) = -1;
|
| 9775 |
|
|
|
| 9776 |
|
|
XEXP (label_ref, 0) = new_label;
|
| 9777 |
|
|
JUMP_LABEL (insn) = new_label;
|
| 9778 |
|
|
JUMP_LABEL (uncond_jump) = code_label;
|
| 9779 |
|
|
|
| 9780 |
|
|
return true;
|
| 9781 |
|
|
}
|
| 9782 |
|
|
|
| 9783 |
|
|
/* Returns 1 if INSN reads the value of REG for purposes not related
|
| 9784 |
|
|
to addressing of memory, and 0 otherwise. */
|
| 9785 |
|
|
static int
|
| 9786 |
|
|
s390_non_addr_reg_read_p (rtx reg, rtx insn)
|
| 9787 |
|
|
{
|
| 9788 |
|
|
return reg_referenced_p (reg, PATTERN (insn))
|
| 9789 |
|
|
&& !reg_used_in_mem_p (REGNO (reg), PATTERN (insn));
|
| 9790 |
|
|
}
|
| 9791 |
|
|
|
| 9792 |
|
|
/* Starting from INSN find_cond_jump looks downwards in the insn
|
| 9793 |
|
|
stream for a single jump insn which is the last user of the
|
| 9794 |
|
|
condition code set in INSN. */
|
| 9795 |
|
|
static rtx
|
| 9796 |
|
|
find_cond_jump (rtx insn)
|
| 9797 |
|
|
{
|
| 9798 |
|
|
for (; insn; insn = NEXT_INSN (insn))
|
| 9799 |
|
|
{
|
| 9800 |
|
|
rtx ite, cc;
|
| 9801 |
|
|
|
| 9802 |
|
|
if (LABEL_P (insn))
|
| 9803 |
|
|
break;
|
| 9804 |
|
|
|
| 9805 |
|
|
if (!JUMP_P (insn))
|
| 9806 |
|
|
{
|
| 9807 |
|
|
if (reg_mentioned_p (gen_rtx_REG (CCmode, CC_REGNUM), insn))
|
| 9808 |
|
|
break;
|
| 9809 |
|
|
continue;
|
| 9810 |
|
|
}
|
| 9811 |
|
|
|
| 9812 |
|
|
/* This will be triggered by a return. */
|
| 9813 |
|
|
if (GET_CODE (PATTERN (insn)) != SET)
|
| 9814 |
|
|
break;
|
| 9815 |
|
|
|
| 9816 |
|
|
gcc_assert (SET_DEST (PATTERN (insn)) == pc_rtx);
|
| 9817 |
|
|
ite = SET_SRC (PATTERN (insn));
|
| 9818 |
|
|
|
| 9819 |
|
|
if (GET_CODE (ite) != IF_THEN_ELSE)
|
| 9820 |
|
|
break;
|
| 9821 |
|
|
|
| 9822 |
|
|
cc = XEXP (XEXP (ite, 0), 0);
|
| 9823 |
|
|
if (!REG_P (cc) || !CC_REGNO_P (REGNO (cc)))
|
| 9824 |
|
|
break;
|
| 9825 |
|
|
|
| 9826 |
|
|
if (find_reg_note (insn, REG_DEAD, cc))
|
| 9827 |
|
|
return insn;
|
| 9828 |
|
|
break;
|
| 9829 |
|
|
}
|
| 9830 |
|
|
|
| 9831 |
|
|
return NULL_RTX;
|
| 9832 |
|
|
}
|
| 9833 |
|
|
|
| 9834 |
|
|
/* Swap the condition in COND and the operands in OP0 and OP1 so that
|
| 9835 |
|
|
the semantics does not change. If NULL_RTX is passed as COND the
|
| 9836 |
|
|
function tries to find the conditional jump starting with INSN. */
|
| 9837 |
|
|
static void
|
| 9838 |
|
|
s390_swap_cmp (rtx cond, rtx *op0, rtx *op1, rtx insn)
|
| 9839 |
|
|
{
|
| 9840 |
|
|
rtx tmp = *op0;
|
| 9841 |
|
|
|
| 9842 |
|
|
if (cond == NULL_RTX)
|
| 9843 |
|
|
{
|
| 9844 |
|
|
rtx jump = find_cond_jump (NEXT_INSN (insn));
|
| 9845 |
|
|
jump = jump ? single_set (jump) : NULL_RTX;
|
| 9846 |
|
|
|
| 9847 |
|
|
if (jump == NULL_RTX)
|
| 9848 |
|
|
return;
|
| 9849 |
|
|
|
| 9850 |
|
|
cond = XEXP (XEXP (jump, 1), 0);
|
| 9851 |
|
|
}
|
| 9852 |
|
|
|
| 9853 |
|
|
*op0 = *op1;
|
| 9854 |
|
|
*op1 = tmp;
|
| 9855 |
|
|
PUT_CODE (cond, swap_condition (GET_CODE (cond)));
|
| 9856 |
|
|
}
|
| 9857 |
|
|
|
| 9858 |
|
|
/* On z10, instructions of the compare-and-branch family have the
|
| 9859 |
|
|
property to access the register occurring as second operand with
|
| 9860 |
|
|
its bits complemented. If such a compare is grouped with a second
|
| 9861 |
|
|
instruction that accesses the same register non-complemented, and
|
| 9862 |
|
|
if that register's value is delivered via a bypass, then the
|
| 9863 |
|
|
pipeline recycles, thereby causing significant performance decline.
|
| 9864 |
|
|
This function locates such situations and exchanges the two
|
| 9865 |
|
|
operands of the compare. The function return true whenever it
|
| 9866 |
|
|
added an insn. */
|
| 9867 |
|
|
static bool
|
| 9868 |
|
|
s390_z10_optimize_cmp (rtx insn)
|
| 9869 |
|
|
{
|
| 9870 |
|
|
rtx prev_insn, next_insn;
|
| 9871 |
|
|
bool insn_added_p = false;
|
| 9872 |
|
|
rtx cond, *op0, *op1;
|
| 9873 |
|
|
|
| 9874 |
|
|
if (GET_CODE (PATTERN (insn)) == PARALLEL)
|
| 9875 |
|
|
{
|
| 9876 |
|
|
/* Handle compare and branch and branch on count
|
| 9877 |
|
|
instructions. */
|
| 9878 |
|
|
rtx pattern = single_set (insn);
|
| 9879 |
|
|
|
| 9880 |
|
|
if (!pattern
|
| 9881 |
|
|
|| SET_DEST (pattern) != pc_rtx
|
| 9882 |
|
|
|| GET_CODE (SET_SRC (pattern)) != IF_THEN_ELSE)
|
| 9883 |
|
|
return false;
|
| 9884 |
|
|
|
| 9885 |
|
|
cond = XEXP (SET_SRC (pattern), 0);
|
| 9886 |
|
|
op0 = &XEXP (cond, 0);
|
| 9887 |
|
|
op1 = &XEXP (cond, 1);
|
| 9888 |
|
|
}
|
| 9889 |
|
|
else if (GET_CODE (PATTERN (insn)) == SET)
|
| 9890 |
|
|
{
|
| 9891 |
|
|
rtx src, dest;
|
| 9892 |
|
|
|
| 9893 |
|
|
/* Handle normal compare instructions. */
|
| 9894 |
|
|
src = SET_SRC (PATTERN (insn));
|
| 9895 |
|
|
dest = SET_DEST (PATTERN (insn));
|
| 9896 |
|
|
|
| 9897 |
|
|
if (!REG_P (dest)
|
| 9898 |
|
|
|| !CC_REGNO_P (REGNO (dest))
|
| 9899 |
|
|
|| GET_CODE (src) != COMPARE)
|
| 9900 |
|
|
return false;
|
| 9901 |
|
|
|
| 9902 |
|
|
/* s390_swap_cmp will try to find the conditional
|
| 9903 |
|
|
jump when passing NULL_RTX as condition. */
|
| 9904 |
|
|
cond = NULL_RTX;
|
| 9905 |
|
|
op0 = &XEXP (src, 0);
|
| 9906 |
|
|
op1 = &XEXP (src, 1);
|
| 9907 |
|
|
}
|
| 9908 |
|
|
else
|
| 9909 |
|
|
return false;
|
| 9910 |
|
|
|
| 9911 |
|
|
if (!REG_P (*op0) || !REG_P (*op1))
|
| 9912 |
|
|
return false;
|
| 9913 |
|
|
|
| 9914 |
|
|
if (GET_MODE_CLASS (GET_MODE (*op0)) != MODE_INT)
|
| 9915 |
|
|
return false;
|
| 9916 |
|
|
|
| 9917 |
|
|
/* Swap the COMPARE arguments and its mask if there is a
|
| 9918 |
|
|
conflicting access in the previous insn. */
|
| 9919 |
|
|
prev_insn = prev_active_insn (insn);
|
| 9920 |
|
|
if (prev_insn != NULL_RTX && INSN_P (prev_insn)
|
| 9921 |
|
|
&& reg_referenced_p (*op1, PATTERN (prev_insn)))
|
| 9922 |
|
|
s390_swap_cmp (cond, op0, op1, insn);
|
| 9923 |
|
|
|
| 9924 |
|
|
/* Check if there is a conflict with the next insn. If there
|
| 9925 |
|
|
was no conflict with the previous insn, then swap the
|
| 9926 |
|
|
COMPARE arguments and its mask. If we already swapped
|
| 9927 |
|
|
the operands, or if swapping them would cause a conflict
|
| 9928 |
|
|
with the previous insn, issue a NOP after the COMPARE in
|
| 9929 |
|
|
order to separate the two instuctions. */
|
| 9930 |
|
|
next_insn = next_active_insn (insn);
|
| 9931 |
|
|
if (next_insn != NULL_RTX && INSN_P (next_insn)
|
| 9932 |
|
|
&& s390_non_addr_reg_read_p (*op1, next_insn))
|
| 9933 |
|
|
{
|
| 9934 |
|
|
if (prev_insn != NULL_RTX && INSN_P (prev_insn)
|
| 9935 |
|
|
&& s390_non_addr_reg_read_p (*op0, prev_insn))
|
| 9936 |
|
|
{
|
| 9937 |
|
|
if (REGNO (*op1) == 0)
|
| 9938 |
|
|
emit_insn_after (gen_nop1 (), insn);
|
| 9939 |
|
|
else
|
| 9940 |
|
|
emit_insn_after (gen_nop (), insn);
|
| 9941 |
|
|
insn_added_p = true;
|
| 9942 |
|
|
}
|
| 9943 |
|
|
else
|
| 9944 |
|
|
s390_swap_cmp (cond, op0, op1, insn);
|
| 9945 |
|
|
}
|
| 9946 |
|
|
return insn_added_p;
|
| 9947 |
|
|
}
|
| 9948 |
|
|
|
| 9949 |
|
|
/* Perform machine-dependent processing. */
|
| 9950 |
|
|
|
| 9951 |
|
|
static void
|
| 9952 |
|
|
s390_reorg (void)
|
| 9953 |
|
|
{
|
| 9954 |
|
|
bool pool_overflow = false;
|
| 9955 |
|
|
|
| 9956 |
|
|
/* Make sure all splits have been performed; splits after
|
| 9957 |
|
|
machine_dependent_reorg might confuse insn length counts. */
|
| 9958 |
|
|
split_all_insns_noflow ();
|
| 9959 |
|
|
|
| 9960 |
|
|
/* Install the main literal pool and the associated base
|
| 9961 |
|
|
register load insns.
|
| 9962 |
|
|
|
| 9963 |
|
|
In addition, there are two problematic situations we need
|
| 9964 |
|
|
to correct:
|
| 9965 |
|
|
|
| 9966 |
|
|
- the literal pool might be > 4096 bytes in size, so that
|
| 9967 |
|
|
some of its elements cannot be directly accessed
|
| 9968 |
|
|
|
| 9969 |
|
|
- a branch target might be > 64K away from the branch, so that
|
| 9970 |
|
|
it is not possible to use a PC-relative instruction.
|
| 9971 |
|
|
|
| 9972 |
|
|
To fix those, we split the single literal pool into multiple
|
| 9973 |
|
|
pool chunks, reloading the pool base register at various
|
| 9974 |
|
|
points throughout the function to ensure it always points to
|
| 9975 |
|
|
the pool chunk the following code expects, and / or replace
|
| 9976 |
|
|
PC-relative branches by absolute branches.
|
| 9977 |
|
|
|
| 9978 |
|
|
However, the two problems are interdependent: splitting the
|
| 9979 |
|
|
literal pool can move a branch further away from its target,
|
| 9980 |
|
|
causing the 64K limit to overflow, and on the other hand,
|
| 9981 |
|
|
replacing a PC-relative branch by an absolute branch means
|
| 9982 |
|
|
we need to put the branch target address into the literal
|
| 9983 |
|
|
pool, possibly causing it to overflow.
|
| 9984 |
|
|
|
| 9985 |
|
|
So, we loop trying to fix up both problems until we manage
|
| 9986 |
|
|
to satisfy both conditions at the same time. Note that the
|
| 9987 |
|
|
loop is guaranteed to terminate as every pass of the loop
|
| 9988 |
|
|
strictly decreases the total number of PC-relative branches
|
| 9989 |
|
|
in the function. (This is not completely true as there
|
| 9990 |
|
|
might be branch-over-pool insns introduced by chunkify_start.
|
| 9991 |
|
|
Those never need to be split however.) */
|
| 9992 |
|
|
|
| 9993 |
|
|
for (;;)
|
| 9994 |
|
|
{
|
| 9995 |
|
|
struct constant_pool *pool = NULL;
|
| 9996 |
|
|
|
| 9997 |
|
|
/* Collect the literal pool. */
|
| 9998 |
|
|
if (!pool_overflow)
|
| 9999 |
|
|
{
|
| 10000 |
|
|
pool = s390_mainpool_start ();
|
| 10001 |
|
|
if (!pool)
|
| 10002 |
|
|
pool_overflow = true;
|
| 10003 |
|
|
}
|
| 10004 |
|
|
|
| 10005 |
|
|
/* If literal pool overflowed, start to chunkify it. */
|
| 10006 |
|
|
if (pool_overflow)
|
| 10007 |
|
|
pool = s390_chunkify_start ();
|
| 10008 |
|
|
|
| 10009 |
|
|
/* Split out-of-range branches. If this has created new
|
| 10010 |
|
|
literal pool entries, cancel current chunk list and
|
| 10011 |
|
|
recompute it. zSeries machines have large branch
|
| 10012 |
|
|
instructions, so we never need to split a branch. */
|
| 10013 |
|
|
if (!TARGET_CPU_ZARCH && s390_split_branches ())
|
| 10014 |
|
|
{
|
| 10015 |
|
|
if (pool_overflow)
|
| 10016 |
|
|
s390_chunkify_cancel (pool);
|
| 10017 |
|
|
else
|
| 10018 |
|
|
s390_mainpool_cancel (pool);
|
| 10019 |
|
|
|
| 10020 |
|
|
continue;
|
| 10021 |
|
|
}
|
| 10022 |
|
|
|
| 10023 |
|
|
/* If we made it up to here, both conditions are satisfied.
|
| 10024 |
|
|
Finish up literal pool related changes. */
|
| 10025 |
|
|
if (pool_overflow)
|
| 10026 |
|
|
s390_chunkify_finish (pool);
|
| 10027 |
|
|
else
|
| 10028 |
|
|
s390_mainpool_finish (pool);
|
| 10029 |
|
|
|
| 10030 |
|
|
/* We're done splitting branches. */
|
| 10031 |
|
|
cfun->machine->split_branches_pending_p = false;
|
| 10032 |
|
|
break;
|
| 10033 |
|
|
}
|
| 10034 |
|
|
|
| 10035 |
|
|
/* Generate out-of-pool execute target insns. */
|
| 10036 |
|
|
if (TARGET_CPU_ZARCH)
|
| 10037 |
|
|
{
|
| 10038 |
|
|
rtx insn, label, target;
|
| 10039 |
|
|
|
| 10040 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 10041 |
|
|
{
|
| 10042 |
|
|
label = s390_execute_label (insn);
|
| 10043 |
|
|
if (!label)
|
| 10044 |
|
|
continue;
|
| 10045 |
|
|
|
| 10046 |
|
|
gcc_assert (label != const0_rtx);
|
| 10047 |
|
|
|
| 10048 |
|
|
target = emit_label (XEXP (label, 0));
|
| 10049 |
|
|
INSN_ADDRESSES_NEW (target, -1);
|
| 10050 |
|
|
|
| 10051 |
|
|
target = emit_insn (s390_execute_target (insn));
|
| 10052 |
|
|
INSN_ADDRESSES_NEW (target, -1);
|
| 10053 |
|
|
}
|
| 10054 |
|
|
}
|
| 10055 |
|
|
|
| 10056 |
|
|
/* Try to optimize prologue and epilogue further. */
|
| 10057 |
|
|
s390_optimize_prologue ();
|
| 10058 |
|
|
|
| 10059 |
|
|
/* Walk over the insns and do some z10 specific changes. */
|
| 10060 |
|
|
if (s390_tune == PROCESSOR_2097_Z10)
|
| 10061 |
|
|
{
|
| 10062 |
|
|
rtx insn;
|
| 10063 |
|
|
bool insn_added_p = false;
|
| 10064 |
|
|
|
| 10065 |
|
|
/* The insn lengths and addresses have to be up to date for the
|
| 10066 |
|
|
following manipulations. */
|
| 10067 |
|
|
shorten_branches (get_insns ());
|
| 10068 |
|
|
|
| 10069 |
|
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
| 10070 |
|
|
{
|
| 10071 |
|
|
if (!INSN_P (insn) || INSN_CODE (insn) <= 0)
|
| 10072 |
|
|
continue;
|
| 10073 |
|
|
|
| 10074 |
|
|
if (JUMP_P (insn))
|
| 10075 |
|
|
insn_added_p |= s390_z10_fix_long_loop_prediction (insn);
|
| 10076 |
|
|
|
| 10077 |
|
|
if (GET_CODE (PATTERN (insn)) == PARALLEL
|
| 10078 |
|
|
|| GET_CODE (PATTERN (insn)) == SET)
|
| 10079 |
|
|
insn_added_p |= s390_z10_optimize_cmp (insn);
|
| 10080 |
|
|
}
|
| 10081 |
|
|
|
| 10082 |
|
|
/* Adjust branches if we added new instructions. */
|
| 10083 |
|
|
if (insn_added_p)
|
| 10084 |
|
|
shorten_branches (get_insns ());
|
| 10085 |
|
|
}
|
| 10086 |
|
|
}
|
| 10087 |
|
|
|
| 10088 |
|
|
/* Return true if INSN is a fp load insn writing register REGNO. */
|
| 10089 |
|
|
static inline bool
|
| 10090 |
|
|
s390_fpload_toreg (rtx insn, unsigned int regno)
|
| 10091 |
|
|
{
|
| 10092 |
|
|
rtx set;
|
| 10093 |
|
|
enum attr_type flag = s390_safe_attr_type (insn);
|
| 10094 |
|
|
|
| 10095 |
|
|
if (flag != TYPE_FLOADSF && flag != TYPE_FLOADDF)
|
| 10096 |
|
|
return false;
|
| 10097 |
|
|
|
| 10098 |
|
|
set = single_set (insn);
|
| 10099 |
|
|
|
| 10100 |
|
|
if (set == NULL_RTX)
|
| 10101 |
|
|
return false;
|
| 10102 |
|
|
|
| 10103 |
|
|
if (!REG_P (SET_DEST (set)) || !MEM_P (SET_SRC (set)))
|
| 10104 |
|
|
return false;
|
| 10105 |
|
|
|
| 10106 |
|
|
if (REGNO (SET_DEST (set)) != regno)
|
| 10107 |
|
|
return false;
|
| 10108 |
|
|
|
| 10109 |
|
|
return true;
|
| 10110 |
|
|
}
|
| 10111 |
|
|
|
| 10112 |
|
|
/* This value describes the distance to be avoided between an
|
| 10113 |
|
|
aritmetic fp instruction and an fp load writing the same register.
|
| 10114 |
|
|
Z10_EARLYLOAD_DISTANCE - 1 as well as Z10_EARLYLOAD_DISTANCE + 1 is
|
| 10115 |
|
|
fine but the exact value has to be avoided. Otherwise the FP
|
| 10116 |
|
|
pipeline will throw an exception causing a major penalty. */
|
| 10117 |
|
|
#define Z10_EARLYLOAD_DISTANCE 7
|
| 10118 |
|
|
|
| 10119 |
|
|
/* Rearrange the ready list in order to avoid the situation described
|
| 10120 |
|
|
for Z10_EARLYLOAD_DISTANCE. A problematic load instruction is
|
| 10121 |
|
|
moved to the very end of the ready list. */
|
| 10122 |
|
|
static void
|
| 10123 |
|
|
s390_z10_prevent_earlyload_conflicts (rtx *ready, int *nready_p)
|
| 10124 |
|
|
{
|
| 10125 |
|
|
unsigned int regno;
|
| 10126 |
|
|
int nready = *nready_p;
|
| 10127 |
|
|
rtx tmp;
|
| 10128 |
|
|
int i;
|
| 10129 |
|
|
rtx insn;
|
| 10130 |
|
|
rtx set;
|
| 10131 |
|
|
enum attr_type flag;
|
| 10132 |
|
|
int distance;
|
| 10133 |
|
|
|
| 10134 |
|
|
/* Skip DISTANCE - 1 active insns. */
|
| 10135 |
|
|
for (insn = last_scheduled_insn, distance = Z10_EARLYLOAD_DISTANCE - 1;
|
| 10136 |
|
|
distance > 0 && insn != NULL_RTX;
|
| 10137 |
|
|
distance--, insn = prev_active_insn (insn))
|
| 10138 |
|
|
if (CALL_P (insn) || JUMP_P (insn))
|
| 10139 |
|
|
return;
|
| 10140 |
|
|
|
| 10141 |
|
|
if (insn == NULL_RTX)
|
| 10142 |
|
|
return;
|
| 10143 |
|
|
|
| 10144 |
|
|
set = single_set (insn);
|
| 10145 |
|
|
|
| 10146 |
|
|
if (set == NULL_RTX || !REG_P (SET_DEST (set))
|
| 10147 |
|
|
|| GET_MODE_CLASS (GET_MODE (SET_DEST (set))) != MODE_FLOAT)
|
| 10148 |
|
|
return;
|
| 10149 |
|
|
|
| 10150 |
|
|
flag = s390_safe_attr_type (insn);
|
| 10151 |
|
|
|
| 10152 |
|
|
if (flag == TYPE_FLOADSF || flag == TYPE_FLOADDF)
|
| 10153 |
|
|
return;
|
| 10154 |
|
|
|
| 10155 |
|
|
regno = REGNO (SET_DEST (set));
|
| 10156 |
|
|
i = nready - 1;
|
| 10157 |
|
|
|
| 10158 |
|
|
while (!s390_fpload_toreg (ready[i], regno) && i > 0)
|
| 10159 |
|
|
i--;
|
| 10160 |
|
|
|
| 10161 |
|
|
if (!i)
|
| 10162 |
|
|
return;
|
| 10163 |
|
|
|
| 10164 |
|
|
tmp = ready[i];
|
| 10165 |
|
|
memmove (&ready[1], &ready[0], sizeof (rtx) * i);
|
| 10166 |
|
|
ready[0] = tmp;
|
| 10167 |
|
|
}
|
| 10168 |
|
|
|
| 10169 |
|
|
/* This function is called via hook TARGET_SCHED_REORDER before
|
| 10170 |
|
|
issueing one insn from list READY which contains *NREADYP entries.
|
| 10171 |
|
|
For target z10 it reorders load instructions to avoid early load
|
| 10172 |
|
|
conflicts in the floating point pipeline */
|
| 10173 |
|
|
static int
|
| 10174 |
|
|
s390_sched_reorder (FILE *file ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
|
| 10175 |
|
|
rtx *ready, int *nreadyp, int clock ATTRIBUTE_UNUSED)
|
| 10176 |
|
|
{
|
| 10177 |
|
|
if (s390_tune == PROCESSOR_2097_Z10)
|
| 10178 |
|
|
if (reload_completed && *nreadyp > 1)
|
| 10179 |
|
|
s390_z10_prevent_earlyload_conflicts (ready, nreadyp);
|
| 10180 |
|
|
|
| 10181 |
|
|
return s390_issue_rate ();
|
| 10182 |
|
|
}
|
| 10183 |
|
|
|
| 10184 |
|
|
/* This function is called via hook TARGET_SCHED_VARIABLE_ISSUE after
|
| 10185 |
|
|
the scheduler has issued INSN. It stores the last issued insn into
|
| 10186 |
|
|
last_scheduled_insn in order to make it available for
|
| 10187 |
|
|
s390_sched_reorder. */
|
| 10188 |
|
|
static int
|
| 10189 |
|
|
s390_sched_variable_issue (FILE *file ATTRIBUTE_UNUSED,
|
| 10190 |
|
|
int verbose ATTRIBUTE_UNUSED,
|
| 10191 |
|
|
rtx insn, int more)
|
| 10192 |
|
|
{
|
| 10193 |
|
|
last_scheduled_insn = insn;
|
| 10194 |
|
|
|
| 10195 |
|
|
if (GET_CODE (PATTERN (insn)) != USE
|
| 10196 |
|
|
&& GET_CODE (PATTERN (insn)) != CLOBBER)
|
| 10197 |
|
|
return more - 1;
|
| 10198 |
|
|
else
|
| 10199 |
|
|
return more;
|
| 10200 |
|
|
}
|
| 10201 |
|
|
|
| 10202 |
|
|
static void
|
| 10203 |
|
|
s390_sched_init (FILE *file ATTRIBUTE_UNUSED,
|
| 10204 |
|
|
int verbose ATTRIBUTE_UNUSED,
|
| 10205 |
|
|
int max_ready ATTRIBUTE_UNUSED)
|
| 10206 |
|
|
{
|
| 10207 |
|
|
last_scheduled_insn = NULL_RTX;
|
| 10208 |
|
|
}
|
| 10209 |
|
|
|
| 10210 |
|
|
/* Initialize GCC target structure. */
|
| 10211 |
|
|
|
| 10212 |
|
|
#undef TARGET_ASM_ALIGNED_HI_OP
|
| 10213 |
|
|
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
|
| 10214 |
|
|
#undef TARGET_ASM_ALIGNED_DI_OP
|
| 10215 |
|
|
#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
|
| 10216 |
|
|
#undef TARGET_ASM_INTEGER
|
| 10217 |
|
|
#define TARGET_ASM_INTEGER s390_assemble_integer
|
| 10218 |
|
|
|
| 10219 |
|
|
#undef TARGET_ASM_OPEN_PAREN
|
| 10220 |
|
|
#define TARGET_ASM_OPEN_PAREN ""
|
| 10221 |
|
|
|
| 10222 |
|
|
#undef TARGET_ASM_CLOSE_PAREN
|
| 10223 |
|
|
#define TARGET_ASM_CLOSE_PAREN ""
|
| 10224 |
|
|
|
| 10225 |
|
|
#undef TARGET_DEFAULT_TARGET_FLAGS
|
| 10226 |
|
|
#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_FUSED_MADD)
|
| 10227 |
|
|
#undef TARGET_HANDLE_OPTION
|
| 10228 |
|
|
#define TARGET_HANDLE_OPTION s390_handle_option
|
| 10229 |
|
|
|
| 10230 |
|
|
#undef TARGET_ENCODE_SECTION_INFO
|
| 10231 |
|
|
#define TARGET_ENCODE_SECTION_INFO s390_encode_section_info
|
| 10232 |
|
|
|
| 10233 |
|
|
#ifdef HAVE_AS_TLS
|
| 10234 |
|
|
#undef TARGET_HAVE_TLS
|
| 10235 |
|
|
#define TARGET_HAVE_TLS true
|
| 10236 |
|
|
#endif
|
| 10237 |
|
|
#undef TARGET_CANNOT_FORCE_CONST_MEM
|
| 10238 |
|
|
#define TARGET_CANNOT_FORCE_CONST_MEM s390_cannot_force_const_mem
|
| 10239 |
|
|
|
| 10240 |
|
|
#undef TARGET_DELEGITIMIZE_ADDRESS
|
| 10241 |
|
|
#define TARGET_DELEGITIMIZE_ADDRESS s390_delegitimize_address
|
| 10242 |
|
|
|
| 10243 |
|
|
#undef TARGET_LEGITIMIZE_ADDRESS
|
| 10244 |
|
|
#define TARGET_LEGITIMIZE_ADDRESS s390_legitimize_address
|
| 10245 |
|
|
|
| 10246 |
|
|
#undef TARGET_RETURN_IN_MEMORY
|
| 10247 |
|
|
#define TARGET_RETURN_IN_MEMORY s390_return_in_memory
|
| 10248 |
|
|
|
| 10249 |
|
|
#undef TARGET_INIT_BUILTINS
|
| 10250 |
|
|
#define TARGET_INIT_BUILTINS s390_init_builtins
|
| 10251 |
|
|
#undef TARGET_EXPAND_BUILTIN
|
| 10252 |
|
|
#define TARGET_EXPAND_BUILTIN s390_expand_builtin
|
| 10253 |
|
|
|
| 10254 |
|
|
#undef TARGET_ASM_OUTPUT_MI_THUNK
|
| 10255 |
|
|
#define TARGET_ASM_OUTPUT_MI_THUNK s390_output_mi_thunk
|
| 10256 |
|
|
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
|
| 10257 |
|
|
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
|
| 10258 |
|
|
|
| 10259 |
|
|
#undef TARGET_SCHED_ADJUST_PRIORITY
|
| 10260 |
|
|
#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority
|
| 10261 |
|
|
#undef TARGET_SCHED_ISSUE_RATE
|
| 10262 |
|
|
#define TARGET_SCHED_ISSUE_RATE s390_issue_rate
|
| 10263 |
|
|
#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
|
| 10264 |
|
|
#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD s390_first_cycle_multipass_dfa_lookahead
|
| 10265 |
|
|
|
| 10266 |
|
|
#undef TARGET_SCHED_VARIABLE_ISSUE
|
| 10267 |
|
|
#define TARGET_SCHED_VARIABLE_ISSUE s390_sched_variable_issue
|
| 10268 |
|
|
#undef TARGET_SCHED_REORDER
|
| 10269 |
|
|
#define TARGET_SCHED_REORDER s390_sched_reorder
|
| 10270 |
|
|
#undef TARGET_SCHED_INIT
|
| 10271 |
|
|
#define TARGET_SCHED_INIT s390_sched_init
|
| 10272 |
|
|
|
| 10273 |
|
|
#undef TARGET_CANNOT_COPY_INSN_P
|
| 10274 |
|
|
#define TARGET_CANNOT_COPY_INSN_P s390_cannot_copy_insn_p
|
| 10275 |
|
|
#undef TARGET_RTX_COSTS
|
| 10276 |
|
|
#define TARGET_RTX_COSTS s390_rtx_costs
|
| 10277 |
|
|
#undef TARGET_ADDRESS_COST
|
| 10278 |
|
|
#define TARGET_ADDRESS_COST s390_address_cost
|
| 10279 |
|
|
|
| 10280 |
|
|
#undef TARGET_MACHINE_DEPENDENT_REORG
|
| 10281 |
|
|
#define TARGET_MACHINE_DEPENDENT_REORG s390_reorg
|
| 10282 |
|
|
|
| 10283 |
|
|
#undef TARGET_VALID_POINTER_MODE
|
| 10284 |
|
|
#define TARGET_VALID_POINTER_MODE s390_valid_pointer_mode
|
| 10285 |
|
|
|
| 10286 |
|
|
#undef TARGET_BUILD_BUILTIN_VA_LIST
|
| 10287 |
|
|
#define TARGET_BUILD_BUILTIN_VA_LIST s390_build_builtin_va_list
|
| 10288 |
|
|
#undef TARGET_EXPAND_BUILTIN_VA_START
|
| 10289 |
|
|
#define TARGET_EXPAND_BUILTIN_VA_START s390_va_start
|
| 10290 |
|
|
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
|
| 10291 |
|
|
#define TARGET_GIMPLIFY_VA_ARG_EXPR s390_gimplify_va_arg
|
| 10292 |
|
|
|
| 10293 |
|
|
#undef TARGET_PROMOTE_FUNCTION_MODE
|
| 10294 |
|
|
#define TARGET_PROMOTE_FUNCTION_MODE s390_promote_function_mode
|
| 10295 |
|
|
#undef TARGET_PASS_BY_REFERENCE
|
| 10296 |
|
|
#define TARGET_PASS_BY_REFERENCE s390_pass_by_reference
|
| 10297 |
|
|
|
| 10298 |
|
|
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
|
| 10299 |
|
|
#define TARGET_FUNCTION_OK_FOR_SIBCALL s390_function_ok_for_sibcall
|
| 10300 |
|
|
|
| 10301 |
|
|
#undef TARGET_FIXED_CONDITION_CODE_REGS
|
| 10302 |
|
|
#define TARGET_FIXED_CONDITION_CODE_REGS s390_fixed_condition_code_regs
|
| 10303 |
|
|
|
| 10304 |
|
|
#undef TARGET_CC_MODES_COMPATIBLE
|
| 10305 |
|
|
#define TARGET_CC_MODES_COMPATIBLE s390_cc_modes_compatible
|
| 10306 |
|
|
|
| 10307 |
|
|
#undef TARGET_INVALID_WITHIN_DOLOOP
|
| 10308 |
|
|
#define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_const_rtx_null
|
| 10309 |
|
|
|
| 10310 |
|
|
#ifdef HAVE_AS_TLS
|
| 10311 |
|
|
#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
|
| 10312 |
|
|
#define TARGET_ASM_OUTPUT_DWARF_DTPREL s390_output_dwarf_dtprel
|
| 10313 |
|
|
#endif
|
| 10314 |
|
|
|
| 10315 |
|
|
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
|
| 10316 |
|
|
#undef TARGET_MANGLE_TYPE
|
| 10317 |
|
|
#define TARGET_MANGLE_TYPE s390_mangle_type
|
| 10318 |
|
|
#endif
|
| 10319 |
|
|
|
| 10320 |
|
|
#undef TARGET_SCALAR_MODE_SUPPORTED_P
|
| 10321 |
|
|
#define TARGET_SCALAR_MODE_SUPPORTED_P s390_scalar_mode_supported_p
|
| 10322 |
|
|
|
| 10323 |
|
|
#undef TARGET_SECONDARY_RELOAD
|
| 10324 |
|
|
#define TARGET_SECONDARY_RELOAD s390_secondary_reload
|
| 10325 |
|
|
|
| 10326 |
|
|
#undef TARGET_LIBGCC_CMP_RETURN_MODE
|
| 10327 |
|
|
#define TARGET_LIBGCC_CMP_RETURN_MODE s390_libgcc_cmp_return_mode
|
| 10328 |
|
|
|
| 10329 |
|
|
#undef TARGET_LIBGCC_SHIFT_COUNT_MODE
|
| 10330 |
|
|
#define TARGET_LIBGCC_SHIFT_COUNT_MODE s390_libgcc_shift_count_mode
|
| 10331 |
|
|
|
| 10332 |
|
|
#undef TARGET_LEGITIMATE_ADDRESS_P
|
| 10333 |
|
|
#define TARGET_LEGITIMATE_ADDRESS_P s390_legitimate_address_p
|
| 10334 |
|
|
|
| 10335 |
|
|
#undef TARGET_CAN_ELIMINATE
|
| 10336 |
|
|
#define TARGET_CAN_ELIMINATE s390_can_eliminate
|
| 10337 |
|
|
|
| 10338 |
|
|
#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
|
| 10339 |
|
|
#define TARGET_ASM_TRAMPOLINE_TEMPLATE s390_asm_trampoline_template
|
| 10340 |
|
|
#undef TARGET_TRAMPOLINE_INIT
|
| 10341 |
|
|
#define TARGET_TRAMPOLINE_INIT s390_trampoline_init
|
| 10342 |
|
|
|
| 10343 |
|
|
struct gcc_target targetm = TARGET_INITIALIZER;
|
| 10344 |
|
|
|
| 10345 |
|
|
#include "gt-s390.h"
|