OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [config/] [c6x/] [c6x.c] - Blame information for rev 709

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 709 jeremybenn
/* Target Code for TI C6X
2
   Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
3
   Contributed by Andrew Jenner <andrew@codesourcery.com>
4
   Contributed by Bernd Schmidt <bernds@codesourcery.com>
5
 
6
   This file is part of GCC.
7
 
8
   GCC is free software; you can redistribute it and/or modify it
9
   under the terms of the GNU General Public License as published
10
   by the Free Software Foundation; either version 3, or (at your
11
   option) any later version.
12
 
13
   GCC is distributed in the hope that it will be useful, but WITHOUT
14
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16
   License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with GCC; see the file COPYING3.  If not see
20
   <http://www.gnu.org/licenses/>.  */
21
 
22
#include "config.h"
23
#include "system.h"
24
#include "coretypes.h"
25
#include "tm.h"
26
#include "rtl.h"
27
#include "tree.h"
28
#include "insn-flags.h"
29
#include "output.h"
30
#include "insn-attr.h"
31
#include "insn-codes.h"
32
#include "expr.h"
33
#include "regs.h"
34
#include "optabs.h"
35
#include "recog.h"
36
#include "ggc.h"
37
#include "sched-int.h"
38
#include "timevar.h"
39
#include "tm_p.h"
40
#include "tm-preds.h"
41
#include "tm-constrs.h"
42
#include "df.h"
43
#include "integrate.h"
44
#include "diagnostic-core.h"
45
#include "cgraph.h"
46
#include "cfglayout.h"
47
#include "langhooks.h"
48
#include "target.h"
49
#include "target-def.h"
50
#include "sel-sched.h"
51
#include "debug.h"
52
#include "opts.h"
53
#include "hw-doloop.h"
54
#include "regrename.h"
55
 
56
/* Table of supported architecture variants.  */
57
typedef struct
58
{
59
  const char *arch;
60
  enum c6x_cpu_type type;
61
  unsigned short features;
62
} c6x_arch_table;
63
 
64
/* A list of all ISAs, mapping each one to a representative device.
65
   Used for -march selection.  */
66
static const c6x_arch_table all_isas[] =
67
{
68
#define C6X_ISA(NAME,DEVICE,FLAGS) \
69
  { NAME, DEVICE, FLAGS },
70
#include "c6x-isas.def"
71
#undef C6X_ISA
72
  { NULL, C6X_CPU_C62X, 0 }
73
};
74
 
75
/* This is the parsed result of the "-march=" option, if given.  */
76
enum c6x_cpu_type c6x_arch = C6X_DEFAULT_ARCH;
77
 
78
/* A mask of insn types that are allowed by the architecture selected by
79
   the -march option.  */
80
unsigned long c6x_insn_mask = C6X_DEFAULT_INSN_MASK;
81
 
82
/* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
83
 */
84
static rtx c6x_current_insn = NULL_RTX;
85
 
86
/* A decl we build to access __c6xabi_DSBT_base.  */
87
static GTY(()) tree dsbt_decl;
88
 
89
/* Determines whether we run our final scheduling pass or not.  We always
90
   avoid the normal second scheduling pass.  */
91
static int c6x_flag_schedule_insns2;
92
 
93
/* Determines whether we run variable tracking in machine dependent
94
   reorganization.  */
95
static int c6x_flag_var_tracking;
96
 
97
/* Determines whether we use modulo scheduling.  */
98
static int c6x_flag_modulo_sched;
99
 
100
/* Record the state of flag_pic before we set it to 1 for DSBT.  */
101
int c6x_initial_flag_pic;
102
 
103
typedef struct
104
{
105
  /* We record the clock cycle for every insn during scheduling.  */
106
  int clock;
107
  /* After scheduling, we run assign_reservations to choose unit
108
     reservations for all insns.  These are recorded here.  */
109
  int reservation;
110
  /* Records the new condition for insns which must be made
111
     conditional after scheduling.  An entry of NULL_RTX means no such
112
     change is necessary.  */
113
  rtx new_cond;
114
  /* True for the first insn that was scheduled in an ebb.  */
115
  bool ebb_start;
116
  /* The scheduler state after the insn, transformed into a mask of UNIT_QID
117
     bits rather than storing the state.  Meaningful only for the last
118
     insn in a cycle.  */
119
  unsigned int unit_mask;
120
} c6x_sched_insn_info;
121
 
122
DEF_VEC_O(c6x_sched_insn_info);
123
DEF_VEC_ALLOC_O(c6x_sched_insn_info, heap);
124
 
125
/* Record a c6x_sched_insn_info structure for every insn in the function.  */
126
static VEC(c6x_sched_insn_info, heap) *insn_info;
127
 
128
#define INSN_INFO_LENGTH (VEC_length (c6x_sched_insn_info, insn_info))
129
#define INSN_INFO_ENTRY(N) (*VEC_index (c6x_sched_insn_info, insn_info, (N)))
130
 
131
static bool done_cfi_sections;
132
 
133
#define RESERVATION_FLAG_D 1
134
#define RESERVATION_FLAG_L 2
135
#define RESERVATION_FLAG_S 4
136
#define RESERVATION_FLAG_M 8
137
#define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
138
#define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
139
#define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
140
#define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
141
 
142
/* The DFA names of the units.  */
143
static const char *const c6x_unit_names[] =
144
{
145
  "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
146
  "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
147
};
148
 
149
/* The DFA unit number for each unit in c6x_unit_names[].  */
150
static int c6x_unit_codes[ARRAY_SIZE (c6x_unit_names)];
151
 
152
/* Unit query IDs.  */
153
#define UNIT_QID_D1 0
154
#define UNIT_QID_L1 1
155
#define UNIT_QID_S1 2
156
#define UNIT_QID_M1 3
157
#define UNIT_QID_FPS1 4
158
#define UNIT_QID_FPL1 5
159
#define UNIT_QID_ADDDPS1 6
160
#define UNIT_QID_ADDDPL1 7
161
#define UNIT_QID_SIDE_OFFSET 8
162
 
163
#define RESERVATION_S1 2
164
#define RESERVATION_S2 10
165
 
166
/* An enum for the unit requirements we count in the UNIT_REQS table.  */
167
enum unitreqs
168
{
169
  UNIT_REQ_D,
170
  UNIT_REQ_L,
171
  UNIT_REQ_S,
172
  UNIT_REQ_M,
173
  UNIT_REQ_DL,
174
  UNIT_REQ_DS,
175
  UNIT_REQ_LS,
176
  UNIT_REQ_DLS,
177
  UNIT_REQ_T,
178
  UNIT_REQ_X,
179
  UNIT_REQ_MAX
180
};
181
 
182
/* A table used to count unit requirements.  Used when computing minimum
183
   iteration intervals.  */
184
typedef int unit_req_table[2][UNIT_REQ_MAX];
185
static unit_req_table unit_reqs;
186
 
187
/* Register map for debugging.  */
188
int const dbx_register_map[FIRST_PSEUDO_REGISTER] =
189
{
190
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,  /* A0 - A15.  */
191
  37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,   /* A16 - A32.  */
192
  50, 51, 52,
193
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,   /* B0 - B15.  */
194
  29, 30, 31,
195
  53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,   /* B16 - B32.  */
196
  66, 67, 68,
197
  -1, -1, -1                                            /* FP, ARGP, ILC.  */
198
};
199
 
200
/* Allocate a new, cleared machine_function structure.  */
201
 
202
static struct machine_function *
203
c6x_init_machine_status (void)
204
{
205
  return ggc_alloc_cleared_machine_function ();
206
}
207
 
208
/* Implement TARGET_OPTION_OVERRIDE.  */
209
 
210
static void
211
c6x_option_override (void)
212
{
213
  unsigned i;
214
 
215
  if (global_options_set.x_c6x_arch_option)
216
    {
217
      c6x_arch = all_isas[c6x_arch_option].type;
218
      c6x_insn_mask &= ~C6X_INSNS_ALL_CPU_BITS;
219
      c6x_insn_mask |= all_isas[c6x_arch_option].features;
220
    }
221
 
222
  c6x_flag_schedule_insns2 = flag_schedule_insns_after_reload;
223
  flag_schedule_insns_after_reload = 0;
224
 
225
  c6x_flag_modulo_sched = flag_modulo_sched;
226
  flag_modulo_sched = 0;
227
 
228
  init_machine_status = c6x_init_machine_status;
229
 
230
  for (i = 0; i < ARRAY_SIZE (c6x_unit_names); i++)
231
    c6x_unit_codes[i] = get_cpu_unit_code (c6x_unit_names[i]);
232
 
233
  if (flag_pic && !TARGET_DSBT)
234
    {
235
      error ("-fpic and -fPIC not supported without -mdsbt on this target");
236
      flag_pic = 0;
237
    }
238
  c6x_initial_flag_pic = flag_pic;
239
  if (TARGET_DSBT && !flag_pic)
240
    flag_pic = 1;
241
}
242
 
243
 
244
/* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook.  */
245
 
246
static void
247
c6x_conditional_register_usage (void)
248
{
249
  int i;
250
  if (c6x_arch == C6X_CPU_C62X || c6x_arch == C6X_CPU_C67X)
251
    for (i = 16; i < 32; i++)
252
      {
253
        fixed_regs[i] = 1;
254
        fixed_regs[32 + i] = 1;
255
      }
256
  if (TARGET_INSNS_64)
257
    {
258
      SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_A_REGS],
259
                        REG_A0);
260
      SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_REGS],
261
                        REG_A0);
262
      CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_A_REGS],
263
                          REG_A0);
264
      CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_REGS],
265
                          REG_A0);
266
    }
267
}
268
 
269
static GTY(()) rtx eqdf_libfunc;
270
static GTY(()) rtx nedf_libfunc;
271
static GTY(()) rtx ledf_libfunc;
272
static GTY(()) rtx ltdf_libfunc;
273
static GTY(()) rtx gedf_libfunc;
274
static GTY(()) rtx gtdf_libfunc;
275
static GTY(()) rtx eqsf_libfunc;
276
static GTY(()) rtx nesf_libfunc;
277
static GTY(()) rtx lesf_libfunc;
278
static GTY(()) rtx ltsf_libfunc;
279
static GTY(()) rtx gesf_libfunc;
280
static GTY(()) rtx gtsf_libfunc;
281
static GTY(()) rtx strasgi_libfunc;
282
static GTY(()) rtx strasgi64p_libfunc;
283
 
284
/* Implement the TARGET_INIT_LIBFUNCS macro.  We use this to rename library
285
   functions to match the C6x ABI.  */
286
 
287
static void
288
c6x_init_libfuncs (void)
289
{
290
  /* Double-precision floating-point arithmetic.  */
291
  set_optab_libfunc (add_optab, DFmode, "__c6xabi_addd");
292
  set_optab_libfunc (sdiv_optab, DFmode, "__c6xabi_divd");
293
  set_optab_libfunc (smul_optab, DFmode, "__c6xabi_mpyd");
294
  set_optab_libfunc (neg_optab, DFmode, "__c6xabi_negd");
295
  set_optab_libfunc (sub_optab, DFmode, "__c6xabi_subd");
296
 
297
  /* Single-precision floating-point arithmetic.  */
298
  set_optab_libfunc (add_optab, SFmode, "__c6xabi_addf");
299
  set_optab_libfunc (sdiv_optab, SFmode, "__c6xabi_divf");
300
  set_optab_libfunc (smul_optab, SFmode, "__c6xabi_mpyf");
301
  set_optab_libfunc (neg_optab, SFmode, "__c6xabi_negf");
302
  set_optab_libfunc (sub_optab, SFmode, "__c6xabi_subf");
303
 
304
  /* Floating-point comparisons.  */
305
  eqsf_libfunc = init_one_libfunc ("__c6xabi_eqf");
306
  nesf_libfunc = init_one_libfunc ("__c6xabi_neqf");
307
  lesf_libfunc = init_one_libfunc ("__c6xabi_lef");
308
  ltsf_libfunc = init_one_libfunc ("__c6xabi_ltf");
309
  gesf_libfunc = init_one_libfunc ("__c6xabi_gef");
310
  gtsf_libfunc = init_one_libfunc ("__c6xabi_gtf");
311
  eqdf_libfunc = init_one_libfunc ("__c6xabi_eqd");
312
  nedf_libfunc = init_one_libfunc ("__c6xabi_neqd");
313
  ledf_libfunc = init_one_libfunc ("__c6xabi_led");
314
  ltdf_libfunc = init_one_libfunc ("__c6xabi_ltd");
315
  gedf_libfunc = init_one_libfunc ("__c6xabi_ged");
316
  gtdf_libfunc = init_one_libfunc ("__c6xabi_gtd");
317
 
318
  set_optab_libfunc (eq_optab, SFmode, NULL);
319
  set_optab_libfunc (ne_optab, SFmode, "__c6xabi_neqf");
320
  set_optab_libfunc (gt_optab, SFmode, NULL);
321
  set_optab_libfunc (ge_optab, SFmode, NULL);
322
  set_optab_libfunc (lt_optab, SFmode, NULL);
323
  set_optab_libfunc (le_optab, SFmode, NULL);
324
  set_optab_libfunc (unord_optab, SFmode, "__c6xabi_unordf");
325
  set_optab_libfunc (eq_optab, DFmode, NULL);
326
  set_optab_libfunc (ne_optab, DFmode, "__c6xabi_neqd");
327
  set_optab_libfunc (gt_optab, DFmode, NULL);
328
  set_optab_libfunc (ge_optab, DFmode, NULL);
329
  set_optab_libfunc (lt_optab, DFmode, NULL);
330
  set_optab_libfunc (le_optab, DFmode, NULL);
331
  set_optab_libfunc (unord_optab, DFmode, "__c6xabi_unordd");
332
 
333
  /* Floating-point to integer conversions.  */
334
  set_conv_libfunc (sfix_optab, SImode, DFmode, "__c6xabi_fixdi");
335
  set_conv_libfunc (ufix_optab, SImode, DFmode, "__c6xabi_fixdu");
336
  set_conv_libfunc (sfix_optab, DImode, DFmode, "__c6xabi_fixdlli");
337
  set_conv_libfunc (ufix_optab, DImode, DFmode, "__c6xabi_fixdull");
338
  set_conv_libfunc (sfix_optab, SImode, SFmode, "__c6xabi_fixfi");
339
  set_conv_libfunc (ufix_optab, SImode, SFmode, "__c6xabi_fixfu");
340
  set_conv_libfunc (sfix_optab, DImode, SFmode, "__c6xabi_fixflli");
341
  set_conv_libfunc (ufix_optab, DImode, SFmode, "__c6xabi_fixfull");
342
 
343
  /* Conversions between floating types.  */
344
  set_conv_libfunc (trunc_optab, SFmode, DFmode, "__c6xabi_cvtdf");
345
  set_conv_libfunc (sext_optab, DFmode, SFmode, "__c6xabi_cvtfd");
346
 
347
  /* Integer to floating-point conversions.  */
348
  set_conv_libfunc (sfloat_optab, DFmode, SImode, "__c6xabi_fltid");
349
  set_conv_libfunc (ufloat_optab, DFmode, SImode, "__c6xabi_fltud");
350
  set_conv_libfunc (sfloat_optab, DFmode, DImode, "__c6xabi_fltllid");
351
  set_conv_libfunc (ufloat_optab, DFmode, DImode, "__c6xabi_fltulld");
352
  set_conv_libfunc (sfloat_optab, SFmode, SImode, "__c6xabi_fltif");
353
  set_conv_libfunc (ufloat_optab, SFmode, SImode, "__c6xabi_fltuf");
354
  set_conv_libfunc (sfloat_optab, SFmode, DImode, "__c6xabi_fltllif");
355
  set_conv_libfunc (ufloat_optab, SFmode, DImode, "__c6xabi_fltullf");
356
 
357
  /* Long long.  */
358
  set_optab_libfunc (smul_optab, DImode, "__c6xabi_mpyll");
359
  set_optab_libfunc (ashl_optab, DImode, "__c6xabi_llshl");
360
  set_optab_libfunc (lshr_optab, DImode, "__c6xabi_llshru");
361
  set_optab_libfunc (ashr_optab, DImode, "__c6xabi_llshr");
362
 
363
  set_optab_libfunc (sdiv_optab, SImode, "__c6xabi_divi");
364
  set_optab_libfunc (udiv_optab, SImode, "__c6xabi_divu");
365
  set_optab_libfunc (smod_optab, SImode, "__c6xabi_remi");
366
  set_optab_libfunc (umod_optab, SImode, "__c6xabi_remu");
367
  set_optab_libfunc (sdivmod_optab, SImode, "__c6xabi_divremi");
368
  set_optab_libfunc (udivmod_optab, SImode, "__c6xabi_divremu");
369
  set_optab_libfunc (sdiv_optab, DImode, "__c6xabi_divlli");
370
  set_optab_libfunc (udiv_optab, DImode, "__c6xabi_divull");
371
  set_optab_libfunc (smod_optab, DImode, "__c6xabi_remlli");
372
  set_optab_libfunc (umod_optab, DImode, "__c6xabi_remull");
373
  set_optab_libfunc (udivmod_optab, DImode, "__c6xabi_divremull");
374
 
375
  /* Block move.  */
376
  strasgi_libfunc = init_one_libfunc ("__c6xabi_strasgi");
377
  strasgi64p_libfunc = init_one_libfunc ("__c6xabi_strasgi_64plus");
378
}
379
 
380
/* Begin the assembly file.  */
381
 
382
static void
383
c6x_file_start (void)
384
{
385
  /* Variable tracking should be run after all optimizations which change order
386
     of insns.  It also needs a valid CFG.  This can't be done in
387
     c6x_override_options, because flag_var_tracking is finalized after
388
     that.  */
389
  c6x_flag_var_tracking = flag_var_tracking;
390
  flag_var_tracking = 0;
391
 
392
  done_cfi_sections = false;
393
  default_file_start ();
394
 
395
  /* Arrays are aligned to 8-byte boundaries.  */
396
  asm_fprintf (asm_out_file,
397
               "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
398
  asm_fprintf (asm_out_file,
399
               "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
400
 
401
  /* Stack alignment is 8 bytes.  */
402
  asm_fprintf (asm_out_file,
403
               "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
404
  asm_fprintf (asm_out_file,
405
               "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
406
 
407
#if 0 /* FIXME: Reenable when TI's tools are fixed.  */
408
  /* ??? Ideally we'd check flag_short_wchar somehow.  */
409
  asm_fprintf (asm_out_file, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
410
#endif
411
 
412
  /* We conform to version 1.0 of the ABI.  */
413
  asm_fprintf (asm_out_file,
414
               "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
415
 
416
}
417
 
418
/* The LTO frontend only enables exceptions when it sees a function that
419
   uses it.  This changes the return value of dwarf2out_do_frame, so we
420
   have to check before every function.  */
421
 
422
void
423
c6x_output_file_unwind (FILE * f)
424
{
425
  if (done_cfi_sections)
426
    return;
427
 
428
  /* Output a .cfi_sections directive.  */
429
  if (dwarf2out_do_frame ())
430
    {
431
      if (flag_unwind_tables || flag_exceptions)
432
        {
433
          if (write_symbols == DWARF2_DEBUG
434
              || write_symbols == VMS_AND_DWARF2_DEBUG)
435
            asm_fprintf (f, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
436
          else
437
            asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
438
        }
439
      else
440
        asm_fprintf (f, "\t.cfi_sections .debug_frame\n");
441
      done_cfi_sections = true;
442
    }
443
}
444
 
445
/* Output unwind directives at the end of a function.  */
446
 
447
static void
448
c6x_output_fn_unwind (FILE * f)
449
{
450
  /* Return immediately if we are not generating unwinding tables.  */
451
  if (! (flag_unwind_tables || flag_exceptions))
452
    return;
453
 
454
  /* If this function will never be unwound, then mark it as such.  */
455
  if (!(flag_unwind_tables || crtl->uses_eh_lsda)
456
      && (TREE_NOTHROW (current_function_decl)
457
          || crtl->all_throwers_are_sibcalls))
458
    fputs("\t.cantunwind\n", f);
459
 
460
  fputs ("\t.endp\n", f);
461
}
462
 
463
 
464
/* Stack and Calling.  */
465
 
466
int argument_registers[10] =
467
{
468
  REG_A4, REG_B4,
469
  REG_A6, REG_B6,
470
  REG_A8, REG_B8,
471
  REG_A10, REG_B10,
472
  REG_A12, REG_B12
473
};
474
 
475
/* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h.  */
476
 
477
void
478
c6x_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype, rtx libname,
479
                          int n_named_args ATTRIBUTE_UNUSED)
480
{
481
  cum->count = 0;
482
  cum->nregs = 10;
483
  if (!libname && fntype)
484
    {
485
      /* We need to find out the number of named arguments.  Unfortunately,
486
         for incoming arguments, N_NAMED_ARGS is set to -1.  */
487
      if (stdarg_p (fntype))
488
        cum->nregs = type_num_arguments (fntype) - 1;
489
      if (cum->nregs > 10)
490
        cum->nregs = 10;
491
    }
492
}
493
 
494
/* Implements the macro FUNCTION_ARG defined in c6x.h.  */
495
 
496
static rtx
497
c6x_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
498
                  const_tree type, bool named ATTRIBUTE_UNUSED)
499
{
500
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
501
  if (cum->count >= cum->nregs)
502
    return NULL_RTX;
503
  if (type)
504
    {
505
      HOST_WIDE_INT size = int_size_in_bytes (type);
506
      if (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (type))
507
        {
508
          if (size > 4)
509
            {
510
              rtx reg1 = gen_rtx_REG (SImode, argument_registers[cum->count] + 1);
511
              rtx reg2 = gen_rtx_REG (SImode, argument_registers[cum->count]);
512
              rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
513
                                     gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
514
              return gen_rtx_PARALLEL (mode, vec);
515
            }
516
        }
517
    }
518
  return gen_rtx_REG (mode, argument_registers[cum->count]);
519
}
520
 
521
static void
522
c6x_function_arg_advance (cumulative_args_t cum_v,
523
                          enum machine_mode mode ATTRIBUTE_UNUSED,
524
                          const_tree type ATTRIBUTE_UNUSED,
525
                          bool named ATTRIBUTE_UNUSED)
526
{
527
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
528
  cum->count++;
529
}
530
 
531
 
532
/* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
533
   upward rather than downward.  */
534
 
535
bool
536
c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
537
                          const_tree type, bool first)
538
{
539
  HOST_WIDE_INT size;
540
 
541
  if (!TARGET_BIG_ENDIAN)
542
    return true;
543
  if (!first)
544
    return true;
545
  if (!type)
546
    return true;
547
  size = int_size_in_bytes (type);
548
  return size == 3;
549
}
550
 
551
/* Implement TARGET_FUNCTION_ARG_BOUNDARY.  */
552
 
553
static unsigned int
554
c6x_function_arg_boundary (enum machine_mode mode, const_tree type)
555
{
556
  unsigned int boundary = type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode);
557
 
558
  if (boundary > BITS_PER_WORD)
559
    return 2 * BITS_PER_WORD;
560
 
561
  if (mode == BLKmode)
562
    {
563
      HOST_WIDE_INT size = int_size_in_bytes (type);
564
      if (size > 4)
565
        return 2 * BITS_PER_WORD;
566
      if (boundary < BITS_PER_WORD)
567
        {
568
          if (size >= 3)
569
            return BITS_PER_WORD;
570
          if (size >= 2)
571
            return 2 * BITS_PER_UNIT;
572
        }
573
    }
574
  return boundary;
575
}
576
 
577
/* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY.  */
578
static unsigned int
579
c6x_function_arg_round_boundary (enum machine_mode mode, const_tree type)
580
{
581
  return c6x_function_arg_boundary (mode, type);
582
}
583
 
584
/* TARGET_FUNCTION_VALUE implementation.  Returns an RTX representing the place
585
   where function FUNC returns or receives a value of data type TYPE.  */
586
 
587
static rtx
588
c6x_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED,
589
                    bool outgoing ATTRIBUTE_UNUSED)
590
{
591
  /* Functions return values in register A4.  When returning aggregates, we may
592
     have to adjust for endianness.  */
593
  if (TARGET_BIG_ENDIAN && type && AGGREGATE_TYPE_P (type))
594
    {
595
      HOST_WIDE_INT size = int_size_in_bytes (type);
596
      if (size > 4)
597
        {
598
 
599
          rtx reg1 = gen_rtx_REG (SImode, REG_A4 + 1);
600
          rtx reg2 = gen_rtx_REG (SImode, REG_A4);
601
          rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
602
                                 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
603
          return gen_rtx_PARALLEL (TYPE_MODE (type), vec);
604
        }
605
    }
606
  return gen_rtx_REG (TYPE_MODE (type), REG_A4);
607
}
608
 
609
/* Implement TARGET_LIBCALL_VALUE.  */
610
 
611
static rtx
612
c6x_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
613
{
614
  return gen_rtx_REG (mode, REG_A4);
615
}
616
 
617
/* TARGET_STRUCT_VALUE_RTX implementation.  */
618
 
619
static rtx
620
c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED)
621
{
622
  return gen_rtx_REG (Pmode, REG_A3);
623
}
624
 
625
/* Implement TARGET_FUNCTION_VALUE_REGNO_P.  */
626
 
627
static bool
628
c6x_function_value_regno_p (const unsigned int regno)
629
{
630
  return regno == REG_A4;
631
}
632
 
633
/* Types larger than 64 bit, and variable sized types, are passed by
634
   reference.  The callee must copy them; see c6x_callee_copies.  */
635
 
636
static bool
637
c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
638
                       enum machine_mode mode, const_tree type,
639
                       bool named ATTRIBUTE_UNUSED)
640
{
641
  int size = -1;
642
  if (type)
643
    size = int_size_in_bytes (type);
644
  else if (mode != VOIDmode)
645
    size = GET_MODE_SIZE (mode);
646
  return size > 2 * UNITS_PER_WORD || size == -1;
647
}
648
 
649
/* Decide whether a type should be returned in memory (true)
650
   or in a register (false).  This is called by the macro
651
   TARGET_RETURN_IN_MEMORY.  */
652
 
653
static bool
654
c6x_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
655
{
656
  int size = int_size_in_bytes (type);
657
  return size > 2 * UNITS_PER_WORD || size == -1;
658
}
659
 
660
/* Values which must be returned in the most-significant end of the return
661
   register.  */
662
 
663
static bool
664
c6x_return_in_msb (const_tree valtype)
665
{
666
  HOST_WIDE_INT size = int_size_in_bytes (valtype);
667
  return TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype) && size == 3;
668
}
669
 
670
/* Implement TARGET_CALLEE_COPIES.  */
671
 
672
static bool
673
c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
674
                   enum machine_mode mode ATTRIBUTE_UNUSED,
675
                   const_tree type ATTRIBUTE_UNUSED,
676
                   bool named ATTRIBUTE_UNUSED)
677
{
678
  return true;
679
}
680
 
681
/* Return the type to use as __builtin_va_list.  */
682
static tree
683
c6x_build_builtin_va_list (void)
684
{
685
  return build_pointer_type (char_type_node);
686
}
687
 
688
static void
689
c6x_asm_trampoline_template (FILE *f)
690
{
691
  fprintf (f, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
692
  fprintf (f, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
693
  fprintf (f, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
694
  fprintf (f, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
695
  fprintf (f, "\t.long\t0x00000362\n"); /* b .s2 B0 */
696
  fprintf (f, "\t.long\t0x00008000\n"); /* nop 5 */
697
  fprintf (f, "\t.long\t0x00000000\n"); /* nop */
698
  fprintf (f, "\t.long\t0x00000000\n"); /* nop */
699
}
700
 
701
/* Emit RTL insns to initialize the variable parts of a trampoline at
702
   TRAMP. FNADDR is an RTX for the address of the function's pure
703
   code.  CXT is an RTX for the static chain value for the function.  */
704
 
705
static void
706
c6x_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt)
707
{
708
  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
709
  rtx t1 = copy_to_reg (fnaddr);
710
  rtx t2 = copy_to_reg (cxt);
711
  rtx mask = gen_reg_rtx (SImode);
712
  int i;
713
 
714
  emit_block_move (tramp, assemble_trampoline_template (),
715
                   GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
716
 
717
  emit_move_insn (mask, GEN_INT (0xffff << 7));
718
 
719
  for (i = 0; i < 4; i++)
720
    {
721
      rtx mem = adjust_address (tramp, SImode, i * 4);
722
      rtx t = (i & 1) ? t2 : t1;
723
      rtx v1 = gen_reg_rtx (SImode);
724
      rtx v2 = gen_reg_rtx (SImode);
725
      emit_move_insn (v1, mem);
726
      if (i < 2)
727
        emit_insn (gen_ashlsi3 (v2, t, GEN_INT (7)));
728
      else
729
        emit_insn (gen_lshrsi3 (v2, t, GEN_INT (9)));
730
      emit_insn (gen_andsi3 (v2, v2, mask));
731
      emit_insn (gen_iorsi3 (v2, v2, v1));
732
      emit_move_insn (mem, v2);
733
    }
734
#ifdef CLEAR_INSN_CACHE
735
  tramp = XEXP (tramp, 0);
736
  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gnu_clear_cache"),
737
                     LCT_NORMAL, VOIDmode, 2, tramp, Pmode,
738
                     plus_constant (tramp, TRAMPOLINE_SIZE), Pmode);
739
#endif
740
}
741
 
742
/* Determine whether c6x_output_mi_thunk can succeed.  */
743
 
744
static bool
745
c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED,
746
                         HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
747
                         HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
748
                         const_tree function ATTRIBUTE_UNUSED)
749
{
750
  return !TARGET_LONG_CALLS;
751
}
752
 
753
/* Output the assembler code for a thunk function.  THUNK is the
754
   declaration for the thunk function itself, FUNCTION is the decl for
755
   the target function.  DELTA is an immediate constant offset to be
756
   added to THIS.  If VCALL_OFFSET is nonzero, the word at
757
   *(*this + vcall_offset) should be added to THIS.  */
758
 
759
static void
760
c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
761
                     tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
762
                     HOST_WIDE_INT vcall_offset, tree function)
763
{
764
  rtx xops[5];
765
  /* The this parameter is passed as the first argument.  */
766
  rtx this_rtx = gen_rtx_REG (Pmode, REG_A4);
767
 
768
  c6x_current_insn = NULL_RTX;
769
 
770
  xops[4] = XEXP (DECL_RTL (function), 0);
771
  if (!vcall_offset)
772
    {
773
      output_asm_insn ("b .s2 \t%4", xops);
774
      if (!delta)
775
        output_asm_insn ("nop 5", xops);
776
    }
777
 
778
  /* Adjust the this parameter by a fixed constant.  */
779
  if (delta)
780
    {
781
      xops[0] = GEN_INT (delta);
782
      xops[1] = this_rtx;
783
      if (delta >= -16 && delta <= 15)
784
        {
785
          output_asm_insn ("add .s1 %0, %1, %1", xops);
786
          if (!vcall_offset)
787
            output_asm_insn ("nop 4", xops);
788
        }
789
      else if (delta >= 16 && delta < 32)
790
        {
791
          output_asm_insn ("add .d1 %0, %1, %1", xops);
792
          if (!vcall_offset)
793
            output_asm_insn ("nop 4", xops);
794
        }
795
      else if (delta >= -32768 && delta < 32768)
796
        {
797
          output_asm_insn ("mvk .s1 %0, A0", xops);
798
          output_asm_insn ("add .d1 %1, A0, %1", xops);
799
          if (!vcall_offset)
800
            output_asm_insn ("nop 3", xops);
801
        }
802
      else
803
        {
804
          output_asm_insn ("mvkl .s1 %0, A0", xops);
805
          output_asm_insn ("mvkh .s1 %0, A0", xops);
806
          output_asm_insn ("add .d1 %1, A0, %1", xops);
807
          if (!vcall_offset)
808
            output_asm_insn ("nop 3", xops);
809
        }
810
    }
811
 
812
  /* Adjust the this parameter by a value stored in the vtable.  */
813
  if (vcall_offset)
814
    {
815
      rtx a0tmp = gen_rtx_REG (Pmode, REG_A0);
816
      rtx a3tmp = gen_rtx_REG (Pmode, REG_A3);
817
 
818
      xops[1] = a3tmp;
819
      xops[2] = a0tmp;
820
      xops[3] = gen_rtx_MEM (Pmode, a0tmp);
821
      output_asm_insn ("mv .s1 a4, %2", xops);
822
      output_asm_insn ("ldw .d1t1 %3, %2", xops);
823
 
824
      /* Adjust the this parameter.  */
825
      xops[0] = gen_rtx_MEM (Pmode, plus_constant (a0tmp, vcall_offset));
826
      if (!memory_operand (xops[0], Pmode))
827
        {
828
          rtx tmp2 = gen_rtx_REG (Pmode, REG_A1);
829
          xops[0] = GEN_INT (vcall_offset);
830
          xops[1] = tmp2;
831
          output_asm_insn ("mvkl .s1 %0, %1", xops);
832
          output_asm_insn ("mvkh .s1 %0, %1", xops);
833
          output_asm_insn ("nop 2", xops);
834
          output_asm_insn ("add .d1 %2, %1, %2", xops);
835
          xops[0] = gen_rtx_MEM (Pmode, a0tmp);
836
        }
837
      else
838
        output_asm_insn ("nop 4", xops);
839
      xops[2] = this_rtx;
840
      output_asm_insn ("ldw .d1t1 %0, %1", xops);
841
      output_asm_insn ("|| b .s2 \t%4", xops);
842
      output_asm_insn ("nop 4", xops);
843
      output_asm_insn ("add .d1 %2, %1, %2", xops);
844
    }
845
}
846
 
847
/* Return true if EXP goes in small data/bss.  */
848
 
849
static bool
850
c6x_in_small_data_p (const_tree exp)
851
{
852
  /* We want to merge strings, so we never consider them small data.  */
853
  if (TREE_CODE (exp) == STRING_CST)
854
    return false;
855
 
856
  /* Functions are never small data.  */
857
  if (TREE_CODE (exp) == FUNCTION_DECL)
858
    return false;
859
 
860
  if (TREE_CODE (exp) == VAR_DECL && DECL_WEAK (exp))
861
    return false;
862
 
863
  if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
864
    {
865
      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
866
 
867
      if (strcmp (section, ".neardata") == 0
868
          || strncmp (section, ".neardata.", 10) == 0
869
          || strncmp (section, ".gnu.linkonce.s.", 16) == 0
870
          || strcmp (section, ".bss") == 0
871
          || strncmp (section, ".bss.", 5) == 0
872
          || strncmp (section, ".gnu.linkonce.sb.", 17) == 0
873
          || strcmp (section, ".rodata") == 0
874
          || strncmp (section, ".rodata.", 8) == 0
875
          || strncmp (section, ".gnu.linkonce.s2.", 17) == 0)
876
        return true;
877
    }
878
  else
879
    return PLACE_IN_SDATA_P (exp);
880
 
881
  return false;
882
}
883
 
884
/* Return a section for X.  The only special thing we do here is to
885
   honor small data.  We don't have a tree type, so we can't use the
886
   PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
887
   everything sized 8 bytes or smaller into small data.  */
888
 
889
static section *
890
c6x_select_rtx_section (enum machine_mode mode, rtx x,
891
                        unsigned HOST_WIDE_INT align)
892
{
893
  if (c6x_sdata_mode == C6X_SDATA_ALL
894
      || (c6x_sdata_mode != C6X_SDATA_NONE && GET_MODE_SIZE (mode) <= 8))
895
    /* ??? Consider using mergeable sdata sections.  */
896
    return sdata_section;
897
  else
898
    return default_elf_select_rtx_section (mode, x, align);
899
}
900
 
901
static section *
902
c6x_elf_select_section (tree decl, int reloc,
903
                        unsigned HOST_WIDE_INT align)
904
{
905
  const char *sname = NULL;
906
  unsigned int flags = SECTION_WRITE;
907
  if (c6x_in_small_data_p (decl))
908
    {
909
      switch (categorize_decl_for_section (decl, reloc))
910
        {
911
        case SECCAT_SRODATA:
912
          sname = ".rodata";
913
          flags = 0;
914
          break;
915
        case SECCAT_SDATA:
916
          sname = ".neardata";
917
          break;
918
        case SECCAT_SBSS:
919
          sname = ".bss";
920
          flags |= SECTION_BSS;
921
        default:
922
          break;
923
        }
924
    }
925
  else
926
    {
927
      switch (categorize_decl_for_section (decl, reloc))
928
        {
929
        case SECCAT_DATA:
930
          sname = ".fardata";
931
          break;
932
        case SECCAT_DATA_REL:
933
          sname = ".fardata.rel";
934
          break;
935
        case SECCAT_DATA_REL_LOCAL:
936
          sname = ".fardata.rel.local";
937
          break;
938
        case SECCAT_DATA_REL_RO:
939
          sname = ".fardata.rel.ro";
940
          break;
941
        case SECCAT_DATA_REL_RO_LOCAL:
942
          sname = ".fardata.rel.ro.local";
943
          break;
944
        case SECCAT_BSS:
945
          sname = ".far";
946
          flags |= SECTION_BSS;
947
          break;
948
        case SECCAT_RODATA:
949
          sname = ".const";
950
          flags = 0;
951
          break;
952
        case SECCAT_SRODATA:
953
        case SECCAT_SDATA:
954
        case SECCAT_SBSS:
955
          gcc_unreachable ();
956
        default:
957
          break;
958
        }
959
    }
960
  if (sname)
961
    {
962
      /* We might get called with string constants, but get_named_section
963
         doesn't like them as they are not DECLs.  Also, we need to set
964
         flags in that case.  */
965
      if (!DECL_P (decl))
966
        return get_section (sname, flags, NULL);
967
      return get_named_section (decl, sname, reloc);
968
    }
969
 
970
  return default_elf_select_section (decl, reloc, align);
971
}
972
 
973
/* Build up a unique section name, expressed as a
974
   STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
975
   RELOC indicates whether the initial value of EXP requires
976
   link-time relocations.  */
977
 
978
static void ATTRIBUTE_UNUSED
979
c6x_elf_unique_section (tree decl, int reloc)
980
{
981
  const char *prefix = NULL;
982
  /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
983
  bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
984
 
985
  if (c6x_in_small_data_p (decl))
986
    {
987
      switch (categorize_decl_for_section (decl, reloc))
988
        {
989
        case SECCAT_SDATA:
990
          prefix = one_only ? ".s" : ".neardata";
991
          break;
992
        case SECCAT_SBSS:
993
          prefix = one_only ? ".sb" : ".bss";
994
          break;
995
        case SECCAT_SRODATA:
996
          prefix = one_only ? ".s2" : ".rodata";
997
          break;
998
        case SECCAT_RODATA_MERGE_STR:
999
        case SECCAT_RODATA_MERGE_STR_INIT:
1000
        case SECCAT_RODATA_MERGE_CONST:
1001
        case SECCAT_RODATA:
1002
        case SECCAT_DATA:
1003
        case SECCAT_DATA_REL:
1004
        case SECCAT_DATA_REL_LOCAL:
1005
        case SECCAT_DATA_REL_RO:
1006
        case SECCAT_DATA_REL_RO_LOCAL:
1007
          gcc_unreachable ();
1008
        default:
1009
          /* Everything else we place into default sections and hope for the
1010
             best.  */
1011
          break;
1012
        }
1013
    }
1014
  else
1015
    {
1016
      switch (categorize_decl_for_section (decl, reloc))
1017
        {
1018
        case SECCAT_DATA:
1019
        case SECCAT_DATA_REL:
1020
        case SECCAT_DATA_REL_LOCAL:
1021
        case SECCAT_DATA_REL_RO:
1022
        case SECCAT_DATA_REL_RO_LOCAL:
1023
          prefix = one_only ? ".fd" : ".fardata";
1024
          break;
1025
        case SECCAT_BSS:
1026
          prefix = one_only ? ".fb" : ".far";
1027
          break;
1028
        case SECCAT_RODATA:
1029
        case SECCAT_RODATA_MERGE_STR:
1030
        case SECCAT_RODATA_MERGE_STR_INIT:
1031
        case SECCAT_RODATA_MERGE_CONST:
1032
          prefix = one_only ? ".fr" : ".const";
1033
          break;
1034
        case SECCAT_SRODATA:
1035
        case SECCAT_SDATA:
1036
        case SECCAT_SBSS:
1037
          gcc_unreachable ();
1038
        default:
1039
          break;
1040
        }
1041
    }
1042
 
1043
  if (prefix)
1044
    {
1045
      const char *name, *linkonce;
1046
      char *string;
1047
 
1048
      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1049
      name = targetm.strip_name_encoding (name);
1050
 
1051
      /* If we're using one_only, then there needs to be a .gnu.linkonce
1052
         prefix to the section name.  */
1053
      linkonce = one_only ? ".gnu.linkonce" : "";
1054
 
1055
      string = ACONCAT ((linkonce, prefix, ".", name, NULL));
1056
 
1057
      DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
1058
      return;
1059
    }
1060
  default_unique_section (decl, reloc);
1061
}
1062
 
1063
static unsigned int
1064
c6x_section_type_flags (tree decl, const char *name, int reloc)
1065
{
1066
  unsigned int flags = 0;
1067
 
1068
  if (strcmp (name, ".far") == 0
1069
      || strncmp (name, ".far.", 5) == 0)
1070
    flags |= SECTION_BSS;
1071
 
1072
  flags |= default_section_type_flags (decl, name, reloc);
1073
 
1074
  return flags;
1075
}
1076
 
1077
/* Checks whether the given CALL_EXPR would use a caller saved
1078
   register.  This is used to decide whether sibling call optimization
1079
   could be performed on the respective function call.  */
1080
 
1081
static bool
1082
c6x_call_saved_register_used (tree call_expr)
1083
{
1084
  CUMULATIVE_ARGS cum_v;
1085
  cumulative_args_t cum;
1086
  HARD_REG_SET call_saved_regset;
1087
  tree parameter;
1088
  enum machine_mode mode;
1089
  tree type;
1090
  rtx parm_rtx;
1091
  int i;
1092
 
1093
  INIT_CUMULATIVE_ARGS (cum_v, NULL, NULL, 0, 0);
1094
  cum = pack_cumulative_args (&cum_v);
1095
 
1096
  COMPL_HARD_REG_SET (call_saved_regset, call_used_reg_set);
1097
  for (i = 0; i < call_expr_nargs (call_expr); i++)
1098
    {
1099
      parameter = CALL_EXPR_ARG (call_expr, i);
1100
      gcc_assert (parameter);
1101
 
1102
      /* For an undeclared variable passed as parameter we will get
1103
         an ERROR_MARK node here.  */
1104
      if (TREE_CODE (parameter) == ERROR_MARK)
1105
        return true;
1106
 
1107
      type = TREE_TYPE (parameter);
1108
      gcc_assert (type);
1109
 
1110
      mode = TYPE_MODE (type);
1111
      gcc_assert (mode);
1112
 
1113
      if (pass_by_reference (&cum_v, mode, type, true))
1114
        {
1115
          mode = Pmode;
1116
          type = build_pointer_type (type);
1117
        }
1118
 
1119
       parm_rtx = c6x_function_arg (cum, mode, type, 0);
1120
 
1121
       c6x_function_arg_advance (cum, mode, type, 0);
1122
 
1123
       if (!parm_rtx)
1124
         continue;
1125
 
1126
       if (REG_P (parm_rtx)
1127
           && overlaps_hard_reg_set_p (call_saved_regset, GET_MODE (parm_rtx),
1128
                                       REGNO (parm_rtx)))
1129
         return true;
1130
       if (GET_CODE (parm_rtx) == PARALLEL)
1131
         {
1132
           int n = XVECLEN (parm_rtx, 0);
1133
           while (n-- > 0)
1134
             {
1135
               rtx x = XEXP (XVECEXP (parm_rtx, 0, n), 0);
1136
               if (REG_P (x)
1137
                   && overlaps_hard_reg_set_p (call_saved_regset,
1138
                                               GET_MODE (x), REGNO (x)))
1139
                 return true;
1140
             }
1141
         }
1142
    }
1143
  return false;
1144
}
1145
 
1146
/* Decide whether we can make a sibling call to a function.  DECL is the
1147
   declaration of the function being targeted by the call and EXP is the
1148
   CALL_EXPR representing the call.  */
1149
 
1150
static bool
1151
c6x_function_ok_for_sibcall (tree decl, tree exp)
1152
{
1153
  /* Registers A10, A12, B10 and B12 are available as arguments
1154
     register but unfortunately caller saved. This makes functions
1155
     needing these registers for arguments not suitable for
1156
     sibcalls.  */
1157
  if (c6x_call_saved_register_used (exp))
1158
    return false;
1159
 
1160
  if (!flag_pic)
1161
    return true;
1162
 
1163
  if (TARGET_DSBT)
1164
    {
1165
      /* When compiling for DSBT, the calling function must be local,
1166
         so that when we reload B14 in the sibcall epilogue, it will
1167
         not change its value.  */
1168
      struct cgraph_local_info *this_func;
1169
 
1170
      if (!decl)
1171
        /* Not enough information.  */
1172
        return false;
1173
 
1174
      this_func = cgraph_local_info (current_function_decl);
1175
      return this_func->local;
1176
    }
1177
 
1178
  return true;
1179
}
1180
 
1181
/* Return true if DECL is known to be linked into section SECTION.  */
1182
 
1183
static bool
1184
c6x_function_in_section_p (tree decl, section *section)
1185
{
1186
  /* We can only be certain about functions defined in the same
1187
     compilation unit.  */
1188
  if (!TREE_STATIC (decl))
1189
    return false;
1190
 
1191
  /* Make sure that SYMBOL always binds to the definition in this
1192
     compilation unit.  */
1193
  if (!targetm.binds_local_p (decl))
1194
    return false;
1195
 
1196
  /* If DECL_SECTION_NAME is set, assume it is trustworthy.  */
1197
  if (!DECL_SECTION_NAME (decl))
1198
    {
1199
      /* Make sure that we will not create a unique section for DECL.  */
1200
      if (flag_function_sections || DECL_ONE_ONLY (decl))
1201
        return false;
1202
    }
1203
 
1204
  return function_section (decl) == section;
1205
}
1206
 
1207
/* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1208
   as a long call.  */
1209
bool
1210
c6x_long_call_p (rtx op)
1211
{
1212
  tree decl;
1213
 
1214
  if (!TARGET_LONG_CALLS)
1215
    return false;
1216
 
1217
  decl = SYMBOL_REF_DECL (op);
1218
 
1219
  /* Try to determine whether the symbol is in the same section as the current
1220
     function.  Be conservative, and only cater for cases in which the
1221
     whole of the current function is placed in the same section.  */
1222
  if (decl != NULL_TREE
1223
      && !flag_reorder_blocks_and_partition
1224
      && TREE_CODE (decl) == FUNCTION_DECL
1225
      && c6x_function_in_section_p (decl, current_function_section ()))
1226
    return false;
1227
 
1228
  return true;
1229
}
1230
 
1231
/* Emit the sequence for a call.  */
1232
void
1233
c6x_expand_call (rtx retval, rtx address, bool sibcall)
1234
{
1235
  rtx callee = XEXP (address, 0);
1236
  rtx call_insn;
1237
 
1238
  if (!c6x_call_operand (callee, Pmode))
1239
    {
1240
      callee = force_reg (Pmode, callee);
1241
      address = change_address (address, Pmode, callee);
1242
    }
1243
  call_insn = gen_rtx_CALL (VOIDmode, address, const0_rtx);
1244
  if (sibcall)
1245
    {
1246
      call_insn = emit_call_insn (call_insn);
1247
      use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
1248
               gen_rtx_REG (Pmode, REG_B3));
1249
    }
1250
  else
1251
    {
1252
      if (retval == NULL_RTX)
1253
        call_insn = emit_call_insn (call_insn);
1254
      else
1255
        call_insn = emit_call_insn (gen_rtx_SET (GET_MODE (retval), retval,
1256
                                                 call_insn));
1257
    }
1258
  if (flag_pic)
1259
    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
1260
}
1261
 
1262
/* Legitimize PIC addresses.  If the address is already position-independent,
1263
   we return ORIG.  Newly generated position-independent addresses go into a
1264
   reg.  This is REG if nonzero, otherwise we allocate register(s) as
1265
   necessary.  PICREG is the register holding the pointer to the PIC offset
1266
   table.  */
1267
 
1268
static rtx
1269
legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
1270
{
1271
  rtx addr = orig;
1272
  rtx new_rtx = orig;
1273
 
1274
  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
1275
    {
1276
      int unspec = UNSPEC_LOAD_GOT;
1277
      rtx tmp;
1278
 
1279
      if (reg == 0)
1280
        {
1281
          gcc_assert (can_create_pseudo_p ());
1282
          reg = gen_reg_rtx (Pmode);
1283
        }
1284
      if (flag_pic == 2)
1285
        {
1286
          if (can_create_pseudo_p ())
1287
            tmp = gen_reg_rtx (Pmode);
1288
          else
1289
            tmp = reg;
1290
          emit_insn (gen_movsi_gotoff_high (tmp, addr));
1291
          emit_insn (gen_movsi_gotoff_lo_sum (tmp, tmp, addr));
1292
          emit_insn (gen_load_got_gotoff (reg, picreg, tmp));
1293
        }
1294
      else
1295
        {
1296
          tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
1297
          new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
1298
 
1299
          emit_move_insn (reg, new_rtx);
1300
        }
1301
      if (picreg == pic_offset_table_rtx)
1302
        crtl->uses_pic_offset_table = 1;
1303
      return reg;
1304
    }
1305
 
1306
  else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
1307
    {
1308
      rtx base;
1309
 
1310
      if (GET_CODE (addr) == CONST)
1311
        {
1312
          addr = XEXP (addr, 0);
1313
          gcc_assert (GET_CODE (addr) == PLUS);
1314
        }
1315
 
1316
      if (XEXP (addr, 0) == picreg)
1317
        return orig;
1318
 
1319
      if (reg == 0)
1320
        {
1321
          gcc_assert (can_create_pseudo_p ());
1322
          reg = gen_reg_rtx (Pmode);
1323
        }
1324
 
1325
      base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
1326
      addr = legitimize_pic_address (XEXP (addr, 1),
1327
                                     base == reg ? NULL_RTX : reg,
1328
                                     picreg);
1329
 
1330
      if (GET_CODE (addr) == CONST_INT)
1331
        {
1332
          gcc_assert (! reload_in_progress && ! reload_completed);
1333
          addr = force_reg (Pmode, addr);
1334
        }
1335
 
1336
      if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
1337
        {
1338
          base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
1339
          addr = XEXP (addr, 1);
1340
        }
1341
 
1342
      return gen_rtx_PLUS (Pmode, base, addr);
1343
    }
1344
 
1345
  return new_rtx;
1346
}
1347
 
1348
/* Expand a move operation in mode MODE.  The operands are in OPERANDS.
1349
   Returns true if no further code must be generated, false if the caller
1350
   should generate an insn to move OPERANDS[1] to OPERANDS[0].  */
1351
 
1352
bool
1353
expand_move (rtx *operands, enum machine_mode mode)
1354
{
1355
  rtx dest = operands[0];
1356
  rtx op = operands[1];
1357
 
1358
  if ((reload_in_progress | reload_completed) == 0
1359
      && GET_CODE (dest) == MEM && GET_CODE (op) != REG)
1360
    operands[1] = force_reg (mode, op);
1361
  else if (mode == SImode && symbolic_operand (op, SImode))
1362
    {
1363
      if (flag_pic)
1364
        {
1365
          if (sdata_symbolic_operand (op, SImode))
1366
            {
1367
              emit_insn (gen_load_sdata_pic (dest, pic_offset_table_rtx, op));
1368
              crtl->uses_pic_offset_table = 1;
1369
              return true;
1370
            }
1371
          else
1372
            {
1373
              rtx temp = (reload_completed || reload_in_progress
1374
                          ? dest : gen_reg_rtx (Pmode));
1375
 
1376
              operands[1] = legitimize_pic_address (op, temp,
1377
                                                    pic_offset_table_rtx);
1378
            }
1379
        }
1380
      else if (reload_completed
1381
               && !sdata_symbolic_operand (op, SImode))
1382
        {
1383
          emit_insn (gen_movsi_high (dest, op));
1384
          emit_insn (gen_movsi_lo_sum (dest, dest, op));
1385
          return true;
1386
        }
1387
    }
1388
  return false;
1389
}
1390
 
1391
/* This function is called when we're about to expand an integer compare
1392
   operation which performs COMPARISON.  It examines the second operand,
1393
   and if it is an integer constant that cannot be used directly on the
1394
   current machine in a comparison insn, it returns true.  */
1395
bool
1396
c6x_force_op_for_comparison_p (enum rtx_code code, rtx op)
1397
{
1398
  if (!CONST_INT_P (op) || satisfies_constraint_Iu4 (op))
1399
    return false;
1400
 
1401
  if ((code == EQ || code == LT || code == GT)
1402
       && !satisfies_constraint_Is5 (op))
1403
    return true;
1404
  if ((code == GTU || code == LTU)
1405
      && (!TARGET_INSNS_64 || !satisfies_constraint_Iu5 (op)))
1406
    return true;
1407
 
1408
  return false;
1409
}
1410
 
1411
/* Emit comparison instruction if necessary, returning the expression
1412
   that holds the compare result in the proper mode.  Return the comparison
1413
   that should be used in the jump insn.  */
1414
 
1415
rtx
1416
c6x_expand_compare (rtx comparison, enum machine_mode mode)
1417
{
1418
  enum rtx_code code = GET_CODE (comparison);
1419
  rtx op0 = XEXP (comparison, 0);
1420
  rtx op1 = XEXP (comparison, 1);
1421
  rtx cmp;
1422
  enum rtx_code jump_code = code;
1423
  enum machine_mode op_mode = GET_MODE (op0);
1424
 
1425
  if (op_mode == DImode && (code == NE || code == EQ) && op1 == const0_rtx)
1426
    {
1427
      rtx t = gen_reg_rtx (SImode);
1428
      emit_insn (gen_iorsi3 (t, gen_lowpart (SImode, op0),
1429
                             gen_highpart (SImode, op0)));
1430
      op_mode = SImode;
1431
      cmp = t;
1432
    }
1433
  else if (op_mode == DImode)
1434
    {
1435
      rtx lo[2], high[2];
1436
      rtx cmp1, cmp2;
1437
 
1438
      if (code == NE || code == GEU || code == LEU || code == GE || code == LE)
1439
        {
1440
          code = reverse_condition (code);
1441
          jump_code = EQ;
1442
        }
1443
      else
1444
        jump_code = NE;
1445
 
1446
      split_di (&op0, 1, lo, high);
1447
      split_di (&op1, 1, lo + 1, high + 1);
1448
 
1449
      if (c6x_force_op_for_comparison_p (code, high[1])
1450
          || c6x_force_op_for_comparison_p (EQ, high[1]))
1451
        high[1] = force_reg (SImode, high[1]);
1452
 
1453
      cmp1 = gen_reg_rtx (SImode);
1454
      cmp2 = gen_reg_rtx (SImode);
1455
      emit_insn (gen_rtx_SET (VOIDmode, cmp1,
1456
                              gen_rtx_fmt_ee (code, SImode, high[0], high[1])));
1457
      if (code == EQ)
1458
        {
1459
          if (c6x_force_op_for_comparison_p (code, lo[1]))
1460
            lo[1] = force_reg (SImode, lo[1]);
1461
          emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1462
                                  gen_rtx_fmt_ee (code, SImode, lo[0], lo[1])));
1463
          emit_insn (gen_andsi3 (cmp1, cmp1, cmp2));
1464
        }
1465
      else
1466
        {
1467
          emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1468
                                  gen_rtx_EQ (SImode, high[0], high[1])));
1469
          if (code == GT)
1470
            code = GTU;
1471
          else if (code == LT)
1472
            code = LTU;
1473
          if (c6x_force_op_for_comparison_p (code, lo[1]))
1474
            lo[1] = force_reg (SImode, lo[1]);
1475
          emit_insn (gen_cmpsi_and (cmp2, gen_rtx_fmt_ee (code, SImode,
1476
                                                          lo[0], lo[1]),
1477
                                    lo[0], lo[1], cmp2));
1478
          emit_insn (gen_iorsi3 (cmp1, cmp1, cmp2));
1479
        }
1480
      cmp = cmp1;
1481
    }
1482
  else if (TARGET_FP && !flag_finite_math_only
1483
           && (op_mode == DFmode || op_mode == SFmode)
1484
           && code != EQ && code != NE && code != LT && code != GT
1485
           && code != UNLE && code != UNGE)
1486
    {
1487
      enum rtx_code code1, code2, code3;
1488
      rtx (*fn) (rtx, rtx, rtx, rtx, rtx);
1489
 
1490
      jump_code = NE;
1491
      code3 = UNKNOWN;
1492
      switch (code)
1493
        {
1494
        case UNLT:
1495
        case UNGT:
1496
          jump_code = EQ;
1497
          /* fall through */
1498
        case LE:
1499
        case GE:
1500
          code1 = code == LE || code == UNGT ? LT : GT;
1501
          code2 = EQ;
1502
          break;
1503
 
1504
        case UNORDERED:
1505
          jump_code = EQ;
1506
          /* fall through */
1507
        case ORDERED:
1508
          code3 = EQ;
1509
          /* fall through */
1510
        case LTGT:
1511
          code1 = LT;
1512
          code2 = GT;
1513
          break;
1514
 
1515
        case UNEQ:
1516
          code1 = LT;
1517
          code2 = GT;
1518
          jump_code = EQ;
1519
          break;
1520
 
1521
        default:
1522
          gcc_unreachable ();
1523
        }
1524
 
1525
      cmp = gen_reg_rtx (SImode);
1526
      emit_insn (gen_rtx_SET (VOIDmode, cmp,
1527
                              gen_rtx_fmt_ee (code1, SImode, op0, op1)));
1528
      fn = op_mode == DFmode ? gen_cmpdf_ior : gen_cmpsf_ior;
1529
      emit_insn (fn (cmp, gen_rtx_fmt_ee (code2, SImode, op0, op1),
1530
                     op0, op1, cmp));
1531
      if (code3 != UNKNOWN)
1532
        emit_insn (fn (cmp, gen_rtx_fmt_ee (code3, SImode, op0, op1),
1533
                       op0, op1, cmp));
1534
    }
1535
  else if (op_mode == SImode && (code == NE || code == EQ) && op1 == const0_rtx)
1536
    cmp = op0;
1537
  else
1538
    {
1539
      bool is_fp_libfunc;
1540
      is_fp_libfunc = !TARGET_FP && (op_mode == DFmode || op_mode == SFmode);
1541
 
1542
      if ((code == NE || code == GEU || code == LEU || code == GE || code == LE)
1543
          && !is_fp_libfunc)
1544
        {
1545
          code = reverse_condition (code);
1546
          jump_code = EQ;
1547
        }
1548
      else if (code == UNGE)
1549
        {
1550
          code = LT;
1551
          jump_code = EQ;
1552
        }
1553
      else if (code == UNLE)
1554
        {
1555
          code = GT;
1556
          jump_code = EQ;
1557
        }
1558
      else
1559
        jump_code = NE;
1560
 
1561
      if (is_fp_libfunc)
1562
        {
1563
          rtx insns;
1564
          rtx libfunc;
1565
          switch (code)
1566
            {
1567
            case EQ:
1568
              libfunc = op_mode == DFmode ? eqdf_libfunc : eqsf_libfunc;
1569
              break;
1570
            case NE:
1571
              libfunc = op_mode == DFmode ? nedf_libfunc : nesf_libfunc;
1572
              break;
1573
            case GT:
1574
              libfunc = op_mode == DFmode ? gtdf_libfunc : gtsf_libfunc;
1575
              break;
1576
            case GE:
1577
              libfunc = op_mode == DFmode ? gedf_libfunc : gesf_libfunc;
1578
              break;
1579
            case LT:
1580
              libfunc = op_mode == DFmode ? ltdf_libfunc : ltsf_libfunc;
1581
              break;
1582
            case LE:
1583
              libfunc = op_mode == DFmode ? ledf_libfunc : lesf_libfunc;
1584
              break;
1585
            default:
1586
              gcc_unreachable ();
1587
            }
1588
          start_sequence ();
1589
 
1590
          cmp = emit_library_call_value (libfunc, 0, LCT_CONST, SImode, 2,
1591
                                         op0, op_mode, op1, op_mode);
1592
          insns = get_insns ();
1593
          end_sequence ();
1594
 
1595
          emit_libcall_block (insns, cmp, cmp,
1596
                              gen_rtx_fmt_ee (code, SImode, op0, op1));
1597
        }
1598
      else
1599
        {
1600
          cmp = gen_reg_rtx (SImode);
1601
          if (c6x_force_op_for_comparison_p (code, op1))
1602
            op1 = force_reg (SImode, op1);
1603
          emit_insn (gen_rtx_SET (VOIDmode, cmp,
1604
                                  gen_rtx_fmt_ee (code, SImode, op0, op1)));
1605
        }
1606
    }
1607
 
1608
  return gen_rtx_fmt_ee (jump_code, mode, cmp, const0_rtx);
1609
}
1610
 
1611
/* Return one word of double-word value OP.  HIGH_P is true to select the
1612
   high part, false to select the low part.  When encountering auto-increment
1613
   addressing, we make the assumption that the low part is going to be accessed
1614
   first.  */
1615
 
1616
rtx
1617
c6x_subword (rtx op, bool high_p)
1618
{
1619
  unsigned int byte;
1620
  enum machine_mode mode;
1621
 
1622
  mode = GET_MODE (op);
1623
  if (mode == VOIDmode)
1624
    mode = DImode;
1625
 
1626
  if (TARGET_BIG_ENDIAN ? !high_p : high_p)
1627
    byte = UNITS_PER_WORD;
1628
  else
1629
    byte = 0;
1630
 
1631
  if (MEM_P (op))
1632
    {
1633
      rtx addr = XEXP (op, 0);
1634
      if (GET_CODE (addr) == PLUS || REG_P (addr))
1635
        return adjust_address (op, word_mode, byte);
1636
      /* FIXME: should really support autoincrement addressing for
1637
         multi-word modes.  */
1638
      gcc_unreachable ();
1639
    }
1640
 
1641
  return simplify_gen_subreg (word_mode, op, mode, byte);
1642
}
1643
 
1644
/* Split one or more DImode RTL references into pairs of SImode
1645
   references.  The RTL can be REG, offsettable MEM, integer constant, or
1646
   CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
1647
   split and "num" is its length.  lo_half and hi_half are output arrays
1648
   that parallel "operands".  */
1649
 
1650
void
1651
split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1652
{
1653
  while (num--)
1654
    {
1655
      rtx op = operands[num];
1656
 
1657
      lo_half[num] = c6x_subword (op, false);
1658
      hi_half[num] = c6x_subword (op, true);
1659
    }
1660
}
1661
 
1662
/* Return true if VAL is a mask valid for a clr instruction.  */
1663
bool
1664
c6x_valid_mask_p (HOST_WIDE_INT val)
1665
{
1666
  int i;
1667
  for (i = 0; i < 32; i++)
1668
    if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1669
      break;
1670
  for (; i < 32; i++)
1671
    if (val & ((unsigned HOST_WIDE_INT)1 << i))
1672
      break;
1673
  for (; i < 32; i++)
1674
    if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1675
      return false;
1676
  return true;
1677
}
1678
 
1679
/* Expand a block move for a movmemM pattern.  */
1680
 
1681
bool
1682
c6x_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
1683
                   rtx expected_align_exp ATTRIBUTE_UNUSED,
1684
                   rtx expected_size_exp ATTRIBUTE_UNUSED)
1685
{
1686
  unsigned HOST_WIDE_INT align = 1;
1687
  unsigned HOST_WIDE_INT src_mem_align, dst_mem_align, min_mem_align;
1688
  unsigned HOST_WIDE_INT count = 0, offset = 0;
1689
  unsigned int biggest_move = TARGET_STDW ? 8 : 4;
1690
 
1691
  if (CONST_INT_P (align_exp))
1692
    align = INTVAL (align_exp);
1693
 
1694
  src_mem_align = MEM_ALIGN (src) / BITS_PER_UNIT;
1695
  dst_mem_align = MEM_ALIGN (dst) / BITS_PER_UNIT;
1696
  min_mem_align = MIN (src_mem_align, dst_mem_align);
1697
 
1698
  if (min_mem_align > align)
1699
    align = min_mem_align / BITS_PER_UNIT;
1700
  if (src_mem_align < align)
1701
    src_mem_align = align;
1702
  if (dst_mem_align < align)
1703
    dst_mem_align = align;
1704
 
1705
  if (CONST_INT_P (count_exp))
1706
    count = INTVAL (count_exp);
1707
  else
1708
    return false;
1709
 
1710
  /* Make sure we don't need to care about overflow later on.  */
1711
  if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
1712
    return false;
1713
 
1714
  if (count >= 28 && (count & 3) == 0 && align >= 4)
1715
    {
1716
      tree dst_expr = MEM_EXPR (dst);
1717
      tree src_expr = MEM_EXPR (src);
1718
      rtx fn = TARGET_INSNS_64PLUS ? strasgi64p_libfunc : strasgi_libfunc;
1719
      rtx srcreg = force_reg (Pmode, XEXP (src, 0));
1720
      rtx dstreg = force_reg (Pmode, XEXP (dst, 0));
1721
 
1722
      if (src_expr)
1723
        mark_addressable (src_expr);
1724
      if (dst_expr)
1725
        mark_addressable (dst_expr);
1726
      emit_library_call (fn, LCT_NORMAL, VOIDmode, 3,
1727
                         dstreg, Pmode, srcreg, Pmode, count_exp, SImode);
1728
      return true;
1729
    }
1730
 
1731
  if (biggest_move > align && !TARGET_INSNS_64)
1732
    biggest_move = align;
1733
 
1734
  if (count / biggest_move > 7)
1735
    return false;
1736
 
1737
  while (count > 0)
1738
    {
1739
      rtx reg, reg_lowpart;
1740
      enum machine_mode srcmode, dstmode;
1741
      unsigned HOST_WIDE_INT src_size, dst_size, src_left;
1742
      int shift;
1743
      rtx srcmem, dstmem;
1744
 
1745
      while (biggest_move > count)
1746
        biggest_move /= 2;
1747
 
1748
      src_size = dst_size = biggest_move;
1749
      if (src_size > src_mem_align && src_size == 2)
1750
        src_size = 1;
1751
      if (dst_size > dst_mem_align && dst_size == 2)
1752
        dst_size = 1;
1753
 
1754
      if (dst_size > src_size)
1755
        dst_size = src_size;
1756
 
1757
      srcmode = mode_for_size (src_size * BITS_PER_UNIT, MODE_INT, 0);
1758
      dstmode = mode_for_size (dst_size * BITS_PER_UNIT, MODE_INT, 0);
1759
      if (src_size >= 4)
1760
        reg_lowpart = reg = gen_reg_rtx (srcmode);
1761
      else
1762
        {
1763
          reg = gen_reg_rtx (SImode);
1764
          reg_lowpart = gen_lowpart (srcmode, reg);
1765
        }
1766
 
1767
      srcmem = adjust_address (copy_rtx (src), srcmode, offset);
1768
 
1769
      if (src_size > src_mem_align)
1770
        {
1771
          enum insn_code icode = (srcmode == SImode ? CODE_FOR_movmisalignsi
1772
                                  : CODE_FOR_movmisaligndi);
1773
          emit_insn (GEN_FCN (icode) (reg_lowpart, srcmem));
1774
        }
1775
      else
1776
        emit_move_insn (reg_lowpart, srcmem);
1777
 
1778
      src_left = src_size;
1779
      shift = TARGET_BIG_ENDIAN ? (src_size - dst_size) * BITS_PER_UNIT  : 0;
1780
      while (src_left > 0)
1781
        {
1782
          rtx dstreg = reg_lowpart;
1783
 
1784
          if (src_size > dst_size)
1785
            {
1786
              rtx srcword = reg;
1787
              int shift_amount = shift & (BITS_PER_WORD - 1);
1788
              if (src_size > 4)
1789
                srcword = operand_subword_force (srcword, src_left >= 4 ? 0 : 4,
1790
                                                 SImode);
1791
              if (shift_amount > 0)
1792
                {
1793
                  dstreg = gen_reg_rtx (SImode);
1794
                  emit_insn (gen_lshrsi3 (dstreg, srcword,
1795
                                          GEN_INT (shift_amount)));
1796
                }
1797
              else
1798
                dstreg = srcword;
1799
              dstreg = gen_lowpart (dstmode, dstreg);
1800
            }
1801
 
1802
          dstmem = adjust_address (copy_rtx (dst), dstmode, offset);
1803
          if (dst_size > dst_mem_align)
1804
            {
1805
              enum insn_code icode = (dstmode == SImode ? CODE_FOR_movmisalignsi
1806
                                      : CODE_FOR_movmisaligndi);
1807
              emit_insn (GEN_FCN (icode) (dstmem, dstreg));
1808
            }
1809
          else
1810
            emit_move_insn (dstmem, dstreg);
1811
 
1812
          if (TARGET_BIG_ENDIAN)
1813
            shift -= dst_size * BITS_PER_UNIT;
1814
          else
1815
            shift += dst_size * BITS_PER_UNIT;
1816
          offset += dst_size;
1817
          src_left -= dst_size;
1818
        }
1819
      count -= src_size;
1820
    }
1821
  return true;
1822
}
1823
 
1824
/* Subroutine of print_address_operand, print a single address offset OFF for
1825
   a memory access of mode MEM_MODE, choosing between normal form and scaled
1826
   form depending on the type of the insn.  Misaligned memory references must
1827
   use the scaled form.  */
1828
 
1829
static void
1830
print_address_offset (FILE *file, rtx off, enum machine_mode mem_mode)
1831
{
1832
  rtx pat;
1833
 
1834
  if (c6x_current_insn != NULL_RTX)
1835
    {
1836
      pat = PATTERN (c6x_current_insn);
1837
      if (GET_CODE (pat) == COND_EXEC)
1838
        pat = COND_EXEC_CODE (pat);
1839
      if (GET_CODE (pat) == PARALLEL)
1840
        pat = XVECEXP (pat, 0, 0);
1841
 
1842
      if (GET_CODE (pat) == SET
1843
          && GET_CODE (SET_SRC (pat)) == UNSPEC
1844
          && XINT (SET_SRC (pat), 1) == UNSPEC_MISALIGNED_ACCESS)
1845
        {
1846
          gcc_assert (CONST_INT_P (off)
1847
                      && (INTVAL (off) & (GET_MODE_SIZE (mem_mode) - 1)) == 0);
1848
          fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
1849
                   INTVAL (off) / GET_MODE_SIZE (mem_mode));
1850
          return;
1851
        }
1852
    }
1853
  fputs ("(", file);
1854
  output_address (off);
1855
  fputs (")", file);
1856
}
1857
 
1858
static bool
1859
c6x_print_operand_punct_valid_p (unsigned char c)
1860
{
1861
  return c == '$' || c == '.' || c == '|';
1862
}
1863
 
1864
static void c6x_print_operand (FILE *, rtx, int);
1865
 
1866
/* Subroutine of c6x_print_operand; used to print a memory reference X to FILE.  */
1867
 
1868
static void
1869
c6x_print_address_operand (FILE *file, rtx x, enum machine_mode mem_mode)
1870
{
1871
  rtx off;
1872
  switch (GET_CODE (x))
1873
    {
1874
    case PRE_MODIFY:
1875
    case POST_MODIFY:
1876
      if (GET_CODE (x) == POST_MODIFY)
1877
        output_address (XEXP (x, 0));
1878
      off = XEXP (XEXP (x, 1), 1);
1879
      if (XEXP (x, 0) == stack_pointer_rtx)
1880
        {
1881
          if (GET_CODE (x) == PRE_MODIFY)
1882
            gcc_assert (INTVAL (off) > 0);
1883
          else
1884
            gcc_assert (INTVAL (off) < 0);
1885
        }
1886
      if (CONST_INT_P (off) && INTVAL (off) < 0)
1887
        {
1888
          fprintf (file, "--");
1889
          off = GEN_INT (-INTVAL (off));
1890
        }
1891
      else
1892
        fprintf (file, "++");
1893
      if (GET_CODE (x) == PRE_MODIFY)
1894
        output_address (XEXP (x, 0));
1895
      print_address_offset (file, off, mem_mode);
1896
      break;
1897
 
1898
    case PLUS:
1899
      off = XEXP (x, 1);
1900
      if (CONST_INT_P (off) && INTVAL (off) < 0)
1901
        {
1902
          fprintf (file, "-");
1903
          off = GEN_INT (-INTVAL (off));
1904
        }
1905
      else
1906
        fprintf (file, "+");
1907
      output_address (XEXP (x, 0));
1908
      print_address_offset (file, off, mem_mode);
1909
      break;
1910
 
1911
    case PRE_DEC:
1912
      gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1913
      fprintf (file, "--");
1914
      output_address (XEXP (x, 0));
1915
      fprintf (file, "[1]");
1916
      break;
1917
    case PRE_INC:
1918
      fprintf (file, "++");
1919
      output_address (XEXP (x, 0));
1920
      fprintf (file, "[1]");
1921
      break;
1922
    case POST_INC:
1923
      gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1924
      output_address (XEXP (x, 0));
1925
      fprintf (file, "++[1]");
1926
      break;
1927
    case POST_DEC:
1928
      output_address (XEXP (x, 0));
1929
      fprintf (file, "--[1]");
1930
      break;
1931
 
1932
    case SYMBOL_REF:
1933
    case CONST:
1934
    case LABEL_REF:
1935
      gcc_assert (sdata_symbolic_operand (x, Pmode));
1936
      fprintf (file, "+B14(");
1937
      output_addr_const (file, x);
1938
      fprintf (file, ")");
1939
      break;
1940
 
1941
    case UNSPEC:
1942
      switch (XINT (x, 1))
1943
        {
1944
        case UNSPEC_LOAD_GOT:
1945
          fputs ("$GOT(", file);
1946
          output_addr_const (file, XVECEXP (x, 0, 0));
1947
          fputs (")", file);
1948
          break;
1949
        case UNSPEC_LOAD_SDATA:
1950
          output_addr_const (file, XVECEXP (x, 0, 0));
1951
          break;
1952
        default:
1953
          gcc_unreachable ();
1954
        }
1955
      break;
1956
 
1957
    default:
1958
      gcc_assert (GET_CODE (x) != MEM);
1959
      c6x_print_operand (file, x, 0);
1960
      break;
1961
    }
1962
}
1963
 
1964
/* Return a single character, which is either 'l', 's', 'd' or 'm', which
1965
   specifies the functional unit used by INSN.  */
1966
 
1967
char
1968
c6x_get_unit_specifier (rtx insn)
1969
{
1970
  enum attr_units units;
1971
 
1972
  if (insn_info)
1973
    {
1974
      int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
1975
      return c6x_unit_names[unit][0];
1976
    }
1977
 
1978
  units = get_attr_units (insn);
1979
  switch (units)
1980
    {
1981
    case UNITS_D:
1982
    case UNITS_DL:
1983
    case UNITS_DS:
1984
    case UNITS_DLS:
1985
    case UNITS_D_ADDR:
1986
      return 'd';
1987
      break;
1988
    case UNITS_L:
1989
    case UNITS_LS:
1990
      return 'l';
1991
      break;
1992
    case UNITS_S:
1993
      return 's';
1994
      break;
1995
    case UNITS_M:
1996
      return 'm';
1997
      break;
1998
    default:
1999
      gcc_unreachable ();
2000
    }
2001
}
2002
 
2003
/* Prints the unit specifier field.  */
2004
static void
2005
c6x_print_unit_specifier_field (FILE *file, rtx insn)
2006
{
2007
  enum attr_units units = get_attr_units (insn);
2008
  enum attr_cross cross = get_attr_cross (insn);
2009
  enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
2010
  int half;
2011
  char unitspec;
2012
 
2013
  if (units == UNITS_D_ADDR)
2014
    {
2015
      enum attr_addr_regfile arf = get_attr_addr_regfile (insn);
2016
      int t_half;
2017
      gcc_assert (arf != ADDR_REGFILE_UNKNOWN);
2018
      half = arf == ADDR_REGFILE_A ? 1 : 2;
2019
      t_half = rf == DEST_REGFILE_A ? 1 : 2;
2020
      fprintf (file, ".d%dt%d", half, t_half);
2021
      return;
2022
    }
2023
 
2024
  if (insn_info)
2025
    {
2026
      int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
2027
      fputs (".", file);
2028
      fputs (c6x_unit_names[unit], file);
2029
      if (cross == CROSS_Y)
2030
        fputs ("x", file);
2031
      return;
2032
    }
2033
 
2034
  gcc_assert (rf != DEST_REGFILE_UNKNOWN);
2035
  unitspec = c6x_get_unit_specifier (insn);
2036
  half = rf == DEST_REGFILE_A ? 1 : 2;
2037
  fprintf (file, ".%c%d%s", unitspec, half, cross == CROSS_Y ? "x" : "");
2038
}
2039
 
2040
/* Output assembly language output for the address ADDR to FILE.  */
2041
static void
2042
c6x_print_operand_address (FILE *file, rtx addr)
2043
{
2044
  c6x_print_address_operand (file, addr, VOIDmode);
2045
}
2046
 
2047
/* Print an operand, X, to FILE, with an optional modifier in CODE.
2048
 
2049
   Meaning of CODE:
2050
   $ -- print the unit specifier field for the instruction.
2051
   . -- print the predicate for the instruction or an emptry string for an
2052
        unconditional one.
2053
   | -- print "||" if the insn should be issued in parallel with the previous
2054
        one.
2055
 
2056
   C -- print an opcode suffix for a reversed condition
2057
   d -- H, W or D as a suffix for ADDA, based on the factor given by the
2058
        operand
2059
   D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2060
        the operand
2061
   J -- print a predicate
2062
   j -- like J, but use reverse predicate
2063
   k -- treat a CONST_INT as a register number and print it as a register
2064
   k -- like k, but print out a doubleword register
2065
   n -- print an integer operand, negated
2066
   p -- print the low part of a DImode register
2067
   P -- print the high part of a DImode register
2068
   r -- print the absolute value of an integer operand, shifted right by 1
2069
   R -- print the absolute value of an integer operand, shifted right by 2
2070
   f -- the first clear bit in an integer operand assumed to be a mask for
2071
        a clr instruction
2072
   F -- the last clear bit in such a mask
2073
   s -- the first set bit in an integer operand assumed to be a mask for
2074
        a set instruction
2075
   S -- the last set bit in such a mask
2076
   U -- print either 1 or 2, depending on the side of the machine used by
2077
        the operand  */
2078
 
2079
static void
2080
c6x_print_operand (FILE *file, rtx x, int code)
2081
{
2082
  int i;
2083
  HOST_WIDE_INT v;
2084
  tree t;
2085
  enum machine_mode mode;
2086
 
2087
  if (code == '|')
2088
    {
2089
      if (GET_MODE (c6x_current_insn) != TImode)
2090
        fputs ("||", file);
2091
      return;
2092
    }
2093
  if (code == '$')
2094
    {
2095
      c6x_print_unit_specifier_field (file, c6x_current_insn);
2096
      return;
2097
    }
2098
 
2099
  if (code == '.')
2100
    {
2101
      x = current_insn_predicate;
2102
      if (x)
2103
        {
2104
          unsigned int regno = REGNO (XEXP (x, 0));
2105
          fputs ("[", file);
2106
          if (GET_CODE (x) == EQ)
2107
            fputs ("!", file);
2108
          fputs (reg_names [regno], file);
2109
          fputs ("]", file);
2110
        }
2111
      return;
2112
    }
2113
 
2114
  mode = GET_MODE (x);
2115
 
2116
  switch (code)
2117
    {
2118
    case 'C':
2119
    case 'c':
2120
      {
2121
        enum rtx_code c = GET_CODE (x);
2122
        if (code == 'C')
2123
          c = swap_condition (c);
2124
        fputs (GET_RTX_NAME (c), file);
2125
      }
2126
      return;
2127
 
2128
    case 'J':
2129
    case 'j':
2130
      {
2131
        unsigned int regno = REGNO (XEXP (x, 0));
2132
        if ((GET_CODE (x) == EQ) == (code == 'J'))
2133
          fputs ("!", file);
2134
        fputs (reg_names [regno], file);
2135
      }
2136
      return;
2137
 
2138
    case 'k':
2139
      gcc_assert (GET_CODE (x) == CONST_INT);
2140
      v = INTVAL (x);
2141
      fprintf (file, "%s", reg_names[v]);
2142
      return;
2143
    case 'K':
2144
      gcc_assert (GET_CODE (x) == CONST_INT);
2145
      v = INTVAL (x);
2146
      gcc_assert ((v & 1) == 0);
2147
      fprintf (file, "%s:%s", reg_names[v + 1], reg_names[v]);
2148
      return;
2149
 
2150
    case 's':
2151
    case 'S':
2152
    case 'f':
2153
    case 'F':
2154
      gcc_assert (GET_CODE (x) == CONST_INT);
2155
      v = INTVAL (x);
2156
      for (i = 0; i < 32; i++)
2157
        {
2158
          HOST_WIDE_INT tst = v & 1;
2159
          if (((code == 'f' || code == 'F') && !tst)
2160
              || ((code == 's' || code == 'S') && tst))
2161
            break;
2162
          v >>= 1;
2163
        }
2164
      if (code == 'f' || code == 's')
2165
        {
2166
          fprintf (file, "%d", i);
2167
          return;
2168
        }
2169
      for (;i < 32; i++)
2170
        {
2171
          HOST_WIDE_INT tst = v & 1;
2172
          if ((code == 'F' && tst) || (code == 'S' && !tst))
2173
            break;
2174
          v >>= 1;
2175
        }
2176
      fprintf (file, "%d", i - 1);
2177
      return;
2178
 
2179
    case 'n':
2180
      gcc_assert (GET_CODE (x) == CONST_INT);
2181
      output_addr_const (file, GEN_INT (-INTVAL (x)));
2182
      return;
2183
 
2184
    case 'r':
2185
      gcc_assert (GET_CODE (x) == CONST_INT);
2186
      v = INTVAL (x);
2187
      if (v < 0)
2188
        v = -v;
2189
      output_addr_const (file, GEN_INT (v >> 1));
2190
      return;
2191
 
2192
    case 'R':
2193
      gcc_assert (GET_CODE (x) == CONST_INT);
2194
      v = INTVAL (x);
2195
      if (v < 0)
2196
        v = -v;
2197
      output_addr_const (file, GEN_INT (v >> 2));
2198
      return;
2199
 
2200
    case 'd':
2201
      gcc_assert (GET_CODE (x) == CONST_INT);
2202
      v = INTVAL (x);
2203
      fputs (v == 2 ? "h" : v == 4 ? "w" : "d", file);
2204
      return;
2205
 
2206
    case 'p':
2207
    case 'P':
2208
      gcc_assert (GET_CODE (x) == REG);
2209
      v = REGNO (x);
2210
      if (code == 'P')
2211
        v++;
2212
      fputs (reg_names[v], file);
2213
      return;
2214
 
2215
    case 'D':
2216
      v = 0;
2217
      if (GET_CODE (x) == CONST)
2218
        {
2219
          x = XEXP (x, 0);
2220
          gcc_assert (GET_CODE (x) == PLUS);
2221
          gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT);
2222
          v = INTVAL (XEXP (x, 1));
2223
          x = XEXP (x, 0);
2224
 
2225
        }
2226
      gcc_assert (GET_CODE (x) == SYMBOL_REF);
2227
 
2228
      t = SYMBOL_REF_DECL (x);
2229
      if (DECL_P (t))
2230
        v |= DECL_ALIGN_UNIT (t);
2231
      else
2232
        v |= TYPE_ALIGN_UNIT (TREE_TYPE (t));
2233
      if (v & 1)
2234
        fputs ("b", file);
2235
      else if (v & 2)
2236
        fputs ("h", file);
2237
      else
2238
        fputs ("w", file);
2239
      return;
2240
 
2241
    case 'U':
2242
      if (MEM_P (x))
2243
        {
2244
          x = XEXP (x, 0);
2245
          if (GET_CODE (x) == PLUS
2246
              || GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
2247
            x = XEXP (x, 0);
2248
          if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
2249
            {
2250
              gcc_assert (sdata_symbolic_operand (x, Pmode));
2251
              fputs ("2", file);
2252
              return;
2253
            }
2254
        }
2255
      gcc_assert (REG_P (x));
2256
      if (A_REGNO_P (REGNO (x)))
2257
        fputs ("1", file);
2258
      if (B_REGNO_P (REGNO (x)))
2259
        fputs ("2", file);
2260
      return;
2261
 
2262
    default:
2263
      switch (GET_CODE (x))
2264
        {
2265
        case REG:
2266
          if (GET_MODE_SIZE (mode) == 8)
2267
            fprintf (file, "%s:%s", reg_names[REGNO (x) + 1],
2268
                     reg_names[REGNO (x)]);
2269
          else
2270
            fprintf (file, "%s", reg_names[REGNO (x)]);
2271
          break;
2272
 
2273
        case MEM:
2274
          fputc ('*', file);
2275
          gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
2276
          c6x_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
2277
          break;
2278
 
2279
        case SYMBOL_REF:
2280
          fputc ('(', file);
2281
          output_addr_const (file, x);
2282
          fputc (')', file);
2283
          break;
2284
 
2285
        case CONST_INT:
2286
          output_addr_const (file, x);
2287
          break;
2288
 
2289
        case CONST_DOUBLE:
2290
          output_operand_lossage ("invalid const_double operand");
2291
          break;
2292
 
2293
        default:
2294
          output_addr_const (file, x);
2295
        }
2296
    }
2297
}
2298
 
2299
/* Return TRUE if OP is a valid memory address with a base register of
2300
   class C.  If SMALL_OFFSET is true, we disallow memory references which would
2301
   require a long offset with B14/B15.  */
2302
 
2303
bool
2304
c6x_mem_operand (rtx op, enum reg_class c, bool small_offset)
2305
{
2306
  enum machine_mode mode = GET_MODE (op);
2307
  rtx base = XEXP (op, 0);
2308
  switch (GET_CODE (base))
2309
    {
2310
    case REG:
2311
      break;
2312
    case PLUS:
2313
      if (small_offset
2314
          && (XEXP (base, 0) == stack_pointer_rtx
2315
              || XEXP (base, 0) == pic_offset_table_rtx))
2316
        {
2317
          if (!c6x_legitimate_address_p_1 (mode, base, true, true))
2318
            return false;
2319
        }
2320
 
2321
      /* fall through */
2322
    case PRE_INC:
2323
    case PRE_DEC:
2324
    case PRE_MODIFY:
2325
    case POST_INC:
2326
    case POST_DEC:
2327
    case POST_MODIFY:
2328
      base = XEXP (base, 0);
2329
      break;
2330
 
2331
    case CONST:
2332
    case LABEL_REF:
2333
    case SYMBOL_REF:
2334
      gcc_assert (sdata_symbolic_operand (base, Pmode));
2335
      return !small_offset && c == B_REGS;
2336
 
2337
    default:
2338
      return false;
2339
    }
2340
  return TEST_HARD_REG_BIT (reg_class_contents[ (int) (c)], REGNO (base));
2341
}
2342
 
2343
/* Returns true if X is a valid address for use in a memory reference
2344
   of mode MODE.  If STRICT is true, we do not allow pseudo registers
2345
   in the address.  NO_LARGE_OFFSET is true if we are examining an
2346
   address for use in a load or store misaligned instruction, or
2347
   recursively examining an operand inside a PRE/POST_MODIFY.  */
2348
 
2349
bool
2350
c6x_legitimate_address_p_1 (enum machine_mode mode, rtx x, bool strict,
2351
                            bool no_large_offset)
2352
{
2353
  int size, size1;
2354
  HOST_WIDE_INT off;
2355
  enum rtx_code code = GET_CODE (x);
2356
 
2357
  switch (code)
2358
    {
2359
    case PRE_MODIFY:
2360
    case POST_MODIFY:
2361
      /* We can't split these into word-sized pieces yet.  */
2362
      if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2363
        return false;
2364
      if (GET_CODE (XEXP (x, 1)) != PLUS)
2365
        return false;
2366
      if (!c6x_legitimate_address_p_1 (mode, XEXP (x, 1), strict, true))
2367
        return false;
2368
      if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
2369
        return false;
2370
 
2371
      /* fall through */
2372
    case PRE_INC:
2373
    case PRE_DEC:
2374
    case POST_INC:
2375
    case POST_DEC:
2376
      /* We can't split these into word-sized pieces yet.  */
2377
      if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2378
        return false;
2379
      x = XEXP (x, 0);
2380
      if (!REG_P (x))
2381
        return false;
2382
 
2383
      /* fall through */
2384
    case REG:
2385
      if (strict)
2386
        return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x));
2387
      else
2388
        return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x));
2389
 
2390
    case PLUS:
2391
      if (!REG_P (XEXP (x, 0))
2392
          || !c6x_legitimate_address_p_1 (mode, XEXP (x, 0), strict, false))
2393
        return false;
2394
      /* We cannot ensure currently that both registers end up in the
2395
         same register file.  */
2396
      if (REG_P (XEXP (x, 1)))
2397
        return false;
2398
 
2399
      if (mode == BLKmode)
2400
        size = 4;
2401
      else if (mode == VOIDmode)
2402
        /* ??? This can happen during ivopts.  */
2403
        size = 1;
2404
      else
2405
        size = GET_MODE_SIZE (mode);
2406
 
2407
      if (flag_pic
2408
          && GET_CODE (XEXP (x, 1)) == UNSPEC
2409
          && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_SDATA
2410
          && XEXP (x, 0) == pic_offset_table_rtx
2411
          && sdata_symbolic_operand (XVECEXP (XEXP (x, 1), 0, 0), SImode))
2412
        return !no_large_offset && size <= 4;
2413
      if (flag_pic == 1
2414
          && mode == Pmode
2415
          && GET_CODE (XEXP (x, 1)) == UNSPEC
2416
          && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_GOT
2417
          && XEXP (x, 0) == pic_offset_table_rtx
2418
          && (GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == SYMBOL_REF
2419
              || GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == LABEL_REF))
2420
        return !no_large_offset;
2421
      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2422
        return false;
2423
 
2424
      off = INTVAL (XEXP (x, 1));
2425
 
2426
      /* If the machine does not have doubleword load/stores, we'll use
2427
         word size accesses.  */
2428
      size1 = size;
2429
      if (size == 2 * UNITS_PER_WORD && !TARGET_STDW)
2430
        size = UNITS_PER_WORD;
2431
 
2432
      if (((HOST_WIDE_INT)size1 - 1) & off)
2433
        return false;
2434
      off /= size;
2435
      if (off > -32 && off < (size1 == size ? 32 : 28))
2436
        return true;
2437
      if (no_large_offset || code != PLUS || XEXP (x, 0) != stack_pointer_rtx
2438
          || size1 > UNITS_PER_WORD)
2439
        return false;
2440
      return off >= 0 && off < 32768;
2441
 
2442
    case CONST:
2443
    case SYMBOL_REF:
2444
    case LABEL_REF:
2445
      return (!no_large_offset
2446
              /* With -fpic, we must wrap it in an unspec to show the B14
2447
                 dependency.  */
2448
              && !flag_pic
2449
              && GET_MODE_SIZE (mode) <= UNITS_PER_WORD
2450
              && sdata_symbolic_operand (x, Pmode));
2451
 
2452
    default:
2453
      return false;
2454
    }
2455
}
2456
 
2457
static bool
2458
c6x_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
2459
{
2460
  return c6x_legitimate_address_p_1 (mode, x, strict, false);
2461
}
2462
 
2463
static bool
2464
c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
2465
                           rtx x ATTRIBUTE_UNUSED)
2466
{
2467
  return true;
2468
}
2469
 
2470
/* Implements TARGET_PREFERRED_RENAME_CLASS.  */
2471
static reg_class_t
2472
c6x_preferred_rename_class (reg_class_t cl)
2473
{
2474
  if (cl == A_REGS)
2475
    return NONPREDICATE_A_REGS;
2476
  if (cl == B_REGS)
2477
    return NONPREDICATE_B_REGS;
2478
  if (cl == ALL_REGS || cl == GENERAL_REGS)
2479
    return NONPREDICATE_REGS;
2480
  return NO_REGS;
2481
}
2482
 
2483
/* Implements FINAL_PRESCAN_INSN.  */
2484
void
2485
c6x_final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
2486
                        int noperands ATTRIBUTE_UNUSED)
2487
{
2488
  c6x_current_insn = insn;
2489
}
2490
 
2491
/* A structure to describe the stack layout of a function.  The layout is
2492
   as follows:
2493
 
2494
   [saved frame pointer (or possibly padding0)]
2495
   --> incoming stack pointer, new hard frame pointer
2496
   [saved call-used regs]
2497
   [optional padding1]
2498
   --> soft frame pointer
2499
   [frame]
2500
   [outgoing arguments]
2501
   [optional padding2]
2502
 
2503
  The structure members are laid out in this order.  */
2504
 
2505
struct c6x_frame
2506
{
2507
  int padding0;
2508
  /* Number of registers to save.  */
2509
  int nregs;
2510
  int padding1;
2511
  HOST_WIDE_INT frame;
2512
  int outgoing_arguments_size;
2513
  int padding2;
2514
 
2515
  HOST_WIDE_INT to_allocate;
2516
  /* The offsets relative to the incoming stack pointer (which
2517
     becomes HARD_FRAME_POINTER).  */
2518
  HOST_WIDE_INT frame_pointer_offset;
2519
  HOST_WIDE_INT b3_offset;
2520
 
2521
  /* True if we should call push_rts/pop_rts to save and restore
2522
     registers.  */
2523
  bool push_rts;
2524
};
2525
 
2526
/* Return true if we need to save and modify the PIC register in the
2527
   prologue.  */
2528
 
2529
static bool
2530
must_reload_pic_reg_p (void)
2531
{
2532
  struct cgraph_local_info *i = NULL;
2533
 
2534
  if (!TARGET_DSBT)
2535
    return false;
2536
 
2537
  i = cgraph_local_info (current_function_decl);
2538
 
2539
  if ((crtl->uses_pic_offset_table || !current_function_is_leaf) && !i->local)
2540
    return true;
2541
  return false;
2542
}
2543
 
2544
/* Return 1 if we need to save REGNO.  */
2545
static int
2546
c6x_save_reg (unsigned int regno)
2547
{
2548
  return ((df_regs_ever_live_p (regno)
2549
           && !call_used_regs[regno]
2550
           && !fixed_regs[regno])
2551
          || (regno == RETURN_ADDR_REGNO
2552
              && (df_regs_ever_live_p (regno)
2553
                  || !current_function_is_leaf))
2554
          || (regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ()));
2555
}
2556
 
2557
/* Examine the number of regs NREGS we've determined we must save.
2558
   Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2559
   prologue and epilogue.  */
2560
 
2561
static bool
2562
use_push_rts_p (int nregs)
2563
{
2564
  if (TARGET_INSNS_64PLUS && optimize_function_for_size_p (cfun)
2565
      && !cfun->machine->contains_sibcall
2566
      && !cfun->returns_struct
2567
      && !TARGET_LONG_CALLS
2568
      && nregs >= 6 && !frame_pointer_needed)
2569
    return true;
2570
  return false;
2571
}
2572
 
2573
/* Return number of saved general prupose registers.  */
2574
 
2575
int
2576
c6x_nsaved_regs (void)
2577
{
2578
  int nregs = 0;
2579
  int regno;
2580
 
2581
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
2582
    if (c6x_save_reg (regno))
2583
      nregs++;
2584
  return nregs;
2585
}
2586
 
2587
/* The safe debug order mandated by the ABI.  */
2588
static unsigned reg_save_order[] =
2589
{
2590
  REG_A10, REG_A11, REG_A12, REG_A13,
2591
  REG_A14, REG_B3,
2592
  REG_B10, REG_B11, REG_B12, REG_B13,
2593
  REG_B14, REG_A15
2594
};
2595
 
2596
#define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2597
 
2598
/* Compute the layout of the stack frame and store it in FRAME.  */
2599
 
2600
static void
2601
c6x_compute_frame_layout (struct c6x_frame *frame)
2602
{
2603
  HOST_WIDE_INT size = get_frame_size ();
2604
  HOST_WIDE_INT offset;
2605
  int nregs;
2606
 
2607
  /* We use the four bytes which are technically inside the caller's frame,
2608
     usually to save the frame pointer.  */
2609
  offset = -4;
2610
  frame->padding0 = 0;
2611
  nregs = c6x_nsaved_regs ();
2612
  frame->push_rts = false;
2613
  frame->b3_offset = 0;
2614
  if (use_push_rts_p (nregs))
2615
    {
2616
      frame->push_rts = true;
2617
      frame->b3_offset = (TARGET_BIG_ENDIAN ? -12 : -13) * 4;
2618
      nregs = 14;
2619
    }
2620
  else if (c6x_save_reg (REG_B3))
2621
    {
2622
      int idx;
2623
      for (idx = N_SAVE_ORDER - 1; reg_save_order[idx] != REG_B3; idx--)
2624
        {
2625
          if (c6x_save_reg (reg_save_order[idx]))
2626
            frame->b3_offset -= 4;
2627
        }
2628
    }
2629
  frame->nregs = nregs;
2630
 
2631
  if (size == 0 && nregs == 0)
2632
    {
2633
      frame->padding0 = 4;
2634
      frame->padding1 = frame->padding2 = 0;
2635
      frame->frame_pointer_offset = frame->to_allocate = 0;
2636
      frame->outgoing_arguments_size = 0;
2637
      return;
2638
    }
2639
 
2640
  if (!frame->push_rts)
2641
    offset += frame->nregs * 4;
2642
 
2643
  if (offset == 0 && size == 0 && crtl->outgoing_args_size == 0
2644
      && !current_function_is_leaf)
2645
    /* Don't use the bottom of the caller's frame if we have no
2646
       allocation of our own and call other functions.  */
2647
    frame->padding0 = frame->padding1 = 4;
2648
  else if (offset & 4)
2649
    frame->padding1 = 4;
2650
  else
2651
    frame->padding1 = 0;
2652
 
2653
  offset += frame->padding0 + frame->padding1;
2654
  frame->frame_pointer_offset = offset;
2655
  offset += size;
2656
 
2657
  frame->outgoing_arguments_size = crtl->outgoing_args_size;
2658
  offset += frame->outgoing_arguments_size;
2659
 
2660
  if ((offset & 4) == 0)
2661
    frame->padding2 = 8;
2662
  else
2663
    frame->padding2 = 4;
2664
  frame->to_allocate = offset + frame->padding2;
2665
}
2666
 
2667
/* Return the offset between two registers, one to be eliminated, and the other
2668
   its replacement, at the start of a routine.  */
2669
 
2670
HOST_WIDE_INT
2671
c6x_initial_elimination_offset (int from, int to)
2672
{
2673
  struct c6x_frame frame;
2674
  c6x_compute_frame_layout (&frame);
2675
 
2676
  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
2677
    return 0;
2678
  else if (from == FRAME_POINTER_REGNUM
2679
           && to == HARD_FRAME_POINTER_REGNUM)
2680
    return -frame.frame_pointer_offset;
2681
  else
2682
    {
2683
      gcc_assert (to == STACK_POINTER_REGNUM);
2684
 
2685
      if (from == ARG_POINTER_REGNUM)
2686
        return frame.to_allocate + (frame.push_rts ? 56 : 0);
2687
 
2688
      gcc_assert (from == FRAME_POINTER_REGNUM);
2689
      return frame.to_allocate - frame.frame_pointer_offset;
2690
    }
2691
}
2692
 
2693
/* Given FROM and TO register numbers, say whether this elimination is
2694
   allowed.  Frame pointer elimination is automatically handled.  */
2695
 
2696
static bool
2697
c6x_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
2698
{
2699
  if (to == STACK_POINTER_REGNUM)
2700
    return !frame_pointer_needed;
2701
  return true;
2702
}
2703
 
2704
/* Emit insns to increment the stack pointer by OFFSET.  If
2705
   FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2706
   Does nothing if the offset is zero.  */
2707
 
2708
static void
2709
emit_add_sp_const (HOST_WIDE_INT offset, bool frame_related_p)
2710
{
2711
  rtx to_add = GEN_INT (offset);
2712
  rtx orig_to_add = to_add;
2713
  rtx insn;
2714
 
2715
  if (offset == 0)
2716
    return;
2717
 
2718
  if (offset < -32768 || offset > 32767)
2719
    {
2720
      rtx reg = gen_rtx_REG (SImode, REG_A0);
2721
      rtx low = GEN_INT (trunc_int_for_mode (offset, HImode));
2722
 
2723
      insn = emit_insn (gen_movsi_high (reg, low));
2724
      if (frame_related_p)
2725
        RTX_FRAME_RELATED_P (insn) = 1;
2726
      insn = emit_insn (gen_movsi_lo_sum (reg, reg, to_add));
2727
      if (frame_related_p)
2728
        RTX_FRAME_RELATED_P (insn) = 1;
2729
      to_add = reg;
2730
    }
2731
  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2732
                                to_add));
2733
  if (frame_related_p)
2734
    {
2735
      if (REG_P (to_add))
2736
        add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2737
                      gen_rtx_SET (VOIDmode, stack_pointer_rtx,
2738
                                   gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2739
                                                 orig_to_add)));
2740
 
2741
      RTX_FRAME_RELATED_P (insn) = 1;
2742
    }
2743
}
2744
 
2745
/* Prologue and epilogue.  */
2746
void
2747
c6x_expand_prologue (void)
2748
{
2749
  struct c6x_frame frame;
2750
  rtx insn, mem;
2751
  int nsaved = 0;
2752
  HOST_WIDE_INT initial_offset, off, added_already;
2753
 
2754
  c6x_compute_frame_layout (&frame);
2755
 
2756
  if (flag_stack_usage_info)
2757
    current_function_static_stack_size = frame.to_allocate;
2758
 
2759
  initial_offset = -frame.to_allocate;
2760
  if (frame.push_rts)
2761
    {
2762
      emit_insn (gen_push_rts ());
2763
      nsaved = frame.nregs;
2764
    }
2765
 
2766
  /* If the offsets would be too large for the memory references we will
2767
     create to save registers, do the stack allocation in two parts.
2768
     Ensure by subtracting 8 that we don't store to the word pointed to
2769
     by the stack pointer.  */
2770
  if (initial_offset < -32768)
2771
    initial_offset = -frame.frame_pointer_offset - 8;
2772
 
2773
  if (frame.to_allocate > 0)
2774
    gcc_assert (initial_offset != 0);
2775
 
2776
  off = -initial_offset + 4 - frame.padding0;
2777
 
2778
  mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2779
 
2780
  added_already = 0;
2781
  if (frame_pointer_needed)
2782
    {
2783
      rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2784
      /* We go through some contortions here to both follow the ABI's
2785
         recommendation that FP == incoming SP, and to avoid writing or
2786
         reading the word pointed to by the stack pointer.  */
2787
      rtx addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
2788
                                      gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2789
                                                    GEN_INT (-8)));
2790
      insn = emit_move_insn (gen_frame_mem (Pmode, addr), fp_reg);
2791
      RTX_FRAME_RELATED_P (insn) = 1;
2792
      nsaved++;
2793
      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, stack_pointer_rtx,
2794
                                    GEN_INT (8)));
2795
      RTX_FRAME_RELATED_P (insn) = 1;
2796
      off -= 4;
2797
      added_already = -8;
2798
    }
2799
 
2800
  emit_add_sp_const (initial_offset - added_already, true);
2801
 
2802
  if (nsaved < frame.nregs)
2803
    {
2804
      unsigned i;
2805
 
2806
      for (i = 0; i < N_SAVE_ORDER; i++)
2807
        {
2808
          int idx = N_SAVE_ORDER - i - 1;
2809
          unsigned regno = reg_save_order[idx];
2810
          rtx reg;
2811
          enum machine_mode save_mode = SImode;
2812
 
2813
          if (regno == REG_A15 && frame_pointer_needed)
2814
            /* Already saved.  */
2815
            continue;
2816
          if (!c6x_save_reg (regno))
2817
            continue;
2818
 
2819
          if (TARGET_STDW && (off & 4) == 0 && off <= 256
2820
              && (regno & 1) == 1
2821
              && i + 1 < N_SAVE_ORDER
2822
              && reg_save_order[idx - 1] == regno - 1
2823
              && c6x_save_reg (regno - 1))
2824
            {
2825
              save_mode = DImode;
2826
              regno--;
2827
              i++;
2828
            }
2829
          reg = gen_rtx_REG (save_mode, regno);
2830
          off -= GET_MODE_SIZE (save_mode);
2831
 
2832
          insn = emit_move_insn (adjust_address (mem, save_mode, off),
2833
                                 reg);
2834
          RTX_FRAME_RELATED_P (insn) = 1;
2835
 
2836
          nsaved += HARD_REGNO_NREGS (regno, save_mode);
2837
        }
2838
    }
2839
  gcc_assert (nsaved == frame.nregs);
2840
  emit_add_sp_const (-frame.to_allocate - initial_offset, true);
2841
  if (must_reload_pic_reg_p ())
2842
    {
2843
      if (dsbt_decl == NULL)
2844
        {
2845
          tree t;
2846
 
2847
          t = build_index_type (integer_one_node);
2848
          t = build_array_type (integer_type_node, t);
2849
          t = build_decl (BUILTINS_LOCATION, VAR_DECL,
2850
                          get_identifier ("__c6xabi_DSBT_BASE"), t);
2851
          DECL_ARTIFICIAL (t) = 1;
2852
          DECL_IGNORED_P (t) = 1;
2853
          DECL_EXTERNAL (t) = 1;
2854
          TREE_STATIC (t) = 1;
2855
          TREE_PUBLIC (t) = 1;
2856
          TREE_USED (t) = 1;
2857
 
2858
          dsbt_decl = t;
2859
        }
2860
      emit_insn (gen_setup_dsbt (pic_offset_table_rtx,
2861
                                 XEXP (DECL_RTL (dsbt_decl), 0)));
2862
    }
2863
}
2864
 
2865
void
2866
c6x_expand_epilogue (bool sibcall)
2867
{
2868
  unsigned i;
2869
  struct c6x_frame frame;
2870
  rtx mem;
2871
  HOST_WIDE_INT off;
2872
  int nsaved = 0;
2873
 
2874
  c6x_compute_frame_layout (&frame);
2875
 
2876
  mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2877
 
2878
  /* Insert a dummy set/use of the stack pointer.  This creates a
2879
     scheduler barrier between the prologue saves and epilogue restores. */
2880
  emit_insn (gen_epilogue_barrier (stack_pointer_rtx, stack_pointer_rtx));
2881
 
2882
  /* If the offsets would be too large for the memory references we will
2883
     create to restore registers, do a preliminary stack adjustment here.  */
2884
  off = frame.to_allocate - frame.frame_pointer_offset + frame.padding1;
2885
  if (frame.push_rts)
2886
    {
2887
      nsaved = frame.nregs;
2888
    }
2889
  else
2890
    {
2891
      if (frame.to_allocate > 32768)
2892
        {
2893
          /* Don't add the entire offset so that we leave an unused word
2894
             above the stack pointer.  */
2895
          emit_add_sp_const ((off - 16) & ~7, false);
2896
          off &= 7;
2897
          off += 16;
2898
        }
2899
      for (i = 0; i < N_SAVE_ORDER; i++)
2900
        {
2901
          unsigned regno = reg_save_order[i];
2902
          rtx reg;
2903
          enum machine_mode save_mode = SImode;
2904
 
2905
          if (!c6x_save_reg (regno))
2906
            continue;
2907
          if (regno == REG_A15 && frame_pointer_needed)
2908
            continue;
2909
 
2910
          if (TARGET_STDW && (off & 4) == 0 && off < 256
2911
              && (regno & 1) == 0
2912
              && i + 1 < N_SAVE_ORDER
2913
              && reg_save_order[i + 1] == regno + 1
2914
              && c6x_save_reg (regno + 1))
2915
            {
2916
              save_mode = DImode;
2917
              i++;
2918
            }
2919
          reg = gen_rtx_REG (save_mode, regno);
2920
 
2921
          emit_move_insn (reg, adjust_address (mem, save_mode, off));
2922
 
2923
          off += GET_MODE_SIZE (save_mode);
2924
          nsaved += HARD_REGNO_NREGS (regno, save_mode);
2925
        }
2926
    }
2927
  if (!frame_pointer_needed)
2928
    emit_add_sp_const (off + frame.padding0 - 4, false);
2929
  else
2930
    {
2931
      rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2932
      rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
2933
                                      gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2934
                                                    GEN_INT (8)));
2935
      emit_insn (gen_addsi3 (stack_pointer_rtx, hard_frame_pointer_rtx,
2936
                             GEN_INT (-8)));
2937
      emit_move_insn (fp_reg, gen_frame_mem (Pmode, addr));
2938
      nsaved++;
2939
    }
2940
  gcc_assert (nsaved == frame.nregs);
2941
  if (!sibcall)
2942
    {
2943
      if (frame.push_rts)
2944
        emit_jump_insn (gen_pop_rts ());
2945
      else
2946
        emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
2947
                                                          RETURN_ADDR_REGNO)));
2948
    }
2949
}
2950
 
2951
/* Return the value of the return address for the frame COUNT steps up
2952
   from the current frame, after the prologue.
2953
   We punt for everything but the current frame by returning const0_rtx.  */
2954
 
2955
rtx
2956
c6x_return_addr_rtx (int count)
2957
{
2958
  if (count != 0)
2959
    return const0_rtx;
2960
 
2961
  return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNO);
2962
}
2963
 
2964
/* Return true iff TYPE is one of the shadow types.  */
2965
static bool
2966
shadow_type_p (enum attr_type type)
2967
{
2968
  return (type == TYPE_SHADOW || type == TYPE_LOAD_SHADOW
2969
          || type == TYPE_MULT_SHADOW);
2970
}
2971
 
2972
/* Return true iff INSN is a shadow pattern.  */
2973
static bool
2974
shadow_p (rtx insn)
2975
{
2976
  if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2977
    return false;
2978
  return shadow_type_p (get_attr_type (insn));
2979
}
2980
 
2981
/* Return true iff INSN is a shadow or blockage pattern.  */
2982
static bool
2983
shadow_or_blockage_p (rtx insn)
2984
{
2985
  enum attr_type type;
2986
  if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2987
    return false;
2988
  type = get_attr_type (insn);
2989
  return shadow_type_p (type) || type == TYPE_BLOCKAGE;
2990
}
2991
 
2992
/* Translate UNITS into a bitmask of units we can reserve for this
2993
   insn.  */
2994
static int
2995
get_reservation_flags (enum attr_units units)
2996
{
2997
  switch (units)
2998
    {
2999
    case UNITS_D:
3000
    case UNITS_D_ADDR:
3001
      return RESERVATION_FLAG_D;
3002
    case UNITS_L:
3003
      return RESERVATION_FLAG_L;
3004
    case UNITS_S:
3005
      return RESERVATION_FLAG_S;
3006
    case UNITS_M:
3007
      return RESERVATION_FLAG_M;
3008
    case UNITS_LS:
3009
      return RESERVATION_FLAG_LS;
3010
    case UNITS_DL:
3011
      return RESERVATION_FLAG_DL;
3012
    case UNITS_DS:
3013
      return RESERVATION_FLAG_DS;
3014
    case UNITS_DLS:
3015
      return RESERVATION_FLAG_DLS;
3016
    default:
3017
      return 0;
3018
    }
3019
}
3020
 
3021
/* Compute the side of the machine used by INSN, which reserves UNITS.
3022
   This must match the reservations in the scheduling description.  */
3023
static int
3024
get_insn_side (rtx insn, enum attr_units units)
3025
{
3026
  if (units == UNITS_D_ADDR)
3027
    return (get_attr_addr_regfile (insn) == ADDR_REGFILE_A ? 0 : 1);
3028
  else
3029
    {
3030
      enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
3031
      if (rf == DEST_REGFILE_ANY)
3032
        return get_attr_type (insn) == TYPE_BRANCH ? 0 : 1;
3033
      else
3034
        return rf == DEST_REGFILE_A ? 0 : 1;
3035
    }
3036
}
3037
 
3038
/* After scheduling, walk the insns between HEAD and END and assign unit
3039
   reservations.  */
3040
static void
3041
assign_reservations (rtx head, rtx end)
3042
{
3043
  rtx insn;
3044
  for (insn = head; insn != NEXT_INSN (end); insn = NEXT_INSN (insn))
3045
    {
3046
      unsigned int sched_mask, reserved;
3047
      rtx within, last;
3048
      int pass;
3049
      int rsrv[2];
3050
      int rsrv_count[2][4];
3051
      int i;
3052
 
3053
      if (GET_MODE (insn) != TImode)
3054
        continue;
3055
 
3056
      reserved = 0;
3057
      last = NULL_RTX;
3058
      /* Find the last insn in the packet.  It has a state recorded for it,
3059
         which we can use to determine the units we should be using.  */
3060
      for (within = insn;
3061
           (within != NEXT_INSN (end)
3062
            && (within == insn || GET_MODE (within) != TImode));
3063
           within = NEXT_INSN (within))
3064
        {
3065
          int icode;
3066
          if (!NONDEBUG_INSN_P (within))
3067
            continue;
3068
          icode = recog_memoized (within);
3069
          if (icode < 0)
3070
            continue;
3071
          if (shadow_p (within))
3072
            continue;
3073
          if (INSN_INFO_ENTRY (INSN_UID (within)).reservation != 0)
3074
            reserved |= 1 << INSN_INFO_ENTRY (INSN_UID (within)).reservation;
3075
          last = within;
3076
        }
3077
      if (last == NULL_RTX)
3078
        continue;
3079
 
3080
      sched_mask = INSN_INFO_ENTRY (INSN_UID (last)).unit_mask;
3081
      sched_mask &= ~reserved;
3082
 
3083
      memset (rsrv_count, 0, sizeof rsrv_count);
3084
      rsrv[0] = rsrv[1] = ~0;
3085
      for (i = 0; i < 8; i++)
3086
        {
3087
          int side = i / 4;
3088
          int unit = i & 3;
3089
          unsigned unit_bit = 1 << (unit + side * UNIT_QID_SIDE_OFFSET);
3090
          /* Clear the bits which we expect to reserve in the following loop,
3091
             leaving the ones set which aren't present in the scheduler's
3092
             state and shouldn't be reserved.  */
3093
          if (sched_mask & unit_bit)
3094
            rsrv[i / 4] &= ~(1 << unit);
3095
        }
3096
 
3097
      /* Walk through the insns that occur in the same cycle.  We use multiple
3098
         passes to assign units, assigning for insns with the most specific
3099
         requirements first.  */
3100
      for (pass = 0; pass < 4; pass++)
3101
        for (within = insn;
3102
             (within != NEXT_INSN (end)
3103
              && (within == insn || GET_MODE (within) != TImode));
3104
             within = NEXT_INSN (within))
3105
          {
3106
            int uid = INSN_UID (within);
3107
            int this_rsrv, side;
3108
            int icode;
3109
            enum attr_units units;
3110
            enum attr_type type;
3111
            int j;
3112
 
3113
            if (!NONDEBUG_INSN_P (within))
3114
              continue;
3115
            icode = recog_memoized (within);
3116
            if (icode < 0)
3117
              continue;
3118
            if (INSN_INFO_ENTRY (uid).reservation != 0)
3119
              continue;
3120
            units = get_attr_units (within);
3121
            type = get_attr_type (within);
3122
            this_rsrv = get_reservation_flags (units);
3123
            if (this_rsrv == 0)
3124
              continue;
3125
            side = get_insn_side (within, units);
3126
 
3127
            /* Certain floating point instructions are treated specially.  If
3128
               an insn can choose between units it can reserve, and its
3129
               reservation spans more than one cycle, the reservation contains
3130
               special markers in the first cycle to help us reconstruct what
3131
               the automaton chose.  */
3132
            if ((type == TYPE_ADDDP || type == TYPE_FP4)
3133
                && units == UNITS_LS)
3134
              {
3135
                int test1_code = ((type == TYPE_FP4 ? UNIT_QID_FPL1 : UNIT_QID_ADDDPL1)
3136
                                  + side * UNIT_QID_SIDE_OFFSET);
3137
                int test2_code = ((type == TYPE_FP4 ? UNIT_QID_FPS1 : UNIT_QID_ADDDPS1)
3138
                                  + side * UNIT_QID_SIDE_OFFSET);
3139
                if ((sched_mask & (1 << test1_code)) != 0)
3140
                  {
3141
                    this_rsrv = RESERVATION_FLAG_L;
3142
                    sched_mask &= ~(1 << test1_code);
3143
                  }
3144
                else if ((sched_mask & (1 << test2_code)) != 0)
3145
                  {
3146
                    this_rsrv = RESERVATION_FLAG_S;
3147
                    sched_mask &= ~(1 << test2_code);
3148
                  }
3149
              }
3150
 
3151
            if ((this_rsrv & (this_rsrv - 1)) == 0)
3152
              {
3153
                int t = exact_log2 (this_rsrv) + side * UNIT_QID_SIDE_OFFSET;
3154
                rsrv[side] |= this_rsrv;
3155
                INSN_INFO_ENTRY (uid).reservation = t;
3156
                continue;
3157
              }
3158
 
3159
            if (pass == 1)
3160
              {
3161
                for (j = 0; j < 4; j++)
3162
                  if (this_rsrv & (1 << j))
3163
                    rsrv_count[side][j]++;
3164
                continue;
3165
              }
3166
            if ((pass == 2 && this_rsrv != RESERVATION_FLAG_DLS)
3167
                || (pass == 3 && this_rsrv == RESERVATION_FLAG_DLS))
3168
              {
3169
                int best = -1, best_cost = INT_MAX;
3170
                for (j = 0; j < 4; j++)
3171
                  if ((this_rsrv & (1 << j))
3172
                      && !(rsrv[side] & (1 << j))
3173
                      && rsrv_count[side][j] < best_cost)
3174
                    {
3175
                      best_cost = rsrv_count[side][j];
3176
                      best = j;
3177
                    }
3178
                gcc_assert (best != -1);
3179
                rsrv[side] |= 1 << best;
3180
                for (j = 0; j < 4; j++)
3181
                  if ((this_rsrv & (1 << j)) && j != best)
3182
                    rsrv_count[side][j]--;
3183
 
3184
                INSN_INFO_ENTRY (uid).reservation
3185
                  = best + side * UNIT_QID_SIDE_OFFSET;
3186
              }
3187
          }
3188
    }
3189
}
3190
 
3191
/* Return a factor by which to weight unit imbalances for a reservation
3192
   R.  */
3193
static int
3194
unit_req_factor (enum unitreqs r)
3195
{
3196
  switch (r)
3197
    {
3198
    case UNIT_REQ_D:
3199
    case UNIT_REQ_L:
3200
    case UNIT_REQ_S:
3201
    case UNIT_REQ_M:
3202
    case UNIT_REQ_X:
3203
    case UNIT_REQ_T:
3204
      return 1;
3205
    case UNIT_REQ_DL:
3206
    case UNIT_REQ_LS:
3207
    case UNIT_REQ_DS:
3208
      return 2;
3209
    case UNIT_REQ_DLS:
3210
      return 3;
3211
    default:
3212
      gcc_unreachable ();
3213
    }
3214
}
3215
 
3216
/* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3217
   requirements.  Returns zero if INSN can't be handled, otherwise
3218
   either one or two to show how many of the two pairs are in use.
3219
   REQ1 is always used, it holds what is normally thought of as the
3220
   instructions reservation, e.g. UNIT_REQ_DL.  REQ2 is used to either
3221
   describe a cross path, or for loads/stores, the T unit.  */
3222
static int
3223
get_unit_reqs (rtx insn, int *req1, int *side1, int *req2, int *side2)
3224
{
3225
  enum attr_units units;
3226
  enum attr_cross cross;
3227
  int side, req;
3228
 
3229
  if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
3230
    return 0;
3231
  units = get_attr_units (insn);
3232
  if (units == UNITS_UNKNOWN)
3233
    return 0;
3234
  side = get_insn_side (insn, units);
3235
  cross = get_attr_cross (insn);
3236
 
3237
  req = (units == UNITS_D ? UNIT_REQ_D
3238
         : units == UNITS_D_ADDR ? UNIT_REQ_D
3239
         : units == UNITS_DL ? UNIT_REQ_DL
3240
         : units == UNITS_DS ? UNIT_REQ_DS
3241
         : units == UNITS_L ? UNIT_REQ_L
3242
         : units == UNITS_LS ? UNIT_REQ_LS
3243
         : units == UNITS_S ? UNIT_REQ_S
3244
         : units == UNITS_M ? UNIT_REQ_M
3245
         : units == UNITS_DLS ? UNIT_REQ_DLS
3246
         : -1);
3247
  gcc_assert (req != -1);
3248
  *req1 = req;
3249
  *side1 = side;
3250
  if (units == UNITS_D_ADDR)
3251
    {
3252
      *req2 = UNIT_REQ_T;
3253
      *side2 = side ^ (cross == CROSS_Y ? 1 : 0);
3254
      return 2;
3255
    }
3256
  else if (cross == CROSS_Y)
3257
    {
3258
      *req2 = UNIT_REQ_X;
3259
      *side2 = side;
3260
      return 2;
3261
    }
3262
  return 1;
3263
}
3264
 
3265
/* Walk the insns between and including HEAD and TAIL, and mark the
3266
   resource requirements in the unit_reqs table.  */
3267
static void
3268
count_unit_reqs (unit_req_table reqs, rtx head, rtx tail)
3269
{
3270
  rtx insn;
3271
 
3272
  memset (reqs, 0, sizeof (unit_req_table));
3273
 
3274
  for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
3275
    {
3276
      int side1, side2, req1, req2;
3277
 
3278
      switch (get_unit_reqs (insn, &req1, &side1, &req2, &side2))
3279
        {
3280
        case 2:
3281
          reqs[side2][req2]++;
3282
          /* fall through */
3283
        case 1:
3284
          reqs[side1][req1]++;
3285
          break;
3286
        }
3287
    }
3288
}
3289
 
3290
/* Update the table REQS by merging more specific unit reservations into
3291
   more general ones, i.e. counting (for example) UNIT_REQ_D also in
3292
   UNIT_REQ_DL, DS, and DLS.  */
3293
static void
3294
merge_unit_reqs (unit_req_table reqs)
3295
{
3296
  int side;
3297
  for (side = 0; side < 2; side++)
3298
    {
3299
      int d = reqs[side][UNIT_REQ_D];
3300
      int l = reqs[side][UNIT_REQ_L];
3301
      int s = reqs[side][UNIT_REQ_S];
3302
      int dl = reqs[side][UNIT_REQ_DL];
3303
      int ls = reqs[side][UNIT_REQ_LS];
3304
      int ds = reqs[side][UNIT_REQ_DS];
3305
 
3306
      reqs[side][UNIT_REQ_DL] += d;
3307
      reqs[side][UNIT_REQ_DL] += l;
3308
      reqs[side][UNIT_REQ_DS] += d;
3309
      reqs[side][UNIT_REQ_DS] += s;
3310
      reqs[side][UNIT_REQ_LS] += l;
3311
      reqs[side][UNIT_REQ_LS] += s;
3312
      reqs[side][UNIT_REQ_DLS] += ds + dl + ls + d + l + s;
3313
    }
3314
}
3315
 
3316
/* Examine the table REQS and return a measure of unit imbalance by comparing
3317
   the two sides of the machine.  If, for example, D1 is used twice and D2
3318
   used not at all, the return value should be 1 in the absence of other
3319
   imbalances.  */
3320
static int
3321
unit_req_imbalance (unit_req_table reqs)
3322
{
3323
  int val = 0;
3324
  int i;
3325
 
3326
  for (i = 0; i < UNIT_REQ_MAX; i++)
3327
    {
3328
      int factor = unit_req_factor ((enum unitreqs) i);
3329
      int diff = abs (reqs[0][i] - reqs[1][i]);
3330
      val += (diff + factor - 1) / factor / 2;
3331
    }
3332
  return val;
3333
}
3334
 
3335
/* Return the resource-constrained minimum iteration interval given the
3336
   data in the REQS table.  This must have been processed with
3337
   merge_unit_reqs already.  */
3338
static int
3339
res_mii (unit_req_table reqs)
3340
{
3341
  int side, req;
3342
  int worst = 1;
3343
  for (side = 0; side < 2; side++)
3344
    for (req = 0; req < UNIT_REQ_MAX; req++)
3345
      {
3346
        int factor = unit_req_factor ((enum unitreqs) req);
3347
        worst = MAX ((reqs[side][UNIT_REQ_D] + factor - 1) / factor, worst);
3348
      }
3349
 
3350
  return worst;
3351
}
3352
 
3353
/* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3354
   the operands that are involved in the (up to) two reservations, as
3355
   found by get_unit_reqs.  Return true if we did this successfully, false
3356
   if we couldn't identify what to do with INSN.  */
3357
static bool
3358
get_unit_operand_masks (rtx insn, unsigned int *pmask1, unsigned int *pmask2)
3359
{
3360
  enum attr_op_pattern op_pat;
3361
 
3362
  if (recog_memoized (insn) < 0)
3363
    return 0;
3364
  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
3365
    return false;
3366
  extract_insn (insn);
3367
  op_pat = get_attr_op_pattern (insn);
3368
  if (op_pat == OP_PATTERN_DT)
3369
    {
3370
      gcc_assert (recog_data.n_operands == 2);
3371
      *pmask1 = 1 << 0;
3372
      *pmask2 = 1 << 1;
3373
      return true;
3374
    }
3375
  else if (op_pat == OP_PATTERN_TD)
3376
    {
3377
      gcc_assert (recog_data.n_operands == 2);
3378
      *pmask1 = 1 << 1;
3379
      *pmask2 = 1 << 0;
3380
      return true;
3381
    }
3382
  else if (op_pat == OP_PATTERN_SXS)
3383
    {
3384
      gcc_assert (recog_data.n_operands == 3);
3385
      *pmask1 = (1 << 0) | (1 << 2);
3386
      *pmask2 = 1 << 1;
3387
      return true;
3388
    }
3389
  else if (op_pat == OP_PATTERN_SX)
3390
    {
3391
      gcc_assert (recog_data.n_operands == 2);
3392
      *pmask1 = 1 << 0;
3393
      *pmask2 = 1 << 1;
3394
      return true;
3395
    }
3396
  else if (op_pat == OP_PATTERN_SSX)
3397
    {
3398
      gcc_assert (recog_data.n_operands == 3);
3399
      *pmask1 = (1 << 0) | (1 << 1);
3400
      *pmask2 = 1 << 2;
3401
      return true;
3402
    }
3403
  return false;
3404
}
3405
 
3406
/* Try to replace a register in INSN, which has corresponding rename info
3407
   from regrename_analyze in INFO.  OP_MASK and ORIG_SIDE provide information
3408
   about the operands that must be renamed and the side they are on.
3409
   REQS is the table of unit reservations in the loop between HEAD and TAIL.
3410
   We recompute this information locally after our transformation, and keep
3411
   it only if we managed to improve the balance.  */
3412
static void
3413
try_rename_operands (rtx head, rtx tail, unit_req_table reqs, rtx insn,
3414
                     insn_rr_info *info, unsigned int op_mask, int orig_side)
3415
{
3416
  enum reg_class super_class = orig_side == 0 ? B_REGS : A_REGS;
3417
  HARD_REG_SET unavailable;
3418
  du_head_p this_head;
3419
  struct du_chain *chain;
3420
  int i;
3421
  unsigned tmp_mask;
3422
  int best_reg, old_reg;
3423
  VEC (du_head_p, heap) *involved_chains = NULL;
3424
  unit_req_table new_reqs;
3425
 
3426
  for (i = 0, tmp_mask = op_mask; tmp_mask; i++)
3427
    {
3428
      du_head_p op_chain;
3429
      if ((tmp_mask & (1 << i)) == 0)
3430
        continue;
3431
      if (info->op_info[i].n_chains != 1)
3432
        goto out_fail;
3433
      op_chain = regrename_chain_from_id (info->op_info[i].heads[0]->id);
3434
      VEC_safe_push (du_head_p, heap, involved_chains, op_chain);
3435
      tmp_mask &= ~(1 << i);
3436
    }
3437
 
3438
  if (VEC_length (du_head_p, involved_chains) > 1)
3439
    goto out_fail;
3440
 
3441
  this_head = VEC_index (du_head_p, involved_chains, 0);
3442
  if (this_head->cannot_rename)
3443
    goto out_fail;
3444
 
3445
  for (chain = this_head->first; chain; chain = chain->next_use)
3446
    {
3447
      unsigned int mask1, mask2, mask_changed;
3448
      int count, side1, side2, req1, req2;
3449
      insn_rr_info *this_rr = VEC_index (insn_rr_info, insn_rr,
3450
                                         INSN_UID (chain->insn));
3451
 
3452
      count = get_unit_reqs (chain->insn, &req1, &side1, &req2, &side2);
3453
 
3454
      if (count == 0)
3455
        goto out_fail;
3456
 
3457
      if (!get_unit_operand_masks (chain->insn, &mask1, &mask2))
3458
        goto out_fail;
3459
 
3460
      extract_insn (chain->insn);
3461
 
3462
      mask_changed = 0;
3463
      for (i = 0; i < recog_data.n_operands; i++)
3464
        {
3465
          int j;
3466
          int n_this_op = this_rr->op_info[i].n_chains;
3467
          for (j = 0; j < n_this_op; j++)
3468
            {
3469
              du_head_p other = this_rr->op_info[i].heads[j];
3470
              if (regrename_chain_from_id (other->id) == this_head)
3471
                break;
3472
            }
3473
          if (j == n_this_op)
3474
            continue;
3475
 
3476
          if (n_this_op != 1)
3477
            goto out_fail;
3478
          mask_changed |= 1 << i;
3479
        }
3480
      gcc_assert (mask_changed != 0);
3481
      if (mask_changed != mask1 && mask_changed != mask2)
3482
        goto out_fail;
3483
    }
3484
 
3485
  /* If we get here, we can do the renaming.  */
3486
  COMPL_HARD_REG_SET (unavailable, reg_class_contents[(int) super_class]);
3487
 
3488
  old_reg = this_head->regno;
3489
  best_reg = find_best_rename_reg (this_head, super_class, &unavailable, old_reg);
3490
 
3491
  regrename_do_replace (this_head, best_reg);
3492
 
3493
  count_unit_reqs (new_reqs, head, PREV_INSN (tail));
3494
  merge_unit_reqs (new_reqs);
3495
  if (dump_file)
3496
    {
3497
      fprintf (dump_file, "reshuffle for insn %d, op_mask %x, "
3498
               "original side %d, new reg %d\n",
3499
               INSN_UID (insn), op_mask, orig_side, best_reg);
3500
      fprintf (dump_file, "  imbalance %d -> %d\n",
3501
               unit_req_imbalance (reqs), unit_req_imbalance (new_reqs));
3502
    }
3503
  if (unit_req_imbalance (new_reqs) > unit_req_imbalance (reqs))
3504
    regrename_do_replace (this_head, old_reg);
3505
  else
3506
    memcpy (reqs, new_reqs, sizeof (unit_req_table));
3507
 
3508
 out_fail:
3509
  VEC_free (du_head_p, heap, involved_chains);
3510
}
3511
 
3512
/* Find insns in LOOP which would, if shifted to the other side
3513
   of the machine, reduce an imbalance in the unit reservations.  */
3514
static void
3515
reshuffle_units (basic_block loop)
3516
{
3517
  rtx head = BB_HEAD (loop);
3518
  rtx tail = BB_END (loop);
3519
  rtx insn;
3520
  unit_req_table reqs;
3521
  edge e;
3522
  edge_iterator ei;
3523
  bitmap_head bbs;
3524
 
3525
  count_unit_reqs (reqs, head, PREV_INSN (tail));
3526
  merge_unit_reqs (reqs);
3527
 
3528
  regrename_init (true);
3529
 
3530
  bitmap_initialize (&bbs, &bitmap_default_obstack);
3531
 
3532
  FOR_EACH_EDGE (e, ei, loop->preds)
3533
    bitmap_set_bit (&bbs, e->src->index);
3534
 
3535
  bitmap_set_bit (&bbs, loop->index);
3536
  regrename_analyze (&bbs);
3537
 
3538
  for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
3539
    {
3540
      enum attr_units units;
3541
      int count, side1, side2, req1, req2;
3542
      unsigned int mask1, mask2;
3543
      insn_rr_info *info;
3544
 
3545
      if (!NONDEBUG_INSN_P (insn))
3546
        continue;
3547
 
3548
      count = get_unit_reqs (insn, &req1, &side1, &req2, &side2);
3549
 
3550
      if (count == 0)
3551
        continue;
3552
 
3553
      if (!get_unit_operand_masks (insn, &mask1, &mask2))
3554
        continue;
3555
 
3556
      info = VEC_index (insn_rr_info, insn_rr, INSN_UID (insn));
3557
      if (info->op_info == NULL)
3558
        continue;
3559
 
3560
      if (reqs[side1][req1] > 1
3561
          && reqs[side1][req1] > 2 * reqs[side1 ^ 1][req1])
3562
        {
3563
          try_rename_operands (head, tail, reqs, insn, info, mask1, side1);
3564
        }
3565
 
3566
      units = get_attr_units (insn);
3567
      if (units == UNITS_D_ADDR)
3568
        {
3569
          gcc_assert (count == 2);
3570
          if (reqs[side2][req2] > 1
3571
              && reqs[side2][req2] > 2 * reqs[side2 ^ 1][req2])
3572
            {
3573
              try_rename_operands (head, tail, reqs, insn, info, mask2, side2);
3574
            }
3575
        }
3576
    }
3577
  regrename_finish ();
3578
}
3579
 
3580
/* Backend scheduling state.  */
3581
typedef struct c6x_sched_context
3582
{
3583
  /* The current scheduler clock, saved in the sched_reorder hook.  */
3584
  int curr_sched_clock;
3585
 
3586
  /* Number of insns issued so far in this cycle.  */
3587
  int issued_this_cycle;
3588
 
3589
  /* We record the time at which each jump occurs in JUMP_CYCLES.  The
3590
     theoretical maximum for number of jumps in flight is 12: 2 every
3591
     cycle, with a latency of 6 cycles each.  This is a circular
3592
     buffer; JUMP_CYCLE_INDEX is the pointer to the start.  Earlier
3593
     jumps have a higher index.  This array should be accessed through
3594
     the jump_cycle function.  */
3595
  int jump_cycles[12];
3596
  int jump_cycle_index;
3597
 
3598
  /* In parallel with jump_cycles, this array records the opposite of
3599
     the condition used in each pending jump.  This is used to
3600
     predicate insns that are scheduled in the jump's delay slots.  If
3601
     this is NULL_RTX no such predication happens.  */
3602
  rtx jump_cond[12];
3603
 
3604
  /* Similar to the jump_cycles mechanism, but here we take into
3605
     account all insns with delay slots, to avoid scheduling asms into
3606
     the delay slots.  */
3607
  int delays_finished_at;
3608
 
3609
  /* The following variable value is the last issued insn.  */
3610
  rtx last_scheduled_insn;
3611
  /* The last issued insn that isn't a shadow of another.  */
3612
  rtx last_scheduled_iter0;
3613
 
3614
  /* The following variable value is DFA state before issuing the
3615
     first insn in the current clock cycle.  We do not use this member
3616
     of the structure directly; we copy the data in and out of
3617
     prev_cycle_state.  */
3618
  state_t prev_cycle_state_ctx;
3619
 
3620
  int reg_n_accesses[FIRST_PSEUDO_REGISTER];
3621
  int reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3622
  int reg_set_in_cycle[FIRST_PSEUDO_REGISTER];
3623
 
3624
  int tmp_reg_n_accesses[FIRST_PSEUDO_REGISTER];
3625
  int tmp_reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3626
} *c6x_sched_context_t;
3627
 
3628
/* The current scheduling state.  */
3629
static struct c6x_sched_context ss;
3630
 
3631
/* The following variable value is DFA state before issueing the first insn
3632
   in the current clock cycle.  This is used in c6x_variable_issue for
3633
   comparison with the state after issuing the last insn in a cycle.  */
3634
static state_t prev_cycle_state;
3635
 
3636
/* Set when we discover while processing an insn that it would lead to too
3637
   many accesses of the same register.  */
3638
static bool reg_access_stall;
3639
 
3640
/* The highest insn uid after delayed insns were split, but before loop bodies
3641
   were copied by the modulo scheduling code.  */
3642
static int sploop_max_uid_iter0;
3643
 
3644
/* Look up the jump cycle with index N.  For an out-of-bounds N, we return 0,
3645
   so the caller does not specifically have to test for it.  */
3646
static int
3647
get_jump_cycle (int n)
3648
{
3649
  if (n >= 12)
3650
    return 0;
3651
  n += ss.jump_cycle_index;
3652
  if (n >= 12)
3653
    n -= 12;
3654
  return ss.jump_cycles[n];
3655
}
3656
 
3657
/* Look up the jump condition with index N.  */
3658
static rtx
3659
get_jump_cond (int n)
3660
{
3661
  if (n >= 12)
3662
    return NULL_RTX;
3663
  n += ss.jump_cycle_index;
3664
  if (n >= 12)
3665
    n -= 12;
3666
  return ss.jump_cond[n];
3667
}
3668
 
3669
/* Return the index of the first jump that occurs after CLOCK_VAR.  If no jump
3670
   has delay slots beyond CLOCK_VAR, return -1.  */
3671
static int
3672
first_jump_index (int clock_var)
3673
{
3674
  int retval = -1;
3675
  int n = 0;
3676
  for (;;)
3677
    {
3678
      int t = get_jump_cycle (n);
3679
      if (t <= clock_var)
3680
        break;
3681
      retval = n;
3682
      n++;
3683
    }
3684
  return retval;
3685
}
3686
 
3687
/* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3688
   and has the opposite condition of COND.  */
3689
static void
3690
record_jump (int cycle, rtx cond)
3691
{
3692
  if (ss.jump_cycle_index == 0)
3693
    ss.jump_cycle_index = 11;
3694
  else
3695
    ss.jump_cycle_index--;
3696
  ss.jump_cycles[ss.jump_cycle_index] = cycle;
3697
  ss.jump_cond[ss.jump_cycle_index] = cond;
3698
}
3699
 
3700
/* Set the clock cycle of INSN to CYCLE.  Also clears the insn's entry in
3701
   new_conditions.  */
3702
static void
3703
insn_set_clock (rtx insn, int cycle)
3704
{
3705
  unsigned uid = INSN_UID (insn);
3706
 
3707
  if (uid >= INSN_INFO_LENGTH)
3708
    VEC_safe_grow (c6x_sched_insn_info, heap, insn_info, uid * 5 / 4 + 10);
3709
 
3710
  INSN_INFO_ENTRY (uid).clock = cycle;
3711
  INSN_INFO_ENTRY (uid).new_cond = NULL;
3712
  INSN_INFO_ENTRY (uid).reservation = 0;
3713
  INSN_INFO_ENTRY (uid).ebb_start = false;
3714
}
3715
 
3716
/* Return the clock cycle we set for the insn with uid UID.  */
3717
static int
3718
insn_uid_get_clock (int uid)
3719
{
3720
  return INSN_INFO_ENTRY (uid).clock;
3721
}
3722
 
3723
/* Return the clock cycle we set for INSN.  */
3724
static int
3725
insn_get_clock (rtx insn)
3726
{
3727
  return insn_uid_get_clock (INSN_UID (insn));
3728
}
3729
 
3730
/* Examine INSN, and if it is a conditional jump of any kind, return
3731
   the opposite of the condition in which it branches.  Otherwise,
3732
   return NULL_RTX.  */
3733
static rtx
3734
condjump_opposite_condition (rtx insn)
3735
{
3736
  rtx pat = PATTERN (insn);
3737
  int icode = INSN_CODE (insn);
3738
  rtx x = NULL;
3739
 
3740
  if (icode == CODE_FOR_br_true || icode == CODE_FOR_br_false)
3741
    {
3742
      x = XEXP (SET_SRC (pat), 0);
3743
      if (icode == CODE_FOR_br_false)
3744
        return x;
3745
    }
3746
  if (GET_CODE (pat) == COND_EXEC)
3747
    {
3748
      rtx t = COND_EXEC_CODE (pat);
3749
      if ((GET_CODE (t) == PARALLEL
3750
           && GET_CODE (XVECEXP (t, 0, 0)) == RETURN)
3751
          || (GET_CODE (t) == UNSPEC && XINT (t, 1) == UNSPEC_REAL_JUMP)
3752
          || (GET_CODE (t) == SET && SET_DEST (t) == pc_rtx))
3753
        x = COND_EXEC_TEST (pat);
3754
    }
3755
 
3756
  if (x != NULL_RTX)
3757
    {
3758
      enum rtx_code code = GET_CODE (x);
3759
      x = gen_rtx_fmt_ee (code == EQ ? NE : EQ,
3760
                          GET_MODE (x), XEXP (x, 0),
3761
                          XEXP (x, 1));
3762
    }
3763
  return x;
3764
}
3765
 
3766
/* Return true iff COND1 and COND2 are exactly opposite conditions
3767
   one of them NE and the other EQ.  */
3768
static bool
3769
conditions_opposite_p (rtx cond1, rtx cond2)
3770
{
3771
  return (rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
3772
          && rtx_equal_p (XEXP (cond1, 1), XEXP (cond2, 1))
3773
          && GET_CODE (cond1) == reverse_condition (GET_CODE (cond2)));
3774
}
3775
 
3776
/* Return true if we can add a predicate COND to INSN, or if INSN
3777
   already has that predicate.  If DOIT is true, also perform the
3778
   modification.  */
3779
static bool
3780
predicate_insn (rtx insn, rtx cond, bool doit)
3781
{
3782
  int icode;
3783
  if (cond == NULL_RTX)
3784
    {
3785
      gcc_assert (!doit);
3786
      return false;
3787
    }
3788
 
3789
  if (get_attr_predicable (insn) == PREDICABLE_YES
3790
      && GET_CODE (PATTERN (insn)) != COND_EXEC)
3791
    {
3792
      if (doit)
3793
        {
3794
          rtx newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3795
          PATTERN (insn) = newpat;
3796
          INSN_CODE (insn) = -1;
3797
        }
3798
      return true;
3799
    }
3800
  if (GET_CODE (PATTERN (insn)) == COND_EXEC
3801
      && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn)), cond))
3802
    return true;
3803
  icode = INSN_CODE (insn);
3804
  if (icode == CODE_FOR_real_jump
3805
      || icode == CODE_FOR_jump
3806
      || icode == CODE_FOR_indirect_jump)
3807
    {
3808
      rtx pat = PATTERN (insn);
3809
      rtx dest = (icode == CODE_FOR_real_jump ? XVECEXP (pat, 0, 0)
3810
                  : icode == CODE_FOR_jump ? XEXP (SET_SRC (pat), 0)
3811
                  : SET_SRC (pat));
3812
      if (doit)
3813
        {
3814
          rtx newpat;
3815
          if (REG_P (dest))
3816
            newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3817
          else
3818
            newpat = gen_br_true (cond, XEXP (cond, 0), dest);
3819
          PATTERN (insn) = newpat;
3820
          INSN_CODE (insn) = -1;
3821
        }
3822
      return true;
3823
    }
3824
  if (INSN_CODE (insn) == CODE_FOR_br_true)
3825
    {
3826
      rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3827
      return rtx_equal_p (br_cond, cond);
3828
    }
3829
  if (INSN_CODE (insn) == CODE_FOR_br_false)
3830
    {
3831
      rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3832
      return conditions_opposite_p (br_cond, cond);
3833
    }
3834
  return false;
3835
}
3836
 
3837
/* Initialize SC.  Used by c6x_init_sched_context and c6x_sched_init.  */
3838
static void
3839
init_sched_state (c6x_sched_context_t sc)
3840
{
3841
  sc->last_scheduled_insn = NULL_RTX;
3842
  sc->last_scheduled_iter0 = NULL_RTX;
3843
  sc->issued_this_cycle = 0;
3844
  memset (sc->jump_cycles, 0, sizeof sc->jump_cycles);
3845
  memset (sc->jump_cond, 0, sizeof sc->jump_cond);
3846
  sc->jump_cycle_index = 0;
3847
  sc->delays_finished_at = 0;
3848
  sc->curr_sched_clock = 0;
3849
 
3850
  sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3851
 
3852
  memset (sc->reg_n_accesses, 0, sizeof sc->reg_n_accesses);
3853
  memset (sc->reg_n_xaccesses, 0, sizeof sc->reg_n_xaccesses);
3854
  memset (sc->reg_set_in_cycle, 0, sizeof sc->reg_set_in_cycle);
3855
 
3856
  state_reset (sc->prev_cycle_state_ctx);
3857
}
3858
 
3859
/* Allocate store for new scheduling context.  */
3860
static void *
3861
c6x_alloc_sched_context (void)
3862
{
3863
  return xmalloc (sizeof (struct c6x_sched_context));
3864
}
3865
 
3866
/* If CLEAN_P is true then initializes _SC with clean data,
3867
   and from the global context otherwise.  */
3868
static void
3869
c6x_init_sched_context (void *_sc, bool clean_p)
3870
{
3871
  c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3872
 
3873
  if (clean_p)
3874
    {
3875
      init_sched_state (sc);
3876
    }
3877
  else
3878
    {
3879
      *sc = ss;
3880
      sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3881
      memcpy (sc->prev_cycle_state_ctx, prev_cycle_state, dfa_state_size);
3882
    }
3883
}
3884
 
3885
/* Sets the global scheduling context to the one pointed to by _SC.  */
3886
static void
3887
c6x_set_sched_context (void *_sc)
3888
{
3889
  c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3890
 
3891
  gcc_assert (sc != NULL);
3892
  ss = *sc;
3893
  memcpy (prev_cycle_state, sc->prev_cycle_state_ctx, dfa_state_size);
3894
}
3895
 
3896
/* Clear data in _SC.  */
3897
static void
3898
c6x_clear_sched_context (void *_sc)
3899
{
3900
  c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3901
  gcc_assert (_sc != NULL);
3902
 
3903
  free (sc->prev_cycle_state_ctx);
3904
}
3905
 
3906
/* Free _SC.  */
3907
static void
3908
c6x_free_sched_context (void *_sc)
3909
{
3910
  free (_sc);
3911
}
3912
 
3913
/* Provide information about speculation capabilities, and set the
3914
   DO_BACKTRACKING flag.  */
3915
static void
3916
c6x_set_sched_flags (spec_info_t spec_info)
3917
{
3918
  unsigned int *flags = &(current_sched_info->flags);
3919
 
3920
  if (*flags & SCHED_EBB)
3921
    {
3922
      *flags |= DO_BACKTRACKING | DO_PREDICATION;
3923
    }
3924
 
3925
  spec_info->mask = 0;
3926
}
3927
 
3928
/* Implement the TARGET_SCHED_ISSUE_RATE hook.  */
3929
 
3930
static int
3931
c6x_issue_rate (void)
3932
{
3933
  return 8;
3934
}
3935
 
3936
/* Used together with the collapse_ndfa option, this ensures that we reach a
3937
   deterministic automaton state before trying to advance a cycle.
3938
   With collapse_ndfa, genautomata creates advance cycle arcs only for
3939
   such deterministic states.  */
3940
 
3941
static rtx
3942
c6x_sched_dfa_pre_cycle_insn (void)
3943
{
3944
  return const0_rtx;
3945
}
3946
 
3947
/* We're beginning a new block.  Initialize data structures as necessary.  */
3948
 
3949
static void
3950
c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED,
3951
                int sched_verbose ATTRIBUTE_UNUSED,
3952
                int max_ready ATTRIBUTE_UNUSED)
3953
{
3954
  if (prev_cycle_state == NULL)
3955
    {
3956
      prev_cycle_state = xmalloc (dfa_state_size);
3957
    }
3958
  init_sched_state (&ss);
3959
  state_reset (prev_cycle_state);
3960
}
3961
 
3962
/* We are about to being issuing INSN.  Return nonzero if we cannot
3963
   issue it on given cycle CLOCK and return zero if we should not sort
3964
   the ready queue on the next clock start.
3965
   For C6X, we use this function just to copy the previous DFA state
3966
   for comparison purposes.  */
3967
 
3968
static int
3969
c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
3970
                   rtx insn ATTRIBUTE_UNUSED, int last_clock ATTRIBUTE_UNUSED,
3971
                   int clock ATTRIBUTE_UNUSED, int *sort_p ATTRIBUTE_UNUSED)
3972
{
3973
  if (clock != last_clock)
3974
    memcpy (prev_cycle_state, curr_state, dfa_state_size);
3975
  return 0;
3976
}
3977
 
3978
static void
3979
c6x_mark_regno_read (int regno, bool cross)
3980
{
3981
  int t = ++ss.tmp_reg_n_accesses[regno];
3982
 
3983
  if (t > 4)
3984
    reg_access_stall = true;
3985
 
3986
  if (cross)
3987
    {
3988
      int set_cycle = ss.reg_set_in_cycle[regno];
3989
      /* This must be done in this way rather than by tweaking things in
3990
         adjust_cost, since the stall occurs even for insns with opposite
3991
         predicates, and the scheduler may not even see a dependency.  */
3992
      if (set_cycle > 0 && set_cycle == ss.curr_sched_clock)
3993
        reg_access_stall = true;
3994
      /* This doesn't quite do anything yet as we're only modeling one
3995
         x unit.  */
3996
      ++ss.tmp_reg_n_xaccesses[regno];
3997
    }
3998
}
3999
 
4000
/* Note that REG is read in the insn being examined.  If CROSS, it
4001
   means the access is through a cross path.  Update the temporary reg
4002
   access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4003
   in the current cycle.  */
4004
 
4005
static void
4006
c6x_mark_reg_read (rtx reg, bool cross)
4007
{
4008
  unsigned regno = REGNO (reg);
4009
  unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
4010
 
4011
  while (nregs-- > 0)
4012
    c6x_mark_regno_read (regno + nregs, cross);
4013
}
4014
 
4015
/* Note that register REG is written in cycle CYCLES.  */
4016
 
4017
static void
4018
c6x_mark_reg_written (rtx reg, int cycles)
4019
{
4020
  unsigned regno = REGNO (reg);
4021
  unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
4022
 
4023
  while (nregs-- > 0)
4024
    ss.reg_set_in_cycle[regno + nregs] = cycles;
4025
}
4026
 
4027
/* Update the register state information for an instruction whose
4028
   body is X.  Return true if the instruction has to be delayed until the
4029
   next cycle.  */
4030
 
4031
static bool
4032
c6x_registers_update (rtx insn)
4033
{
4034
  enum attr_cross cross;
4035
  enum attr_dest_regfile destrf;
4036
  int i, nops;
4037
  rtx x;
4038
 
4039
  if (!reload_completed || recog_memoized (insn) < 0)
4040
    return false;
4041
 
4042
  reg_access_stall = false;
4043
  memcpy (ss.tmp_reg_n_accesses, ss.reg_n_accesses,
4044
          sizeof ss.tmp_reg_n_accesses);
4045
  memcpy (ss.tmp_reg_n_xaccesses, ss.reg_n_xaccesses,
4046
          sizeof ss.tmp_reg_n_xaccesses);
4047
 
4048
  extract_insn (insn);
4049
 
4050
  cross = get_attr_cross (insn);
4051
  destrf = get_attr_dest_regfile (insn);
4052
 
4053
  nops = recog_data.n_operands;
4054
  x = PATTERN (insn);
4055
  if (GET_CODE (x) == COND_EXEC)
4056
    {
4057
      c6x_mark_reg_read (XEXP (XEXP (x, 0), 0), false);
4058
      nops -= 2;
4059
    }
4060
 
4061
  for (i = 0; i < nops; i++)
4062
    {
4063
      rtx op = recog_data.operand[i];
4064
      if (recog_data.operand_type[i] == OP_OUT)
4065
        continue;
4066
      if (REG_P (op))
4067
        {
4068
          bool this_cross = cross;
4069
          if (destrf == DEST_REGFILE_A && A_REGNO_P (REGNO (op)))
4070
            this_cross = false;
4071
          if (destrf == DEST_REGFILE_B && B_REGNO_P (REGNO (op)))
4072
            this_cross = false;
4073
          c6x_mark_reg_read (op, this_cross);
4074
        }
4075
      else if (MEM_P (op))
4076
        {
4077
          op = XEXP (op, 0);
4078
          switch (GET_CODE (op))
4079
            {
4080
            case POST_INC:
4081
            case PRE_INC:
4082
            case POST_DEC:
4083
            case PRE_DEC:
4084
              op = XEXP (op, 0);
4085
              /* fall through */
4086
            case REG:
4087
              c6x_mark_reg_read (op, false);
4088
              break;
4089
            case POST_MODIFY:
4090
            case PRE_MODIFY:
4091
              op = XEXP (op, 1);
4092
              gcc_assert (GET_CODE (op) == PLUS);
4093
              /* fall through */
4094
            case PLUS:
4095
              c6x_mark_reg_read (XEXP (op, 0), false);
4096
              if (REG_P (XEXP (op, 1)))
4097
                c6x_mark_reg_read (XEXP (op, 1), false);
4098
              break;
4099
            case SYMBOL_REF:
4100
            case LABEL_REF:
4101
            case CONST:
4102
              c6x_mark_regno_read (REG_B14, false);
4103
              break;
4104
            default:
4105
              gcc_unreachable ();
4106
            }
4107
        }
4108
      else if (!CONSTANT_P (op) && strlen (recog_data.constraints[i]) > 0)
4109
        gcc_unreachable ();
4110
    }
4111
  return reg_access_stall;
4112
}
4113
 
4114
/* Helper function for the TARGET_SCHED_REORDER and
4115
   TARGET_SCHED_REORDER2 hooks.  If scheduling an insn would be unsafe
4116
   in the current cycle, move it down in the ready list and return the
4117
   number of non-unsafe insns.  */
4118
 
4119
static int
4120
c6x_sched_reorder_1 (rtx *ready, int *pn_ready, int clock_var)
4121
{
4122
  int n_ready = *pn_ready;
4123
  rtx *e_ready = ready + n_ready;
4124
  rtx *insnp;
4125
  int first_jump;
4126
 
4127
  /* Keep track of conflicts due to a limit number of register accesses,
4128
     and due to stalls incurred by too early accesses of registers using
4129
     cross paths.  */
4130
 
4131
  for (insnp = ready; insnp < e_ready; insnp++)
4132
    {
4133
      rtx insn = *insnp;
4134
      int icode = recog_memoized (insn);
4135
      bool is_asm = (icode < 0
4136
                     && (GET_CODE (PATTERN (insn)) == ASM_INPUT
4137
                         || asm_noperands (PATTERN (insn)) >= 0));
4138
      bool no_parallel = (is_asm || icode == CODE_FOR_sploop
4139
                          || (icode >= 0
4140
                              && get_attr_type (insn) == TYPE_ATOMIC));
4141
 
4142
      /* We delay asm insns until all delay slots are exhausted.  We can't
4143
         accurately tell how many cycles an asm takes, and the main scheduling
4144
         code always assumes at least 1 cycle, which may be wrong.  */
4145
      if ((no_parallel
4146
           && (ss.issued_this_cycle > 0 || clock_var < ss.delays_finished_at))
4147
          || c6x_registers_update (insn)
4148
          || (ss.issued_this_cycle > 0 && icode == CODE_FOR_sploop))
4149
        {
4150
          memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4151
          *ready = insn;
4152
          n_ready--;
4153
          ready++;
4154
        }
4155
      else if (shadow_p (insn))
4156
        {
4157
          memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4158
          *ready = insn;
4159
        }
4160
    }
4161
 
4162
  /* Ensure that no other jump is scheduled in jump delay slots, since
4163
     it would put the machine into the wrong state.  Also, we must
4164
     avoid scheduling insns that have a latency longer than the
4165
     remaining jump delay slots, as the code at the jump destination
4166
     won't be prepared for it.
4167
 
4168
     However, we can relax this condition somewhat.  The rest of the
4169
     scheduler will automatically avoid scheduling an insn on which
4170
     the jump shadow depends so late that its side effect happens
4171
     after the jump.  This means that if we see an insn with a longer
4172
     latency here, it can safely be scheduled if we can ensure that it
4173
     has a predicate opposite of the previous jump: the side effect
4174
     will happen in what we think of as the same basic block.  In
4175
     c6x_variable_issue, we will record the necessary predicate in
4176
     new_conditions, and after scheduling is finished, we will modify
4177
     the insn.
4178
 
4179
     Special care must be taken whenever there is more than one jump
4180
     in flight.  */
4181
 
4182
  first_jump = first_jump_index (clock_var);
4183
  if (first_jump != -1)
4184
    {
4185
      int first_cycle = get_jump_cycle (first_jump);
4186
      rtx first_cond = get_jump_cond (first_jump);
4187
      int second_cycle = 0;
4188
 
4189
      if (first_jump > 0)
4190
        second_cycle = get_jump_cycle (first_jump - 1);
4191
 
4192
      for (insnp = ready; insnp < e_ready; insnp++)
4193
        {
4194
          rtx insn = *insnp;
4195
          int icode = recog_memoized (insn);
4196
          bool is_asm = (icode < 0
4197
                         && (GET_CODE (PATTERN (insn)) == ASM_INPUT
4198
                             || asm_noperands (PATTERN (insn)) >= 0));
4199
          int this_cycles, rsrv_cycles;
4200
          enum attr_type type;
4201
 
4202
          gcc_assert (!is_asm);
4203
          if (icode < 0)
4204
            continue;
4205
          this_cycles = get_attr_cycles (insn);
4206
          rsrv_cycles = get_attr_reserve_cycles (insn);
4207
          type = get_attr_type (insn);
4208
          /* Treat branches specially; there is also a hazard if two jumps
4209
             end at the same cycle.  */
4210
          if (type == TYPE_BRANCH || type == TYPE_CALL)
4211
            this_cycles++;
4212
          if (clock_var + this_cycles <= first_cycle)
4213
            continue;
4214
          if ((first_jump > 0 && clock_var + this_cycles > second_cycle)
4215
              || clock_var + rsrv_cycles > first_cycle
4216
              || !predicate_insn (insn, first_cond, false))
4217
            {
4218
              memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4219
              *ready = insn;
4220
              n_ready--;
4221
              ready++;
4222
            }
4223
        }
4224
    }
4225
 
4226
  return n_ready;
4227
}
4228
 
4229
/* Implement the TARGET_SCHED_REORDER hook.  We save the current clock
4230
   for later and clear the register access information for the new
4231
   cycle.  We also move asm statements out of the way if they would be
4232
   scheduled in a delay slot.  */
4233
 
4234
static int
4235
c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED,
4236
                   int sched_verbose ATTRIBUTE_UNUSED,
4237
                   rtx *ready ATTRIBUTE_UNUSED,
4238
                   int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
4239
{
4240
  ss.curr_sched_clock = clock_var;
4241
  ss.issued_this_cycle = 0;
4242
  memset (ss.reg_n_accesses, 0, sizeof ss.reg_n_accesses);
4243
  memset (ss.reg_n_xaccesses, 0, sizeof ss.reg_n_xaccesses);
4244
 
4245
  if (ready == NULL)
4246
    return 0;
4247
 
4248
  return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
4249
}
4250
 
4251
/* Implement the TARGET_SCHED_REORDER2 hook.  We use this to record the clock
4252
   cycle for every insn.  */
4253
 
4254
static int
4255
c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
4256
                    int sched_verbose ATTRIBUTE_UNUSED,
4257
                    rtx *ready ATTRIBUTE_UNUSED,
4258
                    int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
4259
{
4260
  /* FIXME: the assembler rejects labels inside an execute packet.
4261
     This can occur if prologue insns are scheduled in parallel with
4262
     others, so we avoid this here.  Also make sure that nothing is
4263
     scheduled in parallel with a TYPE_ATOMIC insn or after a jump.  */
4264
  if (RTX_FRAME_RELATED_P (ss.last_scheduled_insn)
4265
      || JUMP_P (ss.last_scheduled_insn)
4266
      || (recog_memoized (ss.last_scheduled_insn) >= 0
4267
          && get_attr_type (ss.last_scheduled_insn) == TYPE_ATOMIC))
4268
    {
4269
      int n_ready = *pn_ready;
4270
      rtx *e_ready = ready + n_ready;
4271
      rtx *insnp;
4272
 
4273
      for (insnp = ready; insnp < e_ready; insnp++)
4274
        {
4275
          rtx insn = *insnp;
4276
          if (!shadow_p (insn))
4277
            {
4278
              memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4279
              *ready = insn;
4280
              n_ready--;
4281
              ready++;
4282
            }
4283
        }
4284
      return n_ready;
4285
    }
4286
 
4287
  return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
4288
}
4289
 
4290
/* Subroutine of maybe_clobber_cond, called through note_stores.  */
4291
 
4292
static void
4293
clobber_cond_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data1)
4294
{
4295
  rtx *cond = (rtx *)data1;
4296
  if (*cond != NULL_RTX && reg_overlap_mentioned_p (x, *cond))
4297
    *cond = NULL_RTX;
4298
}
4299
 
4300
/* Examine INSN, and if it destroys the conditions have recorded for
4301
   any of the jumps in flight, clear that condition so that we don't
4302
   predicate any more insns.  CLOCK_VAR helps us limit the search to
4303
   only those jumps which are still in flight.  */
4304
 
4305
static void
4306
maybe_clobber_cond (rtx insn, int clock_var)
4307
{
4308
  int n, idx;
4309
  idx = ss.jump_cycle_index;
4310
  for (n = 0; n < 12; n++, idx++)
4311
    {
4312
      rtx cond, link;
4313
      int cycle;
4314
 
4315
      if (idx >= 12)
4316
        idx -= 12;
4317
      cycle = ss.jump_cycles[idx];
4318
      if (cycle <= clock_var)
4319
        return;
4320
 
4321
      cond = ss.jump_cond[idx];
4322
      if (cond == NULL_RTX)
4323
        continue;
4324
 
4325
      if (CALL_P (insn))
4326
        {
4327
          ss.jump_cond[idx] = NULL_RTX;
4328
          continue;
4329
        }
4330
 
4331
      note_stores (PATTERN (insn), clobber_cond_1, ss.jump_cond + idx);
4332
      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
4333
        if (REG_NOTE_KIND (link) == REG_INC)
4334
          clobber_cond_1 (XEXP (link, 0), NULL_RTX, ss.jump_cond + idx);
4335
    }
4336
}
4337
 
4338
/* Implement the TARGET_SCHED_VARIABLE_ISSUE hook.  We are about to
4339
   issue INSN.  Return the number of insns left on the ready queue
4340
   that can be issued this cycle.
4341
   We use this hook to record clock cycles and reservations for every insn.  */
4342
 
4343
static int
4344
c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
4345
                    int sched_verbose ATTRIBUTE_UNUSED,
4346
                    rtx insn, int can_issue_more ATTRIBUTE_UNUSED)
4347
{
4348
  ss.last_scheduled_insn = insn;
4349
  if (INSN_UID (insn) < sploop_max_uid_iter0 && !JUMP_P (insn))
4350
    ss.last_scheduled_iter0 = insn;
4351
  if (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)
4352
    ss.issued_this_cycle++;
4353
  if (insn_info)
4354
    {
4355
      state_t st_after = alloca (dfa_state_size);
4356
      int curr_clock = ss.curr_sched_clock;
4357
      int uid = INSN_UID (insn);
4358
      int icode = recog_memoized (insn);
4359
      rtx first_cond;
4360
      int first, first_cycle;
4361
      unsigned int mask;
4362
      int i;
4363
 
4364
      insn_set_clock (insn, curr_clock);
4365
      INSN_INFO_ENTRY (uid).ebb_start
4366
        = curr_clock == 0 && ss.issued_this_cycle == 1;
4367
 
4368
      first = first_jump_index (ss.curr_sched_clock);
4369
      if (first == -1)
4370
        {
4371
          first_cycle = 0;
4372
          first_cond = NULL_RTX;
4373
        }
4374
      else
4375
        {
4376
          first_cycle = get_jump_cycle (first);
4377
          first_cond = get_jump_cond (first);
4378
        }
4379
      if (icode >= 0
4380
          && first_cycle > curr_clock
4381
          && first_cond != NULL_RTX
4382
          && (curr_clock + get_attr_cycles (insn) > first_cycle
4383
              || get_attr_type (insn) == TYPE_BRANCH
4384
              || get_attr_type (insn) == TYPE_CALL))
4385
        INSN_INFO_ENTRY (uid).new_cond = first_cond;
4386
 
4387
      memcpy (st_after, curr_state, dfa_state_size);
4388
      state_transition (st_after, const0_rtx);
4389
 
4390
      mask = 0;
4391
      for (i = 0; i < 2 * UNIT_QID_SIDE_OFFSET; i++)
4392
        if (cpu_unit_reservation_p (st_after, c6x_unit_codes[i])
4393
            && !cpu_unit_reservation_p (prev_cycle_state, c6x_unit_codes[i]))
4394
          mask |= 1 << i;
4395
      INSN_INFO_ENTRY (uid).unit_mask = mask;
4396
 
4397
      maybe_clobber_cond (insn, curr_clock);
4398
 
4399
      if (icode >= 0)
4400
        {
4401
          int i, cycles;
4402
 
4403
          c6x_registers_update (insn);
4404
          memcpy (ss.reg_n_accesses, ss.tmp_reg_n_accesses,
4405
                  sizeof ss.reg_n_accesses);
4406
          memcpy (ss.reg_n_xaccesses, ss.tmp_reg_n_accesses,
4407
                  sizeof ss.reg_n_xaccesses);
4408
 
4409
          cycles = get_attr_cycles (insn);
4410
          if (ss.delays_finished_at < ss.curr_sched_clock + cycles)
4411
            ss.delays_finished_at = ss.curr_sched_clock + cycles;
4412
          if (get_attr_type (insn) == TYPE_BRANCH
4413
              || get_attr_type (insn) == TYPE_CALL)
4414
            {
4415
              rtx opposite = condjump_opposite_condition (insn);
4416
              record_jump (ss.curr_sched_clock + cycles, opposite);
4417
            }
4418
 
4419
          /* Mark the cycles in which the destination registers are written.
4420
             This is used for calculating stalls when using cross units.  */
4421
          extract_insn (insn);
4422
          /* Cross-path stalls don't apply to results of load insns.  */
4423
          if (get_attr_type (insn) == TYPE_LOAD
4424
              || get_attr_type (insn) == TYPE_LOADN
4425
              || get_attr_type (insn) == TYPE_LOAD_SHADOW)
4426
            cycles--;
4427
          for (i = 0; i < recog_data.n_operands; i++)
4428
            {
4429
              rtx op = recog_data.operand[i];
4430
              if (MEM_P (op))
4431
                {
4432
                  rtx addr = XEXP (op, 0);
4433
                  if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
4434
                    c6x_mark_reg_written (XEXP (addr, 0),
4435
                                          insn_uid_get_clock (uid) + 1);
4436
                }
4437
              if (recog_data.operand_type[i] != OP_IN
4438
                  && REG_P (op))
4439
                {
4440
                  c6x_mark_reg_written (op,
4441
                                        insn_uid_get_clock (uid) + cycles);
4442
                }
4443
            }
4444
        }
4445
    }
4446
  return can_issue_more;
4447
}
4448
 
4449
/* Implement the TARGET_SCHED_ADJUST_COST hook.  We need special handling for
4450
   anti- and output dependencies.  */
4451
 
4452
static int
4453
c6x_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4454
{
4455
  enum attr_type insn_type = TYPE_UNKNOWN, dep_insn_type = TYPE_UNKNOWN;
4456
  int dep_insn_code_number, insn_code_number;
4457
  int shadow_bonus = 0;
4458
  enum reg_note kind;
4459
  dep_insn_code_number = recog_memoized (dep_insn);
4460
  insn_code_number = recog_memoized (insn);
4461
 
4462
  if (dep_insn_code_number >= 0)
4463
    dep_insn_type = get_attr_type (dep_insn);
4464
 
4465
  if (insn_code_number >= 0)
4466
    insn_type = get_attr_type (insn);
4467
 
4468
  kind = REG_NOTE_KIND (link);
4469
  if (kind == 0)
4470
    {
4471
      /* If we have a dependency on a load, and it's not for the result of
4472
         the load, it must be for an autoincrement.  Reduce the cost in that
4473
         case.  */
4474
      if (dep_insn_type == TYPE_LOAD)
4475
        {
4476
          rtx set = PATTERN (dep_insn);
4477
          if (GET_CODE (set) == COND_EXEC)
4478
            set = COND_EXEC_CODE (set);
4479
          if (GET_CODE (set) == UNSPEC)
4480
            cost = 1;
4481
          else
4482
            {
4483
              gcc_assert (GET_CODE (set) == SET);
4484
              if (!reg_overlap_mentioned_p (SET_DEST (set), PATTERN (insn)))
4485
                cost = 1;
4486
            }
4487
        }
4488
    }
4489
 
4490
  /* A jump shadow needs to have its latency decreased by one.  Conceptually,
4491
     it occurs in between two cycles, but we schedule it at the end of the
4492
     first cycle.  */
4493
  if (shadow_type_p (insn_type))
4494
    shadow_bonus = 1;
4495
 
4496
  /* Anti and output dependencies usually have zero cost, but we want
4497
     to insert a stall after a jump, and after certain floating point
4498
     insns that take more than one cycle to read their inputs.  In the
4499
     future, we should try to find a better algorithm for scheduling
4500
     jumps.  */
4501
  if (kind != 0)
4502
    {
4503
      /* We can get anti-dependencies against shadow insns.  Treat these
4504
         like output dependencies, so that the insn is entirely finished
4505
         before the branch takes place.  */
4506
      if (kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW)
4507
        kind = REG_DEP_OUTPUT;
4508
      switch (dep_insn_type)
4509
        {
4510
        case TYPE_CALLP:
4511
          return 1;
4512
        case TYPE_BRANCH:
4513
        case TYPE_CALL:
4514
          if (get_attr_has_shadow (dep_insn) == HAS_SHADOW_Y)
4515
            /* This is a real_jump/real_call insn.  These don't have
4516
               outputs, and ensuring the validity of scheduling things
4517
               in the delay slot is the job of
4518
               c6x_sched_reorder_1.  */
4519
            return 0;
4520
          /* Unsplit calls can happen - e.g. for divide insns.  */
4521
          return 6;
4522
        case TYPE_LOAD:
4523
        case TYPE_LOADN:
4524
        case TYPE_INTDP:
4525
          if (kind == REG_DEP_OUTPUT)
4526
            return 5 - shadow_bonus;
4527
          return 0;
4528
        case TYPE_MPY4:
4529
        case TYPE_FP4:
4530
          if (kind == REG_DEP_OUTPUT)
4531
            return 4 - shadow_bonus;
4532
          return 0;
4533
        case TYPE_MPY2:
4534
          if (kind == REG_DEP_OUTPUT)
4535
            return 2 - shadow_bonus;
4536
          return 0;
4537
        case TYPE_CMPDP:
4538
          if (kind == REG_DEP_OUTPUT)
4539
            return 2 - shadow_bonus;
4540
          return 2;
4541
        case TYPE_ADDDP:
4542
        case TYPE_MPYSPDP:
4543
          if (kind == REG_DEP_OUTPUT)
4544
            return 7 - shadow_bonus;
4545
          return 2;
4546
        case TYPE_MPYSP2DP:
4547
          if (kind == REG_DEP_OUTPUT)
4548
            return 5 - shadow_bonus;
4549
          return 2;
4550
        case TYPE_MPYI:
4551
          if (kind == REG_DEP_OUTPUT)
4552
            return 9 - shadow_bonus;
4553
          return 4;
4554
        case TYPE_MPYID:
4555
        case TYPE_MPYDP:
4556
          if (kind == REG_DEP_OUTPUT)
4557
            return 10 - shadow_bonus;
4558
          return 4;
4559
 
4560
        default:
4561
          if (insn_type == TYPE_SPKERNEL)
4562
            return 0;
4563
          if (kind == REG_DEP_OUTPUT)
4564
            return 1 - shadow_bonus;
4565
 
4566
          return 0;
4567
        }
4568
    }
4569
 
4570
  return cost - shadow_bonus;
4571
}
4572
 
4573
/* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4574
   are N_FILLED.  REAL_FIRST identifies the slot if the insn that appears
4575
   first in the original stream.  */
4576
 
4577
static void
4578
gen_one_bundle (rtx *slot, int n_filled, int real_first)
4579
{
4580
  rtx bundle;
4581
  rtx t;
4582
  int i;
4583
 
4584
  bundle = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec_v (n_filled, slot));
4585
  bundle = make_insn_raw (bundle);
4586
  BLOCK_FOR_INSN (bundle) = BLOCK_FOR_INSN (slot[0]);
4587
  INSN_LOCATOR (bundle) = INSN_LOCATOR (slot[0]);
4588
  PREV_INSN (bundle) = PREV_INSN (slot[real_first]);
4589
 
4590
  t = NULL_RTX;
4591
 
4592
  for (i = 0; i < n_filled; i++)
4593
    {
4594
      rtx insn = slot[i];
4595
      remove_insn (insn);
4596
      PREV_INSN (insn) = t ? t : PREV_INSN (bundle);
4597
      if (t != NULL_RTX)
4598
        NEXT_INSN (t) = insn;
4599
      t = insn;
4600
      if (i > 0)
4601
        INSN_LOCATOR (slot[i]) = INSN_LOCATOR (bundle);
4602
    }
4603
 
4604
  NEXT_INSN (bundle) = NEXT_INSN (PREV_INSN (bundle));
4605
  NEXT_INSN (t) = NEXT_INSN (bundle);
4606
  NEXT_INSN (PREV_INSN (bundle)) = bundle;
4607
  PREV_INSN (NEXT_INSN (bundle)) = bundle;
4608
}
4609
 
4610
/* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4611
   try to insert labels in the middle.  */
4612
 
4613
static void
4614
c6x_gen_bundles (void)
4615
{
4616
  basic_block bb;
4617
  rtx insn, next, last_call;
4618
 
4619
  FOR_EACH_BB (bb)
4620
    {
4621
      rtx insn, next;
4622
      /* The machine is eight insns wide.  We can have up to six shadow
4623
         insns, plus an extra slot for merging the jump shadow.  */
4624
      rtx slot[15];
4625
      int n_filled = 0;
4626
      int first_slot = 0;
4627
 
4628
      for (insn = BB_HEAD (bb);; insn = next)
4629
        {
4630
          int at_end;
4631
          rtx delete_this = NULL_RTX;
4632
 
4633
          if (NONDEBUG_INSN_P (insn))
4634
            {
4635
              /* Put calls at the start of the sequence.  */
4636
              if (CALL_P (insn))
4637
                {
4638
                  first_slot++;
4639
                  if (n_filled)
4640
                    {
4641
                      memmove (&slot[1], &slot[0],
4642
                               n_filled * sizeof (slot[0]));
4643
                    }
4644
                  if (!shadow_p (insn))
4645
                    {
4646
                      PUT_MODE (insn, TImode);
4647
                      if (n_filled)
4648
                        PUT_MODE (slot[1], VOIDmode);
4649
                    }
4650
                  n_filled++;
4651
                  slot[0] = insn;
4652
                }
4653
              else
4654
                {
4655
                  slot[n_filled++] = insn;
4656
                }
4657
            }
4658
 
4659
          next = NEXT_INSN (insn);
4660
          while (next && insn != BB_END (bb)
4661
                 && !(NONDEBUG_INSN_P (next)
4662
                      && GET_CODE (PATTERN (next)) != USE
4663
                      && GET_CODE (PATTERN (next)) != CLOBBER))
4664
            {
4665
              insn = next;
4666
              next = NEXT_INSN (insn);
4667
            }
4668
 
4669
          at_end = insn == BB_END (bb);
4670
          if (delete_this == NULL_RTX
4671
              && (at_end || (GET_MODE (next) == TImode
4672
                             && !(shadow_p (next) && CALL_P (next)))))
4673
            {
4674
              if (n_filled >= 2)
4675
                gen_one_bundle (slot, n_filled, first_slot);
4676
 
4677
              n_filled = 0;
4678
              first_slot = 0;
4679
            }
4680
          if (at_end)
4681
            break;
4682
        }
4683
    }
4684
  /* Bundling, and emitting nops, can separate
4685
     NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls.  Fix
4686
     that up here.  */
4687
  last_call = NULL_RTX;
4688
  for (insn = get_insns (); insn; insn = next)
4689
    {
4690
      next = NEXT_INSN (insn);
4691
      if (CALL_P (insn)
4692
          || (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE
4693
              && CALL_P (XVECEXP (PATTERN (insn), 0, 0))))
4694
        last_call = insn;
4695
      if (!NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION)
4696
        continue;
4697
      if (NEXT_INSN (last_call) == insn)
4698
        continue;
4699
      NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
4700
      PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
4701
      PREV_INSN (insn) = last_call;
4702
      NEXT_INSN (insn) = NEXT_INSN (last_call);
4703
      PREV_INSN (NEXT_INSN (insn)) = insn;
4704
      NEXT_INSN (PREV_INSN (insn)) = insn;
4705
      last_call = insn;
4706
    }
4707
}
4708
 
4709
/* Emit a NOP instruction for CYCLES cycles after insn AFTER.  Return it.  */
4710
 
4711
static rtx
4712
emit_nop_after (int cycles, rtx after)
4713
{
4714
  rtx insn;
4715
 
4716
  /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4717
     operation.  We don't need the extra NOP since in this case, the hardware
4718
     will automatically insert the required stall.  */
4719
  if (cycles == 10)
4720
    cycles--;
4721
 
4722
  gcc_assert (cycles < 10);
4723
 
4724
  insn = emit_insn_after (gen_nop_count (GEN_INT (cycles)), after);
4725
  PUT_MODE (insn, TImode);
4726
 
4727
  return insn;
4728
}
4729
 
4730
/* Determine whether INSN is a call that needs to have a return label
4731
   placed.  */
4732
 
4733
static bool
4734
returning_call_p (rtx insn)
4735
{
4736
  if (CALL_P (insn))
4737
    return (!SIBLING_CALL_P (insn)
4738
            && get_attr_type (insn) != TYPE_CALLP
4739
            && get_attr_type (insn) != TYPE_SHADOW);
4740
  if (recog_memoized (insn) < 0)
4741
    return false;
4742
  if (get_attr_type (insn) == TYPE_CALL)
4743
    return true;
4744
  return false;
4745
}
4746
 
4747
/* Determine whether INSN's pattern can be converted to use callp.  */
4748
static bool
4749
can_use_callp (rtx insn)
4750
{
4751
  int icode = recog_memoized (insn);
4752
  if (!TARGET_INSNS_64PLUS
4753
      || icode < 0
4754
      || GET_CODE (PATTERN (insn)) == COND_EXEC)
4755
    return false;
4756
 
4757
  return ((icode == CODE_FOR_real_call
4758
           || icode == CODE_FOR_call_internal
4759
           || icode == CODE_FOR_call_value_internal)
4760
          && get_attr_dest_regfile (insn) == DEST_REGFILE_ANY);
4761
}
4762
 
4763
/* Convert the pattern of INSN, which must be a CALL_INSN, into a callp.  */
4764
static void
4765
convert_to_callp (rtx insn)
4766
{
4767
  rtx lab;
4768
  extract_insn (insn);
4769
  if (GET_CODE (PATTERN (insn)) == SET)
4770
    {
4771
      rtx dest = recog_data.operand[0];
4772
      lab = recog_data.operand[1];
4773
      PATTERN (insn) = gen_callp_value (dest, lab);
4774
      INSN_CODE (insn) = CODE_FOR_callp_value;
4775
    }
4776
  else
4777
    {
4778
      lab = recog_data.operand[0];
4779
      PATTERN (insn) = gen_callp (lab);
4780
      INSN_CODE (insn) = CODE_FOR_callp;
4781
    }
4782
}
4783
 
4784
/* Scan forwards from INSN until we find the next insn that has mode TImode
4785
   (indicating it starts a new cycle), and occurs in cycle CLOCK.
4786
   Return it if we find such an insn, NULL_RTX otherwise.  */
4787
static rtx
4788
find_next_cycle_insn (rtx insn, int clock)
4789
{
4790
  rtx t = insn;
4791
  if (GET_MODE (t) == TImode)
4792
    t = next_real_insn (t);
4793
  while (t && GET_MODE (t) != TImode)
4794
    t = next_real_insn (t);
4795
 
4796
  if (t && insn_get_clock (t) == clock)
4797
    return t;
4798
  return NULL_RTX;
4799
}
4800
 
4801
/* If COND_INSN has a COND_EXEC condition, wrap the same condition
4802
   around PAT.  Return PAT either unchanged or modified in this
4803
   way.  */
4804
static rtx
4805
duplicate_cond (rtx pat, rtx cond_insn)
4806
{
4807
  rtx cond_pat = PATTERN (cond_insn);
4808
  if (GET_CODE (cond_pat) == COND_EXEC)
4809
    pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (COND_EXEC_TEST (cond_pat)),
4810
                             pat);
4811
  return pat;
4812
}
4813
 
4814
/* Walk forward from INSN to find the last insn that issues in the same clock
4815
   cycle.  */
4816
static rtx
4817
find_last_same_clock (rtx insn)
4818
{
4819
  rtx retval = insn;
4820
  rtx t = next_real_insn (insn);
4821
 
4822
  while (t && GET_MODE (t) != TImode)
4823
    {
4824
      if (!DEBUG_INSN_P (t) && recog_memoized (t) >= 0)
4825
        retval = t;
4826
      t = next_real_insn (t);
4827
    }
4828
  return retval;
4829
}
4830
 
4831
/* For every call insn in the function, emit code to load the return
4832
   address.  For each call we create a return label and store it in
4833
   CALL_LABELS.  If are not scheduling, we emit the labels here,
4834
   otherwise the caller will do it later.
4835
   This function is called after final insn scheduling, but before creating
4836
   the SEQUENCEs that represent execute packets.  */
4837
 
4838
static void
4839
reorg_split_calls (rtx *call_labels)
4840
{
4841
  unsigned int reservation_mask = 0;
4842
  rtx insn = get_insns ();
4843
  gcc_assert (GET_CODE (insn) == NOTE);
4844
  insn = next_real_insn (insn);
4845
  while (insn)
4846
    {
4847
      int uid;
4848
      rtx next = next_real_insn (insn);
4849
 
4850
      if (DEBUG_INSN_P (insn))
4851
        goto done;
4852
 
4853
      if (GET_MODE (insn) == TImode)
4854
        reservation_mask = 0;
4855
      uid = INSN_UID (insn);
4856
      if (c6x_flag_schedule_insns2 && recog_memoized (insn) >= 0)
4857
        reservation_mask |= 1 << INSN_INFO_ENTRY (uid).reservation;
4858
 
4859
      if (returning_call_p (insn))
4860
        {
4861
          rtx label = gen_label_rtx ();
4862
          rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
4863
          rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
4864
 
4865
          LABEL_NUSES (label) = 2;
4866
          if (!c6x_flag_schedule_insns2)
4867
            {
4868
              if (can_use_callp (insn))
4869
                convert_to_callp (insn);
4870
              else
4871
                {
4872
                  rtx t;
4873
                  rtx slot[4];
4874
                  emit_label_after (label, insn);
4875
 
4876
                  /* Bundle the call and its delay slots into a single
4877
                     SEQUENCE.  While these do not issue in parallel
4878
                     we need to group them into a single EH region.  */
4879
                  slot[0] = insn;
4880
                  PUT_MODE (insn, TImode);
4881
                  if (TARGET_INSNS_64)
4882
                    {
4883
                      t = gen_addkpc (reg, labelref, GEN_INT (4));
4884
                      slot[1] = emit_insn_after (duplicate_cond (t, insn),
4885
                                                 insn);
4886
                      PUT_MODE (slot[1], TImode);
4887
                      gen_one_bundle (slot, 2, 0);
4888
                    }
4889
                  else
4890
                    {
4891
                      slot[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4892
                                                 insn);
4893
                      PUT_MODE (slot[3], TImode);
4894
                      t = gen_movsi_lo_sum (reg, reg, labelref);
4895
                      slot[2] = emit_insn_after (duplicate_cond (t, insn),
4896
                                                  insn);
4897
                      PUT_MODE (slot[2], TImode);
4898
                      t = gen_movsi_high (reg, labelref);
4899
                      slot[1] = emit_insn_after (duplicate_cond (t, insn),
4900
                                                 insn);
4901
                      PUT_MODE (slot[1], TImode);
4902
                      gen_one_bundle (slot, 4, 0);
4903
                    }
4904
                }
4905
            }
4906
          else
4907
            {
4908
              /* If we scheduled, we reserved the .S2 unit for one or two
4909
                 cycles after the call.  Emit the insns in these slots,
4910
                 unless it's possible to create a CALLP insn.
4911
                 Note that this works because the dependencies ensure that
4912
                 no insn setting/using B3 is scheduled in the delay slots of
4913
                 a call.  */
4914
              int this_clock = insn_get_clock (insn);
4915
              rtx last_same_clock;
4916
              rtx after1;
4917
 
4918
              call_labels[INSN_UID (insn)] = label;
4919
 
4920
              last_same_clock = find_last_same_clock (insn);
4921
 
4922
              if (can_use_callp (insn))
4923
                {
4924
                  /* Find the first insn of the next execute packet.  If it
4925
                     is the shadow insn corresponding to this call, we may
4926
                     use a CALLP insn.  */
4927
                  rtx shadow = next_nonnote_nondebug_insn (last_same_clock);
4928
 
4929
                  if (CALL_P (shadow)
4930
                      && insn_get_clock (shadow) == this_clock + 5)
4931
                    {
4932
                      convert_to_callp (shadow);
4933
                      insn_set_clock (shadow, this_clock);
4934
                      INSN_INFO_ENTRY (INSN_UID (shadow)).reservation
4935
                        = RESERVATION_S2;
4936
                      INSN_INFO_ENTRY (INSN_UID (shadow)).unit_mask
4937
                        = INSN_INFO_ENTRY (INSN_UID (last_same_clock)).unit_mask;
4938
                      if (GET_MODE (insn) == TImode)
4939
                        {
4940
                          rtx new_cycle_first = NEXT_INSN (insn);
4941
                          while (!NONDEBUG_INSN_P (new_cycle_first)
4942
                                 || GET_CODE (PATTERN (new_cycle_first)) == USE
4943
                                 || GET_CODE (PATTERN (new_cycle_first)) == CLOBBER)
4944
                            new_cycle_first = NEXT_INSN (new_cycle_first);
4945
                          PUT_MODE (new_cycle_first, TImode);
4946
                          if (new_cycle_first != shadow)
4947
                            PUT_MODE (shadow, VOIDmode);
4948
                          INSN_INFO_ENTRY (INSN_UID (new_cycle_first)).ebb_start
4949
                            = INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start;
4950
                        }
4951
                      else
4952
                        PUT_MODE (shadow, VOIDmode);
4953
                      delete_insn (insn);
4954
                      goto done;
4955
                    }
4956
                }
4957
              after1 = find_next_cycle_insn (last_same_clock, this_clock + 1);
4958
              if (after1 == NULL_RTX)
4959
                after1 = last_same_clock;
4960
              else
4961
                after1 = find_last_same_clock (after1);
4962
              if (TARGET_INSNS_64)
4963
                {
4964
                  rtx x1 = gen_addkpc (reg, labelref, const0_rtx);
4965
                  x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4966
                  insn_set_clock (x1, this_clock + 1);
4967
                  INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4968
                  if (after1 == last_same_clock)
4969
                    PUT_MODE (x1, TImode);
4970
                  else
4971
                    INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
4972
                      = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
4973
                }
4974
              else
4975
                {
4976
                  rtx x1, x2;
4977
                  rtx after2 = find_next_cycle_insn (after1, this_clock + 2);
4978
                  if (after2 == NULL_RTX)
4979
                    after2 = after1;
4980
                  x2 = gen_movsi_lo_sum (reg, reg, labelref);
4981
                  x2 = emit_insn_after (duplicate_cond (x2, insn), after2);
4982
                  x1 = gen_movsi_high (reg, labelref);
4983
                  x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4984
                  insn_set_clock (x1, this_clock + 1);
4985
                  insn_set_clock (x2, this_clock + 2);
4986
                  INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4987
                  INSN_INFO_ENTRY (INSN_UID (x2)).reservation = RESERVATION_S2;
4988
                  if (after1 == last_same_clock)
4989
                    PUT_MODE (x1, TImode);
4990
                  else
4991
                    INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
4992
                      = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
4993
                  if (after1 == after2)
4994
                    PUT_MODE (x2, TImode);
4995
                  else
4996
                    INSN_INFO_ENTRY (INSN_UID (x2)).unit_mask
4997
                      = INSN_INFO_ENTRY (INSN_UID (after2)).unit_mask;
4998
                }
4999
            }
5000
        }
5001
    done:
5002
      insn = next;
5003
    }
5004
}
5005
 
5006
/* Called as part of c6x_reorg.  This function emits multi-cycle NOP
5007
   insns as required for correctness.  CALL_LABELS is the array that
5008
   holds the return labels for call insns; we emit these here if
5009
   scheduling was run earlier.  */
5010
 
5011
static void
5012
reorg_emit_nops (rtx *call_labels)
5013
{
5014
  bool first;
5015
  rtx prev, last_call;
5016
  int prev_clock, earliest_bb_end;
5017
  int prev_implicit_nops;
5018
  rtx insn = get_insns ();
5019
 
5020
  /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5021
     its issue time in PREV_CLOCK for the next iteration.  If there is a gap in
5022
     clocks, we must insert a NOP.
5023
     EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5024
     current basic block will finish.  We must not allow the next basic block to
5025
     begin before this cycle.
5026
     PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5027
     a multi-cycle nop.  The code is scheduled such that subsequent insns will
5028
     show the cycle gap, but we needn't insert a real NOP instruction.  */
5029
  insn = next_real_insn (insn);
5030
  last_call = prev = NULL_RTX;
5031
  prev_clock = -1;
5032
  earliest_bb_end = 0;
5033
  prev_implicit_nops = 0;
5034
  first = true;
5035
  while (insn)
5036
    {
5037
      int this_clock = -1;
5038
      rtx next;
5039
      int max_cycles = 0;
5040
 
5041
      next = next_real_insn (insn);
5042
 
5043
      if (DEBUG_INSN_P (insn)
5044
          || GET_CODE (PATTERN (insn)) == USE
5045
          || GET_CODE (PATTERN (insn)) == CLOBBER
5046
          || shadow_or_blockage_p (insn)
5047
          || (JUMP_P (insn)
5048
              && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
5049
                  || GET_CODE (PATTERN (insn)) == ADDR_VEC)))
5050
        goto next_insn;
5051
 
5052
      if (!c6x_flag_schedule_insns2)
5053
        /* No scheduling; ensure that no parallel issue happens.  */
5054
        PUT_MODE (insn, TImode);
5055
      else
5056
        {
5057
          int cycles;
5058
 
5059
          this_clock = insn_get_clock (insn);
5060
          if (this_clock != prev_clock)
5061
            {
5062
              PUT_MODE (insn, TImode);
5063
 
5064
              if (!first)
5065
                {
5066
                  cycles = this_clock - prev_clock;
5067
 
5068
                  cycles -= prev_implicit_nops;
5069
                  if (cycles > 1)
5070
                    {
5071
                      rtx nop = emit_nop_after (cycles - 1, prev);
5072
                      insn_set_clock (nop, prev_clock + prev_implicit_nops + 1);
5073
                    }
5074
                }
5075
              prev_clock = this_clock;
5076
 
5077
              if (last_call
5078
                  && insn_get_clock (last_call) + 6 <= this_clock)
5079
                {
5080
                  emit_label_before (call_labels[INSN_UID (last_call)], insn);
5081
                  last_call = NULL_RTX;
5082
                }
5083
              prev_implicit_nops = 0;
5084
            }
5085
        }
5086
 
5087
      /* Examine how many cycles the current insn takes, and adjust
5088
         LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS.  */
5089
      if (recog_memoized (insn) >= 0
5090
          /* If not scheduling, we've emitted NOPs after calls already.  */
5091
          && (c6x_flag_schedule_insns2 || !returning_call_p (insn)))
5092
        {
5093
          max_cycles = get_attr_cycles (insn);
5094
          if (get_attr_type (insn) == TYPE_CALLP)
5095
            prev_implicit_nops = 5;
5096
        }
5097
      else
5098
        max_cycles = 1;
5099
      if (returning_call_p (insn))
5100
        last_call = insn;
5101
 
5102
      if (c6x_flag_schedule_insns2)
5103
        {
5104
          gcc_assert (this_clock >= 0);
5105
          if (earliest_bb_end < this_clock + max_cycles)
5106
            earliest_bb_end = this_clock + max_cycles;
5107
        }
5108
      else if (max_cycles > 1)
5109
        emit_nop_after (max_cycles - 1, insn);
5110
 
5111
      prev = insn;
5112
      first = false;
5113
 
5114
    next_insn:
5115
      if (c6x_flag_schedule_insns2
5116
          && (next == NULL_RTX
5117
              || (GET_MODE (next) == TImode
5118
                  && INSN_INFO_ENTRY (INSN_UID (next)).ebb_start))
5119
          && earliest_bb_end > 0)
5120
        {
5121
          int cycles = earliest_bb_end - prev_clock;
5122
          if (cycles > 1)
5123
            {
5124
              prev = emit_nop_after (cycles - 1, prev);
5125
              insn_set_clock (prev, prev_clock + prev_implicit_nops + 1);
5126
            }
5127
          earliest_bb_end = 0;
5128
          prev_clock = -1;
5129
          first = true;
5130
 
5131
          if (last_call)
5132
            emit_label_after (call_labels[INSN_UID (last_call)], prev);
5133
          last_call = NULL_RTX;
5134
        }
5135
      insn = next;
5136
    }
5137
}
5138
 
5139
/* If possible, split INSN, which we know is either a jump or a call, into a real
5140
   insn and its shadow.  */
5141
static void
5142
split_delayed_branch (rtx insn)
5143
{
5144
  int code = recog_memoized (insn);
5145
  rtx i1, newpat;
5146
  rtx pat = PATTERN (insn);
5147
 
5148
  if (GET_CODE (pat) == COND_EXEC)
5149
    pat = COND_EXEC_CODE (pat);
5150
 
5151
  if (CALL_P (insn))
5152
    {
5153
      rtx src = pat, dest = NULL_RTX;
5154
      rtx callee;
5155
      if (GET_CODE (pat) == SET)
5156
        {
5157
          dest = SET_DEST (pat);
5158
          src = SET_SRC (pat);
5159
        }
5160
      callee = XEXP (XEXP (src, 0), 0);
5161
      if (SIBLING_CALL_P (insn))
5162
        {
5163
          if (REG_P (callee))
5164
            newpat = gen_indirect_sibcall_shadow ();
5165
          else
5166
            newpat = gen_sibcall_shadow (callee);
5167
          pat = gen_real_jump (callee);
5168
        }
5169
      else if (dest != NULL_RTX)
5170
        {
5171
          if (REG_P (callee))
5172
            newpat = gen_indirect_call_value_shadow (dest);
5173
          else
5174
            newpat = gen_call_value_shadow (dest, callee);
5175
          pat = gen_real_call (callee);
5176
        }
5177
      else
5178
        {
5179
          if (REG_P (callee))
5180
            newpat = gen_indirect_call_shadow ();
5181
          else
5182
            newpat = gen_call_shadow (callee);
5183
          pat = gen_real_call (callee);
5184
        }
5185
      pat = duplicate_cond (pat, insn);
5186
      newpat = duplicate_cond (newpat, insn);
5187
    }
5188
  else
5189
    {
5190
      rtx src, op;
5191
      if (GET_CODE (pat) == PARALLEL
5192
          && GET_CODE (XVECEXP (pat, 0, 0)) == RETURN)
5193
        {
5194
          newpat = gen_return_shadow ();
5195
          pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
5196
          newpat = duplicate_cond (newpat, insn);
5197
        }
5198
      else
5199
        switch (code)
5200
          {
5201
          case CODE_FOR_br_true:
5202
          case CODE_FOR_br_false:
5203
            src = SET_SRC (pat);
5204
            op = XEXP (src, code == CODE_FOR_br_true ? 1 : 2);
5205
            newpat = gen_condjump_shadow (op);
5206
            pat = gen_real_jump (op);
5207
            if (code == CODE_FOR_br_true)
5208
              pat = gen_rtx_COND_EXEC (VOIDmode, XEXP (src, 0), pat);
5209
            else
5210
              pat = gen_rtx_COND_EXEC (VOIDmode,
5211
                                       reversed_comparison (XEXP (src, 0),
5212
                                                            VOIDmode),
5213
                                       pat);
5214
            break;
5215
 
5216
          case CODE_FOR_jump:
5217
            op = SET_SRC (pat);
5218
            newpat = gen_jump_shadow (op);
5219
            break;
5220
 
5221
          case CODE_FOR_indirect_jump:
5222
            newpat = gen_indirect_jump_shadow ();
5223
            break;
5224
 
5225
          case CODE_FOR_return_internal:
5226
            newpat = gen_return_shadow ();
5227
            pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
5228
            break;
5229
 
5230
          default:
5231
            return;
5232
          }
5233
    }
5234
  i1 = emit_insn_before (pat, insn);
5235
  PATTERN (insn) = newpat;
5236
  INSN_CODE (insn) = -1;
5237
  record_delay_slot_pair (i1, insn, 5, 0);
5238
}
5239
 
5240
/* If INSN is a multi-cycle insn that should be handled properly in
5241
   modulo-scheduling, split it into a real insn and a shadow.
5242
   Return true if we made a change.
5243
 
5244
   It is valid for us to fail to split an insn; the caller has to deal
5245
   with the possibility.  Currently we handle loads and most mpy2 and
5246
   mpy4 insns.  */
5247
static bool
5248
split_delayed_nonbranch (rtx insn)
5249
{
5250
  int code = recog_memoized (insn);
5251
  enum attr_type type;
5252
  rtx i1, newpat, src, dest;
5253
  rtx pat = PATTERN (insn);
5254
  rtvec rtv;
5255
  int delay;
5256
 
5257
  if (GET_CODE (pat) == COND_EXEC)
5258
    pat = COND_EXEC_CODE (pat);
5259
 
5260
  if (code < 0 || GET_CODE (pat) != SET)
5261
    return false;
5262
  src = SET_SRC (pat);
5263
  dest = SET_DEST (pat);
5264
  if (!REG_P (dest))
5265
    return false;
5266
 
5267
  type = get_attr_type (insn);
5268
  if (code >= 0
5269
      && (type == TYPE_LOAD
5270
          || type == TYPE_LOADN))
5271
    {
5272
      if (!MEM_P (src)
5273
          && (GET_CODE (src) != ZERO_EXTEND
5274
              || !MEM_P (XEXP (src, 0))))
5275
        return false;
5276
 
5277
      if (GET_MODE_SIZE (GET_MODE (dest)) > 4
5278
          && (GET_MODE_SIZE (GET_MODE (dest)) != 8 || !TARGET_LDDW))
5279
        return false;
5280
 
5281
      rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
5282
                       SET_SRC (pat));
5283
      newpat = gen_load_shadow (SET_DEST (pat));
5284
      pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_LOAD);
5285
      delay = 4;
5286
    }
5287
  else if (code >= 0
5288
           && (type == TYPE_MPY2
5289
               || type == TYPE_MPY4))
5290
    {
5291
      /* We don't handle floating point multiplies yet.  */
5292
      if (GET_MODE (dest) == SFmode)
5293
        return false;
5294
 
5295
      rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
5296
                       SET_SRC (pat));
5297
      newpat = gen_mult_shadow (SET_DEST (pat));
5298
      pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_MULT);
5299
      delay = type == TYPE_MPY2 ? 1 : 3;
5300
    }
5301
  else
5302
    return false;
5303
 
5304
  pat = duplicate_cond (pat, insn);
5305
  newpat = duplicate_cond (newpat, insn);
5306
  i1 = emit_insn_before (pat, insn);
5307
  PATTERN (insn) = newpat;
5308
  INSN_CODE (insn) = -1;
5309
  recog_memoized (insn);
5310
  recog_memoized (i1);
5311
  record_delay_slot_pair (i1, insn, delay, 0);
5312
  return true;
5313
}
5314
 
5315
/* Examine if INSN is the result of splitting a load into a real load and a
5316
   shadow, and if so, undo the transformation.  */
5317
static void
5318
undo_split_delayed_nonbranch (rtx insn)
5319
{
5320
  int icode = recog_memoized (insn);
5321
  enum attr_type type;
5322
  rtx prev_pat, insn_pat, prev;
5323
 
5324
  if (icode < 0)
5325
    return;
5326
  type = get_attr_type (insn);
5327
  if (type != TYPE_LOAD_SHADOW && type != TYPE_MULT_SHADOW)
5328
    return;
5329
  prev = PREV_INSN (insn);
5330
  prev_pat = PATTERN (prev);
5331
  insn_pat = PATTERN (insn);
5332
  if (GET_CODE (prev_pat) == COND_EXEC)
5333
    {
5334
      prev_pat = COND_EXEC_CODE (prev_pat);
5335
      insn_pat = COND_EXEC_CODE (insn_pat);
5336
    }
5337
 
5338
  gcc_assert (GET_CODE (prev_pat) == UNSPEC
5339
              && ((XINT (prev_pat, 1) == UNSPEC_REAL_LOAD
5340
                   && type == TYPE_LOAD_SHADOW)
5341
                  || (XINT (prev_pat, 1) == UNSPEC_REAL_MULT
5342
                      && type == TYPE_MULT_SHADOW)));
5343
  insn_pat = gen_rtx_SET (VOIDmode, SET_DEST (insn_pat),
5344
                          XVECEXP (prev_pat, 0, 1));
5345
  insn_pat = duplicate_cond (insn_pat, prev);
5346
  PATTERN (insn) = insn_pat;
5347
  INSN_CODE (insn) = -1;
5348
  delete_insn (prev);
5349
}
5350
 
5351
/* Split every insn (i.e. jumps and calls) which can have delay slots into
5352
   two parts: the first one is scheduled normally and emits the instruction,
5353
   while the second one is a shadow insn which shows the side effect taking
5354
   place. The second one is placed in the right cycle by the scheduler, but
5355
   not emitted as an assembly instruction.  */
5356
 
5357
static void
5358
split_delayed_insns (void)
5359
{
5360
  rtx insn;
5361
  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5362
    {
5363
      if (JUMP_P (insn) || CALL_P (insn))
5364
        split_delayed_branch (insn);
5365
    }
5366
}
5367
 
5368
/* For every insn that has an entry in the new_conditions vector, give it
5369
   the appropriate predicate.  */
5370
static void
5371
conditionalize_after_sched (void)
5372
{
5373
  basic_block bb;
5374
  rtx insn;
5375
  FOR_EACH_BB (bb)
5376
    FOR_BB_INSNS (bb, insn)
5377
      {
5378
        unsigned uid = INSN_UID (insn);
5379
        rtx cond;
5380
        if (!NONDEBUG_INSN_P (insn) || uid >= INSN_INFO_LENGTH)
5381
          continue;
5382
        cond = INSN_INFO_ENTRY (uid).new_cond;
5383
        if (cond == NULL_RTX)
5384
          continue;
5385
        if (dump_file)
5386
          fprintf (dump_file, "Conditionalizing insn %d\n", uid);
5387
        predicate_insn (insn, cond, true);
5388
      }
5389
}
5390
 
5391
/* A callback for the hw-doloop pass.  This function examines INSN; if
5392
   it is a loop_end pattern we recognize, return the reg rtx for the
5393
   loop counter.  Otherwise, return NULL_RTX.  */
5394
 
5395
static rtx
5396
hwloop_pattern_reg (rtx insn)
5397
{
5398
  rtx pat, reg;
5399
 
5400
  if (!JUMP_P (insn) || recog_memoized (insn) != CODE_FOR_loop_end)
5401
    return NULL_RTX;
5402
 
5403
  pat = PATTERN (insn);
5404
  reg = SET_DEST (XVECEXP (pat, 0, 1));
5405
  if (!REG_P (reg))
5406
    return NULL_RTX;
5407
  return reg;
5408
}
5409
 
5410
/* Return the number of cycles taken by BB, as computed by scheduling,
5411
   including the latencies of all insns with delay slots.  IGNORE is
5412
   an insn we should ignore in the calculation, usually the final
5413
   branch.  */
5414
static int
5415
bb_earliest_end_cycle (basic_block bb, rtx ignore)
5416
{
5417
  int earliest = 0;
5418
  rtx insn;
5419
 
5420
  FOR_BB_INSNS (bb, insn)
5421
    {
5422
      int cycles, this_clock;
5423
 
5424
      if (LABEL_P (insn) || NOTE_P (insn) || DEBUG_INSN_P (insn)
5425
          || GET_CODE (PATTERN (insn)) == USE
5426
          || GET_CODE (PATTERN (insn)) == CLOBBER
5427
          || insn == ignore)
5428
        continue;
5429
 
5430
      this_clock = insn_get_clock (insn);
5431
      cycles = get_attr_cycles (insn);
5432
 
5433
      if (earliest < this_clock + cycles)
5434
        earliest = this_clock + cycles;
5435
    }
5436
  return earliest;
5437
}
5438
 
5439
/* Examine the insns in BB and remove all which have a uid greater or
5440
   equal to MAX_UID.  */
5441
static void
5442
filter_insns_above (basic_block bb, int max_uid)
5443
{
5444
  rtx insn, next;
5445
  bool prev_ti = false;
5446
  int prev_cycle = -1;
5447
 
5448
  FOR_BB_INSNS_SAFE (bb, insn, next)
5449
    {
5450
      int this_cycle;
5451
      if (!NONDEBUG_INSN_P (insn))
5452
        continue;
5453
      if (insn == BB_END (bb))
5454
        return;
5455
      this_cycle = insn_get_clock (insn);
5456
      if (prev_ti && this_cycle == prev_cycle)
5457
        {
5458
          gcc_assert (GET_MODE (insn) != TImode);
5459
          PUT_MODE (insn, TImode);
5460
        }
5461
      prev_ti = false;
5462
      if (INSN_UID (insn) >= max_uid)
5463
        {
5464
          if (GET_MODE (insn) == TImode)
5465
            {
5466
              prev_ti = true;
5467
              prev_cycle = this_cycle;
5468
            }
5469
          delete_insn (insn);
5470
        }
5471
    }
5472
}
5473
 
5474
/* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY.  */
5475
 
5476
static void
5477
c6x_asm_emit_except_personality (rtx personality)
5478
{
5479
  fputs ("\t.personality\t", asm_out_file);
5480
  output_addr_const (asm_out_file, personality);
5481
  fputc ('\n', asm_out_file);
5482
}
5483
 
5484
/* Use a special assembly directive rather than a regular setion for
5485
   unwind table data.  */
5486
 
5487
static void
5488
c6x_asm_init_sections (void)
5489
{
5490
  exception_section = get_unnamed_section (0, output_section_asm_op,
5491
                                           "\t.handlerdata");
5492
}
5493
 
5494
/* A callback for the hw-doloop pass.  Called to optimize LOOP in a
5495
   machine-specific fashion; returns true if successful and false if
5496
   the hwloop_fail function should be called.  */
5497
 
5498
static bool
5499
hwloop_optimize (hwloop_info loop)
5500
{
5501
  basic_block entry_bb, bb;
5502
  rtx seq, insn, prev, entry_after, end_packet;
5503
  rtx head_insn, tail_insn, new_insns, last_insn;
5504
  int loop_earliest;
5505
  int n_execute_packets;
5506
  edge entry_edge;
5507
  unsigned ix;
5508
  int max_uid_before, delayed_splits;
5509
  int i, sp_ii, min_ii, max_ii, max_parallel, n_insns, n_real_insns, stages;
5510
  rtx *orig_vec;
5511
  rtx *copies;
5512
  rtx **insn_copies;
5513
 
5514
  if (!c6x_flag_modulo_sched || !c6x_flag_schedule_insns2
5515
      || !TARGET_INSNS_64PLUS)
5516
    return false;
5517
 
5518
  if (loop->iter_reg_used || loop->depth > 1)
5519
    return false;
5520
  if (loop->has_call || loop->has_asm)
5521
    return false;
5522
 
5523
  if (loop->head != loop->tail)
5524
    return false;
5525
 
5526
  gcc_assert (loop->incoming_dest == loop->head);
5527
 
5528
  entry_edge = NULL;
5529
  FOR_EACH_VEC_ELT (edge, loop->incoming, i, entry_edge)
5530
    if (entry_edge->flags & EDGE_FALLTHRU)
5531
      break;
5532
  if (entry_edge == NULL)
5533
    return false;
5534
 
5535
  reshuffle_units (loop->head);
5536
 
5537
  schedule_ebbs_init ();
5538
  schedule_ebb (BB_HEAD (loop->tail), loop->loop_end, true);
5539
  schedule_ebbs_finish ();
5540
 
5541
  bb = loop->head;
5542
  loop_earliest = bb_earliest_end_cycle (bb, loop->loop_end) + 1;
5543
 
5544
  max_uid_before = get_max_uid ();
5545
 
5546
  /* Split all multi-cycle operations, such as loads.  For normal
5547
     scheduling, we only do this for branches, as the generated code
5548
     would otherwise not be interrupt-safe.  When using sploop, it is
5549
     safe and beneficial to split them.  If any multi-cycle operations
5550
     remain after splitting (because we don't handle them yet), we
5551
     cannot pipeline the loop.  */
5552
  delayed_splits = 0;
5553
  FOR_BB_INSNS (bb, insn)
5554
    {
5555
      if (NONDEBUG_INSN_P (insn))
5556
        {
5557
          recog_memoized (insn);
5558
          if (split_delayed_nonbranch (insn))
5559
            delayed_splits++;
5560
          else if (INSN_CODE (insn) >= 0
5561
                   && get_attr_cycles (insn) > 1)
5562
            goto undo_splits;
5563
        }
5564
    }
5565
 
5566
  /* Count the number of insns as well as the number real insns, and save
5567
     the original sequence of insns in case we must restore it later.  */
5568
  n_insns = n_real_insns = 0;
5569
  FOR_BB_INSNS (bb, insn)
5570
    {
5571
      n_insns++;
5572
      if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
5573
        n_real_insns++;
5574
    }
5575
  orig_vec = XNEWVEC (rtx, n_insns);
5576
  n_insns = 0;
5577
  FOR_BB_INSNS (bb, insn)
5578
    orig_vec[n_insns++] = insn;
5579
 
5580
  /* Count the unit reservations, and compute a minimum II from that
5581
     table.  */
5582
  count_unit_reqs (unit_reqs, loop->start_label,
5583
                   PREV_INSN (loop->loop_end));
5584
  merge_unit_reqs (unit_reqs);
5585
 
5586
  min_ii = res_mii (unit_reqs);
5587
  max_ii = loop_earliest < 15 ? loop_earliest : 14;
5588
 
5589
  /* Make copies of the loop body, up to a maximum number of stages we want
5590
     to handle.  */
5591
  max_parallel = loop_earliest / min_ii + 1;
5592
 
5593
  copies = XCNEWVEC (rtx, (max_parallel + 1) * n_real_insns);
5594
  insn_copies = XNEWVEC (rtx *, max_parallel + 1);
5595
  for (i = 0; i < max_parallel + 1; i++)
5596
    insn_copies[i] = copies + i * n_real_insns;
5597
 
5598
  head_insn = next_nonnote_nondebug_insn (loop->start_label);
5599
  tail_insn = prev_real_insn (BB_END (bb));
5600
 
5601
  i = 0;
5602
  FOR_BB_INSNS (bb, insn)
5603
    if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
5604
      insn_copies[0][i++] = insn;
5605
 
5606
  sploop_max_uid_iter0 = get_max_uid ();
5607
 
5608
  /* Generate the copies of the loop body, and save them in the
5609
     INSN_COPIES array.  */
5610
  start_sequence ();
5611
  for (i = 0; i < max_parallel; i++)
5612
    {
5613
      int j;
5614
      rtx this_iter;
5615
 
5616
      this_iter = duplicate_insn_chain (head_insn, tail_insn);
5617
      j = 0;
5618
      while (this_iter)
5619
        {
5620
          rtx prev_stage_insn = insn_copies[i][j];
5621
          gcc_assert (INSN_CODE (this_iter) == INSN_CODE (prev_stage_insn));
5622
 
5623
          if (INSN_CODE (this_iter) >= 0
5624
              && (get_attr_type (this_iter) == TYPE_LOAD_SHADOW
5625
                  || get_attr_type (this_iter) == TYPE_MULT_SHADOW))
5626
            {
5627
              rtx prev = PREV_INSN (this_iter);
5628
              record_delay_slot_pair (prev, this_iter,
5629
                                      get_attr_cycles (prev) - 1, 0);
5630
            }
5631
          else
5632
            record_delay_slot_pair (prev_stage_insn, this_iter, i, 1);
5633
 
5634
          insn_copies[i + 1][j] = this_iter;
5635
          j++;
5636
          this_iter = next_nonnote_nondebug_insn (this_iter);
5637
        }
5638
    }
5639
  new_insns = get_insns ();
5640
  last_insn = insn_copies[max_parallel][n_real_insns - 1];
5641
  end_sequence ();
5642
  emit_insn_before (new_insns, BB_END (bb));
5643
 
5644
  /* Try to schedule the loop using varying initiation intervals,
5645
     starting with the smallest possible and incrementing it
5646
     on failure.  */
5647
  for (sp_ii = min_ii; sp_ii <= max_ii; sp_ii++)
5648
    {
5649
      basic_block tmp_bb;
5650
      if (dump_file)
5651
        fprintf (dump_file, "Trying to schedule for II %d\n", sp_ii);
5652
 
5653
      df_clear_flags (DF_LR_RUN_DCE);
5654
 
5655
      schedule_ebbs_init ();
5656
      set_modulo_params (sp_ii, max_parallel, n_real_insns,
5657
                         sploop_max_uid_iter0);
5658
      tmp_bb = schedule_ebb (BB_HEAD (bb), last_insn, true);
5659
      schedule_ebbs_finish ();
5660
 
5661
      if (tmp_bb)
5662
        {
5663
          if (dump_file)
5664
            fprintf (dump_file, "Found schedule with II %d\n", sp_ii);
5665
          break;
5666
        }
5667
    }
5668
 
5669
  discard_delay_pairs_above (max_uid_before);
5670
 
5671
  if (sp_ii > max_ii)
5672
    goto restore_loop;
5673
 
5674
  stages = insn_get_clock (ss.last_scheduled_iter0) / sp_ii + 1;
5675
 
5676
  if (stages == 1 && sp_ii > 5)
5677
    goto restore_loop;
5678
 
5679
  /* At this point, we know we've been successful, unless we find later that
5680
     there are too many execute packets for the loop buffer to hold.  */
5681
 
5682
  /* Assign reservations to the instructions in the loop.  We must find
5683
     the stage that contains the full loop kernel, and transfer the
5684
     reservations of the instructions contained in it to the corresponding
5685
     instructions from iteration 0, which are the only ones we'll keep.  */
5686
  assign_reservations (BB_HEAD (bb), ss.last_scheduled_insn);
5687
  PREV_INSN (BB_END (bb)) = ss.last_scheduled_iter0;
5688
  NEXT_INSN (ss.last_scheduled_iter0) = BB_END (bb);
5689
  filter_insns_above (bb, sploop_max_uid_iter0);
5690
 
5691
  for (i = 0; i < n_real_insns; i++)
5692
    {
5693
      rtx insn = insn_copies[0][i];
5694
      int uid = INSN_UID (insn);
5695
      int stage = insn_uid_get_clock (uid) / sp_ii;
5696
 
5697
      if (stage + 1 < stages)
5698
        {
5699
          int copy_uid;
5700
          stage = stages - stage - 1;
5701
          copy_uid = INSN_UID (insn_copies[stage][i]);
5702
          INSN_INFO_ENTRY (uid).reservation
5703
            = INSN_INFO_ENTRY (copy_uid).reservation;
5704
        }
5705
    }
5706
  if (stages == 1)
5707
    stages++;
5708
 
5709
  /* Compute the number of execute packets the pipelined form of the loop will
5710
     require.  */
5711
  prev = NULL_RTX;
5712
  n_execute_packets = 0;
5713
  for (insn = loop->start_label; insn != loop->loop_end; insn = NEXT_INSN (insn))
5714
    {
5715
      if (NONDEBUG_INSN_P (insn) && GET_MODE (insn) == TImode
5716
          && !shadow_p (insn))
5717
        {
5718
          n_execute_packets++;
5719
          if (prev && insn_get_clock (prev) + 1 != insn_get_clock (insn))
5720
            /* We need an extra NOP instruction.  */
5721
            n_execute_packets++;
5722
 
5723
          prev = insn;
5724
        }
5725
    }
5726
 
5727
  end_packet = ss.last_scheduled_iter0;
5728
  while (!NONDEBUG_INSN_P (end_packet) || GET_MODE (end_packet) != TImode)
5729
    end_packet = PREV_INSN (end_packet);
5730
 
5731
  /* The earliest cycle in which we can emit the SPKERNEL instruction.  */
5732
  loop_earliest = (stages - 1) * sp_ii;
5733
  if (loop_earliest > insn_get_clock (end_packet))
5734
    {
5735
      n_execute_packets++;
5736
      end_packet = loop->loop_end;
5737
    }
5738
  else
5739
    loop_earliest = insn_get_clock (end_packet);
5740
 
5741
  if (n_execute_packets > 14)
5742
    goto restore_loop;
5743
 
5744
  /* Generate the spkernel instruction, and place it at the appropriate
5745
     spot.  */
5746
  PUT_MODE (end_packet, VOIDmode);
5747
 
5748
  insn = gen_spkernel (GEN_INT (stages - 1),
5749
                       const0_rtx, JUMP_LABEL (loop->loop_end));
5750
  insn = emit_jump_insn_before (insn, end_packet);
5751
  JUMP_LABEL (insn) = JUMP_LABEL (loop->loop_end);
5752
  insn_set_clock (insn, loop_earliest);
5753
  PUT_MODE (insn, TImode);
5754
  INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start = false;
5755
  delete_insn (loop->loop_end);
5756
 
5757
  /* Place the mvc and sploop instructions before the loop.  */
5758
  entry_bb = entry_edge->src;
5759
 
5760
  start_sequence ();
5761
 
5762
  insn = emit_insn (gen_mvilc (loop->iter_reg));
5763
  insn = emit_insn (gen_sploop (GEN_INT (sp_ii)));
5764
 
5765
  seq = get_insns ();
5766
 
5767
  if (!single_succ_p (entry_bb) || VEC_length (edge, loop->incoming) > 1)
5768
    {
5769
      basic_block new_bb;
5770
      edge e;
5771
      edge_iterator ei;
5772
 
5773
      emit_insn_before (seq, BB_HEAD (loop->head));
5774
      seq = emit_label_before (gen_label_rtx (), seq);
5775
 
5776
      new_bb = create_basic_block (seq, insn, entry_bb);
5777
      FOR_EACH_EDGE (e, ei, loop->incoming)
5778
        {
5779
          if (!(e->flags & EDGE_FALLTHRU))
5780
            redirect_edge_and_branch_force (e, new_bb);
5781
          else
5782
            redirect_edge_succ (e, new_bb);
5783
        }
5784
      make_edge (new_bb, loop->head, 0);
5785
    }
5786
  else
5787
    {
5788
      entry_after = BB_END (entry_bb);
5789
      while (DEBUG_INSN_P (entry_after)
5790
             || (NOTE_P (entry_after)
5791
                 && NOTE_KIND (entry_after) != NOTE_INSN_BASIC_BLOCK))
5792
        entry_after = PREV_INSN (entry_after);
5793
      emit_insn_after (seq, entry_after);
5794
    }
5795
 
5796
  end_sequence ();
5797
 
5798
  /* Make sure we don't try to schedule this loop again.  */
5799
  for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
5800
    bb->flags |= BB_DISABLE_SCHEDULE;
5801
 
5802
  return true;
5803
 
5804
 restore_loop:
5805
  if (dump_file)
5806
    fprintf (dump_file, "Unable to pipeline loop.\n");
5807
 
5808
  for (i = 1; i < n_insns; i++)
5809
    {
5810
      NEXT_INSN (orig_vec[i - 1]) = orig_vec[i];
5811
      PREV_INSN (orig_vec[i]) = orig_vec[i - 1];
5812
    }
5813
  PREV_INSN (orig_vec[0]) = PREV_INSN (BB_HEAD (bb));
5814
  NEXT_INSN (PREV_INSN (BB_HEAD (bb))) = orig_vec[0];
5815
  NEXT_INSN (orig_vec[n_insns - 1]) = NEXT_INSN (BB_END (bb));
5816
  PREV_INSN (NEXT_INSN (BB_END (bb))) = orig_vec[n_insns - 1];
5817
  BB_HEAD (bb) = orig_vec[0];
5818
  BB_END (bb) = orig_vec[n_insns - 1];
5819
 undo_splits:
5820
  free_delay_pairs ();
5821
  FOR_BB_INSNS (bb, insn)
5822
    if (NONDEBUG_INSN_P (insn))
5823
      undo_split_delayed_nonbranch (insn);
5824
  return false;
5825
}
5826
 
5827
/* A callback for the hw-doloop pass.  Called when a loop we have discovered
5828
   turns out not to be optimizable; we have to split the doloop_end pattern
5829
   into a subtract and a test.  */
5830
static void
5831
hwloop_fail (hwloop_info loop)
5832
{
5833
  rtx insn, test, testreg;
5834
 
5835
  if (dump_file)
5836
    fprintf (dump_file, "splitting doloop insn %d\n",
5837
             INSN_UID (loop->loop_end));
5838
  insn = gen_addsi3 (loop->iter_reg, loop->iter_reg, constm1_rtx);
5839
  /* See if we can emit the add at the head of the loop rather than at the
5840
     end.  */
5841
  if (loop->head == NULL
5842
      || loop->iter_reg_used_outside
5843
      || loop->iter_reg_used
5844
      || TEST_HARD_REG_BIT (loop->regs_set_in_loop, REGNO (loop->iter_reg))
5845
      || loop->incoming_dest != loop->head
5846
      || EDGE_COUNT (loop->head->preds) != 2)
5847
    emit_insn_before (insn, loop->loop_end);
5848
  else
5849
    {
5850
      rtx t = loop->start_label;
5851
      while (!NOTE_P (t) || NOTE_KIND (t) != NOTE_INSN_BASIC_BLOCK)
5852
        t = NEXT_INSN (t);
5853
      emit_insn_after (insn, t);
5854
    }
5855
 
5856
  testreg = SET_DEST (XVECEXP (PATTERN (loop->loop_end), 0, 2));
5857
  if (GET_CODE (testreg) == SCRATCH)
5858
    testreg = loop->iter_reg;
5859
  else
5860
    emit_insn_before (gen_movsi (testreg, loop->iter_reg), loop->loop_end);
5861
 
5862
  test = gen_rtx_NE (VOIDmode, testreg, const0_rtx);
5863
  insn = emit_jump_insn_before (gen_cbranchsi4 (test, testreg, const0_rtx,
5864
                                                loop->start_label),
5865
                                loop->loop_end);
5866
 
5867
  JUMP_LABEL (insn) = loop->start_label;
5868
  LABEL_NUSES (loop->start_label)++;
5869
  delete_insn (loop->loop_end);
5870
}
5871
 
5872
static struct hw_doloop_hooks c6x_doloop_hooks =
5873
{
5874
  hwloop_pattern_reg,
5875
  hwloop_optimize,
5876
  hwloop_fail
5877
};
5878
 
5879
/* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5880
   doloop_end patterns where such optimizations are impossible.  */
5881
static void
5882
c6x_hwloops (void)
5883
{
5884
  if (optimize)
5885
    reorg_loops (true, &c6x_doloop_hooks);
5886
}
5887
 
5888
/* Implement the TARGET_MACHINE_DEPENDENT_REORG pass.  We split call insns here
5889
   into a sequence that loads the return register and performs the call,
5890
   and emit the return label.
5891
   If scheduling after reload is requested, it happens here.  */
5892
 
5893
static void
5894
c6x_reorg (void)
5895
{
5896
  basic_block bb;
5897
  rtx *call_labels;
5898
  bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
5899
                      && !maybe_skip_selective_scheduling ());
5900
 
5901
  /* We are freeing block_for_insn in the toplev to keep compatibility
5902
     with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
5903
  compute_bb_for_insn ();
5904
 
5905
  df_clear_flags (DF_LR_RUN_DCE);
5906
  df_note_add_problem ();
5907
 
5908
  /* If optimizing, we'll have split before scheduling.  */
5909
  if (optimize == 0)
5910
    split_all_insns ();
5911
 
5912
  df_analyze ();
5913
 
5914
  if (c6x_flag_schedule_insns2)
5915
    {
5916
      int sz = get_max_uid () * 3 / 2 + 1;
5917
 
5918
      insn_info = VEC_alloc (c6x_sched_insn_info, heap, sz);
5919
    }
5920
 
5921
  /* Make sure the real-jump insns we create are not deleted.  When modulo-
5922
     scheduling, situations where a reg is only stored in a loop can also
5923
     cause dead code when doing the initial unrolling.  */
5924
  sched_no_dce = true;
5925
 
5926
  c6x_hwloops ();
5927
 
5928
  if (c6x_flag_schedule_insns2)
5929
    {
5930
      split_delayed_insns ();
5931
      timevar_push (TV_SCHED2);
5932
      if (do_selsched)
5933
        run_selective_scheduling ();
5934
      else
5935
        schedule_ebbs ();
5936
      conditionalize_after_sched ();
5937
      timevar_pop (TV_SCHED2);
5938
 
5939
      free_delay_pairs ();
5940
    }
5941
  sched_no_dce = false;
5942
 
5943
  call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
5944
 
5945
  reorg_split_calls (call_labels);
5946
 
5947
  if (c6x_flag_schedule_insns2)
5948
    {
5949
      FOR_EACH_BB (bb)
5950
        if ((bb->flags & BB_DISABLE_SCHEDULE) == 0)
5951
          assign_reservations (BB_HEAD (bb), BB_END (bb));
5952
    }
5953
 
5954
  if (c6x_flag_var_tracking)
5955
    {
5956
      timevar_push (TV_VAR_TRACKING);
5957
      variable_tracking_main ();
5958
      timevar_pop (TV_VAR_TRACKING);
5959
    }
5960
 
5961
  reorg_emit_nops (call_labels);
5962
 
5963
  /* Post-process the schedule to move parallel insns into SEQUENCEs.  */
5964
  if (c6x_flag_schedule_insns2)
5965
    {
5966
      free_delay_pairs ();
5967
      c6x_gen_bundles ();
5968
    }
5969
 
5970
  df_finish_pass (false);
5971
}
5972
 
5973
/* Called when a function has been assembled.  It should perform all the
5974
   tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
5975
   tasks.
5976
   We free the reservation (and other scheduling) information here now that
5977
   all insns have been output.  */
5978
void
5979
c6x_function_end (FILE *file, const char *fname)
5980
{
5981
  c6x_output_fn_unwind (file);
5982
 
5983
  if (insn_info)
5984
    VEC_free (c6x_sched_insn_info, heap, insn_info);
5985
  insn_info = NULL;
5986
 
5987
  if (!flag_inhibit_size_directive)
5988
    ASM_OUTPUT_MEASURED_SIZE (file, fname);
5989
}
5990
 
5991
/* Determine whether X is a shift with code CODE and an integer amount
5992
   AMOUNT.  */
5993
static bool
5994
shift_p (rtx x, enum rtx_code code, int amount)
5995
{
5996
  return (GET_CODE (x) == code && GET_CODE (XEXP (x, 1)) == CONST_INT
5997
          && INTVAL (XEXP (x, 1)) == amount);
5998
}
5999
 
6000
/* Compute a (partial) cost for rtx X.  Return true if the complete
6001
   cost has been computed, and false if subexpressions should be
6002
   scanned.  In either case, *TOTAL contains the cost result.  */
6003
 
6004
static bool
6005
c6x_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
6006
               bool speed)
6007
{
6008
  int cost2 = COSTS_N_INSNS (1);
6009
  rtx op0, op1;
6010
 
6011
  switch (code)
6012
    {
6013
    case CONST_INT:
6014
      if (outer_code == SET || outer_code == PLUS)
6015
        *total = satisfies_constraint_IsB (x) ? 0 : cost2;
6016
      else if (outer_code == AND || outer_code == IOR || outer_code == XOR
6017
               || outer_code == MINUS)
6018
        *total = satisfies_constraint_Is5 (x) ? 0 : cost2;
6019
      else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
6020
               || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
6021
        *total = satisfies_constraint_Iu4 (x) ? 0 : cost2;
6022
      else if (outer_code == ASHIFT || outer_code == ASHIFTRT
6023
               || outer_code == LSHIFTRT)
6024
        *total = satisfies_constraint_Iu5 (x) ? 0 : cost2;
6025
      else
6026
        *total = cost2;
6027
      return true;
6028
 
6029
    case CONST:
6030
    case LABEL_REF:
6031
    case SYMBOL_REF:
6032
    case CONST_DOUBLE:
6033
      *total = COSTS_N_INSNS (2);
6034
      return true;
6035
 
6036
    case TRUNCATE:
6037
      /* Recognize a mult_highpart operation.  */
6038
      if ((GET_MODE (x) == HImode || GET_MODE (x) == SImode)
6039
          && GET_CODE (XEXP (x, 0)) == LSHIFTRT
6040
          && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x))
6041
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
6042
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
6043
          && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x)))
6044
        {
6045
          rtx mul = XEXP (XEXP (x, 0), 0);
6046
          rtx op0 = XEXP (mul, 0);
6047
          rtx op1 = XEXP (mul, 1);
6048
          enum rtx_code code0 = GET_CODE (op0);
6049
          enum rtx_code code1 = GET_CODE (op1);
6050
 
6051
          if ((code0 == code1
6052
               && (code0 == SIGN_EXTEND || code0 == ZERO_EXTEND))
6053
              || (GET_MODE (x) == HImode
6054
                  && code0 == ZERO_EXTEND && code1 == SIGN_EXTEND))
6055
            {
6056
              if (GET_MODE (x) == HImode)
6057
                *total = COSTS_N_INSNS (2);
6058
              else
6059
                *total = COSTS_N_INSNS (12);
6060
              *total += rtx_cost (XEXP (op0, 0), code0, 0, speed);
6061
              *total += rtx_cost (XEXP (op1, 0), code1, 0, speed);
6062
              return true;
6063
            }
6064
        }
6065
      return false;
6066
 
6067
    case ASHIFT:
6068
    case ASHIFTRT:
6069
    case LSHIFTRT:
6070
      if (GET_MODE (x) == DImode)
6071
        *total = COSTS_N_INSNS (CONSTANT_P (XEXP (x, 1)) ? 4 : 15);
6072
      else
6073
        *total = COSTS_N_INSNS (1);
6074
      return false;
6075
 
6076
    case PLUS:
6077
    case MINUS:
6078
      *total = COSTS_N_INSNS (1);
6079
      op0 = code == PLUS ? XEXP (x, 0) : XEXP (x, 1);
6080
      op1 = code == PLUS ? XEXP (x, 1) : XEXP (x, 0);
6081
      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
6082
          && INTEGRAL_MODE_P (GET_MODE (x))
6083
          && GET_CODE (op0) == MULT
6084
          && GET_CODE (XEXP (op0, 1)) == CONST_INT
6085
          && (INTVAL (XEXP (op0, 1)) == 2
6086
              || INTVAL (XEXP (op0, 1)) == 4
6087
              || (code == PLUS && INTVAL (XEXP (op0, 1)) == 8)))
6088
        {
6089
          *total += rtx_cost (XEXP (op0, 0), ASHIFT, 0, speed);
6090
          *total += rtx_cost (op1, (enum rtx_code) code, 1, speed);
6091
          return true;
6092
        }
6093
      return false;
6094
 
6095
    case MULT:
6096
      op0 = XEXP (x, 0);
6097
      op1 = XEXP (x, 1);
6098
      if (GET_MODE (x) == DFmode)
6099
        {
6100
          if (TARGET_FP)
6101
            *total = COSTS_N_INSNS (speed ? 10 : 1);
6102
          else
6103
            *total = COSTS_N_INSNS (speed ? 200 : 4);
6104
        }
6105
      else if (GET_MODE (x) == SFmode)
6106
        {
6107
          if (TARGET_FP)
6108
            *total = COSTS_N_INSNS (speed ? 4 : 1);
6109
          else
6110
            *total = COSTS_N_INSNS (speed ? 100 : 4);
6111
        }
6112
      else if (GET_MODE (x) == DImode)
6113
        {
6114
          if (TARGET_MPY32
6115
              && GET_CODE (op0) == GET_CODE (op1)
6116
              && (GET_CODE (op0) == ZERO_EXTEND
6117
                  || GET_CODE (op0) == SIGN_EXTEND))
6118
            {
6119
              *total = COSTS_N_INSNS (speed ? 2 : 1);
6120
              op0 = XEXP (op0, 0);
6121
              op1 = XEXP (op1, 0);
6122
            }
6123
          else
6124
            /* Maybe improve this laster.  */
6125
            *total = COSTS_N_INSNS (20);
6126
        }
6127
      else if (GET_MODE (x) == SImode)
6128
        {
6129
          if (((GET_CODE (op0) == ZERO_EXTEND
6130
                || GET_CODE (op0) == SIGN_EXTEND
6131
                || shift_p (op0, LSHIFTRT, 16))
6132
               && (GET_CODE (op1) == SIGN_EXTEND
6133
                   || GET_CODE (op1) == ZERO_EXTEND
6134
                   || scst5_operand (op1, SImode)
6135
                   || shift_p (op1, ASHIFTRT, 16)
6136
                   || shift_p (op1, LSHIFTRT, 16)))
6137
              || (shift_p (op0, ASHIFTRT, 16)
6138
                  && (GET_CODE (op1) == SIGN_EXTEND
6139
                      || shift_p (op1, ASHIFTRT, 16))))
6140
            {
6141
              *total = COSTS_N_INSNS (speed ? 2 : 1);
6142
              op0 = XEXP (op0, 0);
6143
              if (scst5_operand (op1, SImode))
6144
                op1 = NULL_RTX;
6145
              else
6146
                op1 = XEXP (op1, 0);
6147
            }
6148
          else if (!speed)
6149
            *total = COSTS_N_INSNS (1);
6150
          else if (TARGET_MPY32)
6151
            *total = COSTS_N_INSNS (4);
6152
          else
6153
            *total = COSTS_N_INSNS (6);
6154
        }
6155
      else if (GET_MODE (x) == HImode)
6156
        *total = COSTS_N_INSNS (speed ? 2 : 1);
6157
 
6158
      if (GET_CODE (op0) != REG
6159
          && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
6160
        *total += rtx_cost (op0, MULT, 0, speed);
6161
      if (op1 && GET_CODE (op1) != REG
6162
          && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
6163
        *total += rtx_cost (op1, MULT, 1, speed);
6164
      return true;
6165
 
6166
    case UDIV:
6167
    case DIV:
6168
      /* This is a bit random; assuming on average there'll be 16 leading
6169
         zeros.  FIXME: estimate better for constant dividends.  */
6170
      *total = COSTS_N_INSNS (6 + 3 * 16);
6171
      return false;
6172
 
6173
    case IF_THEN_ELSE:
6174
      /* Recognize the cmp_and/ior patterns.  */
6175
      op0 = XEXP (x, 0);
6176
      if ((GET_CODE (op0) == EQ || GET_CODE (op0) == NE)
6177
          && REG_P (XEXP (op0, 0))
6178
          && XEXP (op0, 1) == const0_rtx
6179
          && rtx_equal_p (XEXP (x, 1), XEXP (op0, 0)))
6180
        {
6181
          *total = rtx_cost (XEXP (x, 1), (enum rtx_code) outer_code,
6182
                             opno, speed);
6183
          return false;
6184
        }
6185
      return false;
6186
 
6187
    default:
6188
      return false;
6189
    }
6190
}
6191
 
6192
/* Implements target hook vector_mode_supported_p.  */
6193
 
6194
static bool
6195
c6x_vector_mode_supported_p (enum machine_mode mode)
6196
{
6197
  switch (mode)
6198
    {
6199
    case V2HImode:
6200
    case V4QImode:
6201
    case V2SImode:
6202
    case V4HImode:
6203
    case V8QImode:
6204
      return true;
6205
    default:
6206
      return false;
6207
    }
6208
}
6209
 
6210
/* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE.  */
6211
static enum machine_mode
6212
c6x_preferred_simd_mode (enum machine_mode mode)
6213
{
6214
  switch (mode)
6215
    {
6216
    case HImode:
6217
      return V2HImode;
6218
    case QImode:
6219
      return V4QImode;
6220
 
6221
    default:
6222
      return word_mode;
6223
    }
6224
}
6225
 
6226
/* Implement TARGET_SCALAR_MODE_SUPPORTED_P.  */
6227
 
6228
static bool
6229
c6x_scalar_mode_supported_p (enum machine_mode mode)
6230
{
6231
  if (ALL_FIXED_POINT_MODE_P (mode)
6232
      && GET_MODE_PRECISION (mode) <= 2 * BITS_PER_WORD)
6233
    return true;
6234
 
6235
  return default_scalar_mode_supported_p (mode);
6236
}
6237
 
6238
/* Output a reference from a function exception table to the type_info
6239
   object X.  Output these via a special assembly directive.  */
6240
 
6241
static bool
6242
c6x_output_ttype (rtx x)
6243
{
6244
  /* Use special relocations for symbol references.  */
6245
  if (GET_CODE (x) != CONST_INT)
6246
    fputs ("\t.ehtype\t", asm_out_file);
6247
  else
6248
    fputs ("\t.word\t", asm_out_file);
6249
  output_addr_const (asm_out_file, x);
6250
  fputc ('\n', asm_out_file);
6251
 
6252
  return TRUE;
6253
}
6254
 
6255
/* Modify the return address of the current function.  */
6256
 
6257
void
6258
c6x_set_return_address (rtx source, rtx scratch)
6259
{
6260
  struct c6x_frame frame;
6261
  rtx addr;
6262
  HOST_WIDE_INT offset;
6263
 
6264
  c6x_compute_frame_layout (&frame);
6265
  if (! c6x_save_reg (RETURN_ADDR_REGNO))
6266
    emit_move_insn (gen_rtx_REG (Pmode, RETURN_ADDR_REGNO), source);
6267
  else
6268
    {
6269
 
6270
      if (frame_pointer_needed)
6271
        {
6272
          addr = hard_frame_pointer_rtx;
6273
          offset = frame.b3_offset;
6274
        }
6275
      else
6276
        {
6277
          addr = stack_pointer_rtx;
6278
          offset = frame.to_allocate - frame.b3_offset;
6279
        }
6280
 
6281
      /* TODO: Use base+offset loads where possible.  */
6282
      if (offset)
6283
        {
6284
          HOST_WIDE_INT low = trunc_int_for_mode (offset, HImode);
6285
 
6286
          emit_insn (gen_movsi_high (scratch, GEN_INT (low)));
6287
          if (low != offset)
6288
            emit_insn (gen_movsi_lo_sum (scratch, scratch, GEN_INT(offset)));
6289
          emit_insn (gen_addsi3 (scratch, addr, scratch));
6290
          addr = scratch;
6291
        }
6292
 
6293
      emit_move_insn (gen_frame_mem (Pmode, addr), source);
6294
    }
6295
}
6296
 
6297
/* We save pairs of registers using a DImode store.  Describe the component
6298
   registers for DWARF generation code.  */
6299
 
6300
static rtx
6301
c6x_dwarf_register_span (rtx rtl)
6302
{
6303
    unsigned regno;
6304
    unsigned real_regno;
6305
    int nregs;
6306
    int i;
6307
    rtx p;
6308
 
6309
    regno = REGNO (rtl);
6310
    nregs = HARD_REGNO_NREGS (regno, GET_MODE (rtl));
6311
    if (nregs == 1)
6312
      return  NULL_RTX;
6313
 
6314
    p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc(nregs));
6315
    for (i = 0; i < nregs; i++)
6316
      {
6317
        if (TARGET_BIG_ENDIAN)
6318
          real_regno = regno + nregs - (i + 1);
6319
        else
6320
          real_regno = regno + i;
6321
 
6322
        XVECEXP (p, 0, i) = gen_rtx_REG (SImode, real_regno);
6323
      }
6324
 
6325
    return p;
6326
}
6327
 
6328
/* Codes for all the C6X builtins.  */
6329
enum c6x_builtins
6330
{
6331
  C6X_BUILTIN_SADD,
6332
  C6X_BUILTIN_SSUB,
6333
  C6X_BUILTIN_ADD2,
6334
  C6X_BUILTIN_SUB2,
6335
  C6X_BUILTIN_ADD4,
6336
  C6X_BUILTIN_SUB4,
6337
  C6X_BUILTIN_SADD2,
6338
  C6X_BUILTIN_SSUB2,
6339
  C6X_BUILTIN_SADDU4,
6340
 
6341
  C6X_BUILTIN_SMPY,
6342
  C6X_BUILTIN_SMPYH,
6343
  C6X_BUILTIN_SMPYHL,
6344
  C6X_BUILTIN_SMPYLH,
6345
  C6X_BUILTIN_MPY2,
6346
  C6X_BUILTIN_SMPY2,
6347
 
6348
  C6X_BUILTIN_CLRR,
6349
  C6X_BUILTIN_EXTR,
6350
  C6X_BUILTIN_EXTRU,
6351
 
6352
  C6X_BUILTIN_SSHL,
6353
  C6X_BUILTIN_SUBC,
6354
  C6X_BUILTIN_ABS,
6355
  C6X_BUILTIN_ABS2,
6356
  C6X_BUILTIN_AVG2,
6357
  C6X_BUILTIN_AVGU4,
6358
 
6359
  C6X_BUILTIN_MAX
6360
};
6361
 
6362
 
6363
static GTY(()) tree c6x_builtin_decls[C6X_BUILTIN_MAX];
6364
 
6365
/* Return the C6X builtin for CODE.  */
6366
static tree
6367
c6x_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
6368
{
6369
  if (code >= C6X_BUILTIN_MAX)
6370
    return error_mark_node;
6371
 
6372
  return c6x_builtin_decls[code];
6373
}
6374
 
6375
#define def_builtin(NAME, TYPE, CODE)                                   \
6376
do {                                                                    \
6377
  tree bdecl;                                                           \
6378
  bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,    \
6379
                                NULL, NULL_TREE);                       \
6380
  c6x_builtin_decls[CODE] = bdecl;                                      \
6381
} while (0)
6382
 
6383
/* Set up all builtin functions for this target.  */
6384
static void
6385
c6x_init_builtins (void)
6386
{
6387
  tree V4QI_type_node = build_vector_type (unsigned_intQI_type_node, 4);
6388
  tree V2HI_type_node = build_vector_type (intHI_type_node, 2);
6389
  tree V2SI_type_node = build_vector_type (intSI_type_node, 2);
6390
  tree int_ftype_int
6391
    = build_function_type_list (integer_type_node, integer_type_node,
6392
                                NULL_TREE);
6393
  tree int_ftype_int_int
6394
    = build_function_type_list (integer_type_node, integer_type_node,
6395
                                integer_type_node, NULL_TREE);
6396
  tree v2hi_ftype_v2hi
6397
    = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
6398
  tree v4qi_ftype_v4qi_v4qi
6399
    = build_function_type_list (V4QI_type_node, V4QI_type_node,
6400
                                V4QI_type_node, NULL_TREE);
6401
  tree v2hi_ftype_v2hi_v2hi
6402
    = build_function_type_list (V2HI_type_node, V2HI_type_node,
6403
                                V2HI_type_node, NULL_TREE);
6404
  tree v2si_ftype_v2hi_v2hi
6405
    = build_function_type_list (V2SI_type_node, V2HI_type_node,
6406
                                V2HI_type_node, NULL_TREE);
6407
 
6408
  def_builtin ("__builtin_c6x_sadd", int_ftype_int_int,
6409
               C6X_BUILTIN_SADD);
6410
  def_builtin ("__builtin_c6x_ssub", int_ftype_int_int,
6411
               C6X_BUILTIN_SSUB);
6412
  def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi,
6413
               C6X_BUILTIN_ADD2);
6414
  def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi,
6415
               C6X_BUILTIN_SUB2);
6416
  def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi,
6417
               C6X_BUILTIN_ADD4);
6418
  def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi,
6419
               C6X_BUILTIN_SUB4);
6420
  def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi,
6421
               C6X_BUILTIN_MPY2);
6422
  def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi,
6423
               C6X_BUILTIN_SADD2);
6424
  def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi,
6425
               C6X_BUILTIN_SSUB2);
6426
  def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi,
6427
               C6X_BUILTIN_SADDU4);
6428
  def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi,
6429
               C6X_BUILTIN_SMPY2);
6430
 
6431
  def_builtin ("__builtin_c6x_smpy", int_ftype_int_int,
6432
               C6X_BUILTIN_SMPY);
6433
  def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int,
6434
               C6X_BUILTIN_SMPYH);
6435
  def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int,
6436
               C6X_BUILTIN_SMPYHL);
6437
  def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int,
6438
               C6X_BUILTIN_SMPYLH);
6439
 
6440
  def_builtin ("__builtin_c6x_sshl", int_ftype_int_int,
6441
               C6X_BUILTIN_SSHL);
6442
  def_builtin ("__builtin_c6x_subc", int_ftype_int_int,
6443
               C6X_BUILTIN_SUBC);
6444
 
6445
  def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi,
6446
               C6X_BUILTIN_AVG2);
6447
  def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi,
6448
               C6X_BUILTIN_AVGU4);
6449
 
6450
  def_builtin ("__builtin_c6x_clrr", int_ftype_int_int,
6451
               C6X_BUILTIN_CLRR);
6452
  def_builtin ("__builtin_c6x_extr", int_ftype_int_int,
6453
               C6X_BUILTIN_EXTR);
6454
  def_builtin ("__builtin_c6x_extru", int_ftype_int_int,
6455
               C6X_BUILTIN_EXTRU);
6456
 
6457
  def_builtin ("__builtin_c6x_abs", int_ftype_int, C6X_BUILTIN_ABS);
6458
  def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi, C6X_BUILTIN_ABS2);
6459
}
6460
 
6461
 
6462
struct builtin_description
6463
{
6464
  const enum insn_code icode;
6465
  const char *const name;
6466
  const enum c6x_builtins code;
6467
};
6468
 
6469
static const struct builtin_description bdesc_2arg[] =
6470
{
6471
  { CODE_FOR_saddsi3, "__builtin_c6x_sadd", C6X_BUILTIN_SADD },
6472
  { CODE_FOR_ssubsi3, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB },
6473
  { CODE_FOR_addv2hi3, "__builtin_c6x_add2", C6X_BUILTIN_ADD2 },
6474
  { CODE_FOR_subv2hi3, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2 },
6475
  { CODE_FOR_addv4qi3, "__builtin_c6x_add4", C6X_BUILTIN_ADD4 },
6476
  { CODE_FOR_subv4qi3, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4 },
6477
  { CODE_FOR_ss_addv2hi3, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2 },
6478
  { CODE_FOR_ss_subv2hi3, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2 },
6479
  { CODE_FOR_us_addv4qi3, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4 },
6480
 
6481
  { CODE_FOR_subcsi3, "__builtin_c6x_subc", C6X_BUILTIN_SUBC },
6482
  { CODE_FOR_ss_ashlsi3, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL },
6483
 
6484
  { CODE_FOR_avgv2hi3, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2 },
6485
  { CODE_FOR_uavgv4qi3, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4 },
6486
 
6487
  { CODE_FOR_mulhqsq3, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY },
6488
  { CODE_FOR_mulhqsq3_hh, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH },
6489
  { CODE_FOR_mulhqsq3_lh, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH },
6490
  { CODE_FOR_mulhqsq3_hl, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL },
6491
 
6492
  { CODE_FOR_mulv2hqv2sq3, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2 },
6493
 
6494
  { CODE_FOR_clrr, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR },
6495
  { CODE_FOR_extr, "__builtin_c6x_extr", C6X_BUILTIN_EXTR },
6496
  { CODE_FOR_extru, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU }
6497
};
6498
 
6499
static const struct builtin_description bdesc_1arg[] =
6500
{
6501
  { CODE_FOR_ssabssi2, "__builtin_c6x_abs", C6X_BUILTIN_ABS },
6502
  { CODE_FOR_ssabsv2hi2, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2 }
6503
};
6504
 
6505
/* Errors in the source file can cause expand_expr to return const0_rtx
6506
   where we expect a vector.  To avoid crashing, use one of the vector
6507
   clear instructions.  */
6508
static rtx
6509
safe_vector_operand (rtx x, enum machine_mode mode)
6510
{
6511
  if (x != const0_rtx)
6512
    return x;
6513
  x = gen_reg_rtx (SImode);
6514
 
6515
  emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
6516
  return gen_lowpart (mode, x);
6517
}
6518
 
6519
/* Subroutine of c6x_expand_builtin to take care of binop insns.  MACFLAG is -1
6520
   if this is a normal binary op, or one of the MACFLAG_xxx constants.  */
6521
 
6522
static rtx
6523
c6x_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
6524
                          bool match_op)
6525
{
6526
  int offs = match_op ? 1 : 0;
6527
  rtx pat;
6528
  tree arg0 = CALL_EXPR_ARG (exp, 0);
6529
  tree arg1 = CALL_EXPR_ARG (exp, 1);
6530
  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6531
  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6532
  enum machine_mode op0mode = GET_MODE (op0);
6533
  enum machine_mode op1mode = GET_MODE (op1);
6534
  enum machine_mode tmode = insn_data[icode].operand[0].mode;
6535
  enum machine_mode mode0 = insn_data[icode].operand[1 + offs].mode;
6536
  enum machine_mode mode1 = insn_data[icode].operand[2 + offs].mode;
6537
  rtx ret = target;
6538
 
6539
  if (VECTOR_MODE_P (mode0))
6540
    op0 = safe_vector_operand (op0, mode0);
6541
  if (VECTOR_MODE_P (mode1))
6542
    op1 = safe_vector_operand (op1, mode1);
6543
 
6544
  if (! target
6545
      || GET_MODE (target) != tmode
6546
      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6547
    {
6548
      if (tmode == SQmode || tmode == V2SQmode)
6549
        {
6550
          ret = gen_reg_rtx (tmode == SQmode ? SImode : V2SImode);
6551
          target = gen_lowpart (tmode, ret);
6552
        }
6553
      else
6554
        target = gen_reg_rtx (tmode);
6555
    }
6556
 
6557
  if ((op0mode == V2HImode || op0mode == SImode || op0mode == VOIDmode)
6558
      && (mode0 == V2HQmode || mode0 == HQmode || mode0 == SQmode))
6559
    {
6560
      op0mode = mode0;
6561
      op0 = gen_lowpart (mode0, op0);
6562
    }
6563
  if ((op1mode == V2HImode || op1mode == SImode || op1mode == VOIDmode)
6564
      && (mode1 == V2HQmode || mode1 == HQmode || mode1 == SQmode))
6565
    {
6566
      op1mode = mode1;
6567
      op1 = gen_lowpart (mode1, op1);
6568
    }
6569
  /* In case the insn wants input operands in modes different from
6570
     the result, abort.  */
6571
  gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
6572
              && (op1mode == mode1 || op1mode == VOIDmode));
6573
 
6574
  if (! (*insn_data[icode].operand[1 + offs].predicate) (op0, mode0))
6575
    op0 = copy_to_mode_reg (mode0, op0);
6576
  if (! (*insn_data[icode].operand[2 + offs].predicate) (op1, mode1))
6577
    op1 = copy_to_mode_reg (mode1, op1);
6578
 
6579
  if (match_op)
6580
    pat = GEN_FCN (icode) (target, target, op0, op1);
6581
  else
6582
    pat = GEN_FCN (icode) (target, op0, op1);
6583
 
6584
  if (! pat)
6585
    return 0;
6586
 
6587
  emit_insn (pat);
6588
 
6589
  return ret;
6590
}
6591
 
6592
/* Subroutine of c6x_expand_builtin to take care of unop insns.  */
6593
 
6594
static rtx
6595
c6x_expand_unop_builtin (enum insn_code icode, tree exp,
6596
                          rtx target)
6597
{
6598
  rtx pat;
6599
  tree arg0 = CALL_EXPR_ARG (exp, 0);
6600
  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6601
  enum machine_mode op0mode = GET_MODE (op0);
6602
  enum machine_mode tmode = insn_data[icode].operand[0].mode;
6603
  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6604
 
6605
  if (! target
6606
      || GET_MODE (target) != tmode
6607
      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6608
    target = gen_reg_rtx (tmode);
6609
 
6610
  if (VECTOR_MODE_P (mode0))
6611
    op0 = safe_vector_operand (op0, mode0);
6612
 
6613
  if (op0mode == SImode && mode0 == HImode)
6614
    {
6615
      op0mode = HImode;
6616
      op0 = gen_lowpart (HImode, op0);
6617
    }
6618
  gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
6619
 
6620
  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6621
    op0 = copy_to_mode_reg (mode0, op0);
6622
 
6623
  pat = GEN_FCN (icode) (target, op0);
6624
  if (! pat)
6625
    return 0;
6626
  emit_insn (pat);
6627
  return target;
6628
}
6629
 
6630
/* Expand an expression EXP that calls a built-in function,
6631
   with result going to TARGET if that's convenient
6632
   (and in mode MODE if that's convenient).
6633
   SUBTARGET may be used as the target for computing one of EXP's operands.
6634
   IGNORE is nonzero if the value is to be ignored.  */
6635
 
6636
static rtx
6637
c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6638
                     rtx subtarget ATTRIBUTE_UNUSED,
6639
                     enum machine_mode mode ATTRIBUTE_UNUSED,
6640
                     int ignore ATTRIBUTE_UNUSED)
6641
{
6642
  size_t i;
6643
  const struct builtin_description *d;
6644
  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6645
  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6646
 
6647
  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6648
    if (d->code == fcode)
6649
      return c6x_expand_binop_builtin (d->icode, exp, target,
6650
                                       fcode == C6X_BUILTIN_CLRR);
6651
 
6652
  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6653
    if (d->code == fcode)
6654
      return c6x_expand_unop_builtin (d->icode, exp, target);
6655
 
6656
  gcc_unreachable ();
6657
}
6658
 
6659
/* Target unwind frame info is generated from dwarf CFI directives, so
6660
   always output dwarf2 unwind info.  */
6661
 
6662
static enum unwind_info_type
6663
c6x_debug_unwind_info (void)
6664
{
6665
  if (flag_unwind_tables || flag_exceptions)
6666
    return UI_DWARF2;
6667
 
6668
  return default_debug_unwind_info ();
6669
}
6670
 
6671
/* Target Structure.  */
6672
 
6673
/* Initialize the GCC target structure.  */
6674
#undef TARGET_FUNCTION_ARG
6675
#define TARGET_FUNCTION_ARG c6x_function_arg
6676
#undef TARGET_FUNCTION_ARG_ADVANCE
6677
#define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6678
#undef TARGET_FUNCTION_ARG_BOUNDARY
6679
#define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6680
#undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6681
#define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6682
  c6x_function_arg_round_boundary
6683
#undef TARGET_FUNCTION_VALUE_REGNO_P
6684
#define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6685
#undef TARGET_FUNCTION_VALUE
6686
#define TARGET_FUNCTION_VALUE c6x_function_value
6687
#undef TARGET_LIBCALL_VALUE
6688
#define TARGET_LIBCALL_VALUE c6x_libcall_value
6689
#undef TARGET_RETURN_IN_MEMORY
6690
#define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6691
#undef TARGET_RETURN_IN_MSB
6692
#define TARGET_RETURN_IN_MSB c6x_return_in_msb
6693
#undef TARGET_PASS_BY_REFERENCE
6694
#define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6695
#undef TARGET_CALLEE_COPIES
6696
#define TARGET_CALLEE_COPIES c6x_callee_copies
6697
#undef TARGET_STRUCT_VALUE_RTX
6698
#define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6699
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
6700
#define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6701
 
6702
#undef TARGET_ASM_OUTPUT_MI_THUNK
6703
#define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6704
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6705
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6706
 
6707
#undef TARGET_BUILD_BUILTIN_VA_LIST
6708
#define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6709
 
6710
#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6711
#define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6712
#undef TARGET_TRAMPOLINE_INIT
6713
#define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6714
 
6715
#undef TARGET_LEGITIMATE_CONSTANT_P
6716
#define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6717
#undef TARGET_LEGITIMATE_ADDRESS_P
6718
#define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6719
 
6720
#undef TARGET_IN_SMALL_DATA_P
6721
#define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6722
#undef  TARGET_ASM_SELECT_RTX_SECTION
6723
#define TARGET_ASM_SELECT_RTX_SECTION  c6x_select_rtx_section
6724
#undef TARGET_ASM_SELECT_SECTION
6725
#define TARGET_ASM_SELECT_SECTION  c6x_elf_select_section
6726
#undef TARGET_ASM_UNIQUE_SECTION
6727
#define TARGET_ASM_UNIQUE_SECTION  c6x_elf_unique_section
6728
#undef TARGET_SECTION_TYPE_FLAGS
6729
#define TARGET_SECTION_TYPE_FLAGS  c6x_section_type_flags
6730
#undef TARGET_HAVE_SRODATA_SECTION
6731
#define TARGET_HAVE_SRODATA_SECTION true
6732
#undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6733
#define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6734
 
6735
#undef TARGET_OPTION_OVERRIDE
6736
#define TARGET_OPTION_OVERRIDE c6x_option_override
6737
#undef TARGET_CONDITIONAL_REGISTER_USAGE
6738
#define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6739
 
6740
#undef TARGET_INIT_LIBFUNCS
6741
#define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6742
#undef TARGET_LIBFUNC_GNU_PREFIX
6743
#define TARGET_LIBFUNC_GNU_PREFIX true
6744
 
6745
#undef TARGET_SCALAR_MODE_SUPPORTED_P
6746
#define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6747
#undef TARGET_VECTOR_MODE_SUPPORTED_P
6748
#define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6749
#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6750
#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6751
 
6752
#undef TARGET_RTX_COSTS
6753
#define TARGET_RTX_COSTS c6x_rtx_costs
6754
 
6755
#undef TARGET_SCHED_INIT
6756
#define TARGET_SCHED_INIT c6x_sched_init
6757
#undef TARGET_SCHED_SET_SCHED_FLAGS
6758
#define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6759
#undef TARGET_SCHED_ADJUST_COST
6760
#define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6761
#undef TARGET_SCHED_ISSUE_RATE
6762
#define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6763
#undef TARGET_SCHED_VARIABLE_ISSUE
6764
#define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6765
#undef TARGET_SCHED_REORDER
6766
#define TARGET_SCHED_REORDER c6x_sched_reorder
6767
#undef TARGET_SCHED_REORDER2
6768
#define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6769
#undef TARGET_SCHED_DFA_NEW_CYCLE
6770
#define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6771
#undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6772
#define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
6773
#undef TARGET_SCHED_EXPOSED_PIPELINE
6774
#define TARGET_SCHED_EXPOSED_PIPELINE true
6775
 
6776
#undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6777
#define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6778
#undef TARGET_SCHED_INIT_SCHED_CONTEXT
6779
#define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6780
#undef TARGET_SCHED_SET_SCHED_CONTEXT
6781
#define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6782
#undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6783
#define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
6784
#undef TARGET_SCHED_FREE_SCHED_CONTEXT
6785
#define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6786
 
6787
#undef TARGET_CAN_ELIMINATE
6788
#define TARGET_CAN_ELIMINATE c6x_can_eliminate
6789
 
6790
#undef TARGET_PREFERRED_RENAME_CLASS
6791
#define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6792
 
6793
#undef TARGET_MACHINE_DEPENDENT_REORG
6794
#define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6795
 
6796
#undef TARGET_ASM_FILE_START
6797
#define TARGET_ASM_FILE_START c6x_file_start
6798
 
6799
#undef  TARGET_PRINT_OPERAND
6800
#define TARGET_PRINT_OPERAND c6x_print_operand
6801
#undef  TARGET_PRINT_OPERAND_ADDRESS
6802
#define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6803
#undef  TARGET_PRINT_OPERAND_PUNCT_VALID_P
6804
#define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6805
 
6806
/* C6x unwinding tables use a different format for the typeinfo tables.  */
6807
#undef TARGET_ASM_TTYPE
6808
#define TARGET_ASM_TTYPE c6x_output_ttype
6809
 
6810
/* The C6x ABI follows the ARM EABI exception handling rules.  */
6811
#undef TARGET_ARM_EABI_UNWINDER
6812
#define TARGET_ARM_EABI_UNWINDER true
6813
 
6814
#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6815
#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6816
 
6817
#undef TARGET_ASM_INIT_SECTIONS
6818
#define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6819
 
6820
#undef TARGET_DEBUG_UNWIND_INFO
6821
#define TARGET_DEBUG_UNWIND_INFO  c6x_debug_unwind_info
6822
 
6823
#undef TARGET_DWARF_REGISTER_SPAN
6824
#define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6825
 
6826
#undef TARGET_INIT_BUILTINS
6827
#define TARGET_INIT_BUILTINS c6x_init_builtins
6828
#undef TARGET_EXPAND_BUILTIN
6829
#define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6830
#undef  TARGET_BUILTIN_DECL
6831
#define TARGET_BUILTIN_DECL c6x_builtin_decl
6832
 
6833
struct gcc_target targetm = TARGET_INITIALIZER;
6834
 
6835
#include "gt-c6x.h"

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.