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