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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 709 jeremybenn
/* Output routines for Sunplus S+CORE processor
2
   Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
3
   Free Software Foundation, Inc.
4
   Contributed by Sunnorth.
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 "regs.h"
28
#include "hard-reg-set.h"
29
#include "insn-config.h"
30
#include "conditions.h"
31
#include "insn-attr.h"
32
#include "recog.h"
33
#include "diagnostic-core.h"
34
#include "output.h"
35
#include "tree.h"
36
#include "function.h"
37
#include "expr.h"
38
#include "optabs.h"
39
#include "flags.h"
40
#include "reload.h"
41
#include "tm_p.h"
42
#include "ggc.h"
43
#include "gstab.h"
44
#include "hashtab.h"
45
#include "debug.h"
46
#include "target.h"
47
#include "target-def.h"
48
#include "integrate.h"
49
#include "langhooks.h"
50
#include "cfglayout.h"
51
#include "df.h"
52
#include "opts.h"
53
 
54
#define SCORE_SDATA_MAX                score_sdata_max
55
#define SCORE_STACK_ALIGN(LOC)         (((LOC) + 3) & ~3)
56
#define SCORE_PROLOGUE_TEMP_REGNUM     (GP_REG_FIRST + 8)
57
#define SCORE_EPILOGUE_TEMP_REGNUM     (GP_REG_FIRST + 8)
58
#define SCORE_DEFAULT_SDATA_MAX        8
59
 
60
#define BITSET_P(VALUE, BIT)           (((VALUE) & (1L << (BIT))) != 0)
61
#define INS_BUF_SZ                     128
62
 
63
enum score_address_type
64
{
65
  SCORE_ADD_REG,
66
  SCORE_ADD_CONST_INT,
67
  SCORE_ADD_SYMBOLIC
68
};
69
 
70
struct score_frame_info
71
{
72
  HOST_WIDE_INT total_size;       /* bytes that the entire frame takes up  */
73
  HOST_WIDE_INT var_size;         /* bytes that variables take up  */
74
  HOST_WIDE_INT args_size;        /* bytes that outgoing arguments take up  */
75
  HOST_WIDE_INT gp_reg_size;      /* bytes needed to store gp regs  */
76
  HOST_WIDE_INT gp_sp_offset;     /* offset from new sp to store gp registers  */
77
  HOST_WIDE_INT cprestore_size;   /* # bytes that the .cprestore slot takes up  */
78
  unsigned int  mask;             /* mask of saved gp registers  */
79
  int num_gp;                     /* number of gp registers saved  */
80
};
81
 
82
struct score_arg_info
83
{
84
  unsigned int num_bytes;     /* The argument's size in bytes  */
85
  unsigned int reg_words;     /* The number of words passed in registers  */
86
  unsigned int reg_offset;    /* The offset of the first register from  */
87
                              /* GP_ARG_FIRST or FP_ARG_FIRST etc  */
88
  unsigned int stack_words;   /* The number of words that must be passed  */
89
                              /* on the stack  */
90
  unsigned int stack_offset;  /* The offset from the start of the stack  */
91
                              /* overflow area  */
92
};
93
 
94
#ifdef RTX_CODE
95
struct score_address_info
96
{
97
  enum score_address_type type;
98
  rtx reg;
99
  rtx offset;
100
  enum rtx_code code;
101
  enum score_symbol_type symbol_type;
102
};
103
#endif
104
 
105
static int score_sdata_max;
106
static char score_ins[INS_BUF_SZ + 8];
107
 
108
struct extern_list *extern_head = 0;
109
 
110
#undef  TARGET_ASM_FILE_START
111
#define TARGET_ASM_FILE_START           score_asm_file_start
112
 
113
#undef  TARGET_ASM_FILE_END
114
#define TARGET_ASM_FILE_END             score_asm_file_end
115
 
116
#undef  TARGET_ASM_FUNCTION_PROLOGUE
117
#define TARGET_ASM_FUNCTION_PROLOGUE    score_function_prologue
118
 
119
#undef  TARGET_ASM_FUNCTION_EPILOGUE
120
#define TARGET_ASM_FUNCTION_EPILOGUE    score_function_epilogue
121
 
122
#undef TARGET_OPTION_OVERRIDE
123
#define TARGET_OPTION_OVERRIDE          score_option_override
124
 
125
#undef TARGET_LEGITIMIZE_ADDRESS
126
#define TARGET_LEGITIMIZE_ADDRESS       score_legitimize_address
127
 
128
#undef  TARGET_SCHED_ISSUE_RATE
129
#define TARGET_SCHED_ISSUE_RATE         score_issue_rate
130
 
131
#undef TARGET_ASM_SELECT_RTX_SECTION
132
#define TARGET_ASM_SELECT_RTX_SECTION   score_select_rtx_section
133
 
134
#undef  TARGET_IN_SMALL_DATA_P
135
#define TARGET_IN_SMALL_DATA_P          score_in_small_data_p
136
 
137
#undef  TARGET_FUNCTION_OK_FOR_SIBCALL
138
#define TARGET_FUNCTION_OK_FOR_SIBCALL  score_function_ok_for_sibcall
139
 
140
#undef TARGET_STRICT_ARGUMENT_NAMING
141
#define TARGET_STRICT_ARGUMENT_NAMING   hook_bool_CUMULATIVE_ARGS_true
142
 
143
#undef TARGET_ASM_OUTPUT_MI_THUNK
144
#define TARGET_ASM_OUTPUT_MI_THUNK      score_output_mi_thunk
145
 
146
#undef TARGET_PROMOTE_FUNCTION_MODE
147
#define TARGET_PROMOTE_FUNCTION_MODE    default_promote_function_mode_always_promote
148
 
149
#undef TARGET_PROMOTE_PROTOTYPES
150
#define TARGET_PROMOTE_PROTOTYPES       hook_bool_const_tree_true
151
 
152
#undef TARGET_MUST_PASS_IN_STACK
153
#define TARGET_MUST_PASS_IN_STACK       must_pass_in_stack_var_size
154
 
155
#undef TARGET_ARG_PARTIAL_BYTES
156
#define TARGET_ARG_PARTIAL_BYTES        score_arg_partial_bytes
157
 
158
#undef TARGET_FUNCTION_ARG
159
#define TARGET_FUNCTION_ARG             score_function_arg
160
 
161
#undef TARGET_FUNCTION_ARG_ADVANCE
162
#define TARGET_FUNCTION_ARG_ADVANCE     score_function_arg_advance
163
 
164
#undef TARGET_PASS_BY_REFERENCE
165
#define TARGET_PASS_BY_REFERENCE        score_pass_by_reference
166
 
167
#undef TARGET_RETURN_IN_MEMORY
168
#define TARGET_RETURN_IN_MEMORY         score_return_in_memory
169
 
170
#undef TARGET_RTX_COSTS
171
#define TARGET_RTX_COSTS                score_rtx_costs
172
 
173
#undef TARGET_ADDRESS_COST
174
#define TARGET_ADDRESS_COST             score_address_cost
175
 
176
#undef TARGET_LEGITIMATE_ADDRESS_P
177
#define TARGET_LEGITIMATE_ADDRESS_P     score_legitimate_address_p
178
 
179
#undef TARGET_CAN_ELIMINATE
180
#define TARGET_CAN_ELIMINATE            score_can_eliminate
181
 
182
#undef TARGET_CONDITIONAL_REGISTER_USAGE
183
#define TARGET_CONDITIONAL_REGISTER_USAGE score_conditional_register_usage
184
 
185
#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
186
#define TARGET_ASM_TRAMPOLINE_TEMPLATE  score_asm_trampoline_template
187
#undef TARGET_TRAMPOLINE_INIT
188
#define TARGET_TRAMPOLINE_INIT          score_trampoline_init
189
 
190
#undef TARGET_REGISTER_MOVE_COST
191
#define TARGET_REGISTER_MOVE_COST       score_register_move_cost
192
 
193
/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
194
   to the same object as SYMBOL.  */
195
static int
196
score_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
197
{
198
  if (GET_CODE (symbol) != SYMBOL_REF)
199
    return 0;
200
 
201
  if (CONSTANT_POOL_ADDRESS_P (symbol)
202
      && offset >= 0
203
      && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
204
    return 1;
205
 
206
  if (SYMBOL_REF_DECL (symbol) != 0
207
      && offset >= 0
208
      && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
209
    return 1;
210
 
211
  return 0;
212
}
213
 
214
/* Split X into a base and a constant offset, storing them in *BASE
215
   and *OFFSET respectively.  */
216
static void
217
score_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
218
{
219
  *offset = 0;
220
 
221
  if (GET_CODE (x) == CONST)
222
    x = XEXP (x, 0);
223
 
224
  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
225
    {
226
      *offset += INTVAL (XEXP (x, 1));
227
      x = XEXP (x, 0);
228
    }
229
 
230
  *base = x;
231
}
232
 
233
/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */
234
static enum score_symbol_type
235
score_classify_symbol (rtx x)
236
{
237
  if (GET_CODE (x) == LABEL_REF)
238
    return SYMBOL_GENERAL;
239
 
240
  gcc_assert (GET_CODE (x) == SYMBOL_REF);
241
 
242
  if (CONSTANT_POOL_ADDRESS_P (x))
243
    {
244
      if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
245
        return SYMBOL_SMALL_DATA;
246
      return SYMBOL_GENERAL;
247
    }
248
  if (SYMBOL_REF_SMALL_P (x))
249
    return SYMBOL_SMALL_DATA;
250
  return SYMBOL_GENERAL;
251
}
252
 
253
/* Return true if the current function must save REGNO.  */
254
static int
255
score_save_reg_p (unsigned int regno)
256
{
257
  /* Check call-saved registers.  */
258
  if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
259
    return 1;
260
 
261
  /* We need to save the old frame pointer before setting up a new one.  */
262
  if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
263
    return 1;
264
 
265
  /* We need to save the incoming return address if it is ever clobbered
266
     within the function.  */
267
  if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
268
    return 1;
269
 
270
  return 0;
271
}
272
 
273
/* Return one word of double-word value OP, taking into account the fixed
274
   endianness of certain registers.  HIGH_P is true to select the high part,
275
   false to select the low part.  */
276
static rtx
277
score_subw (rtx op, int high_p)
278
{
279
  unsigned int byte;
280
  enum machine_mode mode = GET_MODE (op);
281
 
282
  if (mode == VOIDmode)
283
    mode = DImode;
284
 
285
  byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
286
 
287
  if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
288
    return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
289
 
290
  if (GET_CODE (op) == MEM)
291
    return adjust_address (op, SImode, byte);
292
 
293
  return simplify_gen_subreg (SImode, op, mode, byte);
294
}
295
 
296
static struct score_frame_info *
297
score_cached_frame (void)
298
{
299
  static struct score_frame_info _frame_info;
300
  return &_frame_info;
301
}
302
 
303
/* Return the bytes needed to compute the frame pointer from the current
304
   stack pointer.  SIZE is the size (in bytes) of the local variables.  */
305
static struct score_frame_info *
306
score_compute_frame_size (HOST_WIDE_INT size)
307
{
308
  unsigned int regno;
309
  struct score_frame_info *f = score_cached_frame ();
310
 
311
  memset (f, 0, sizeof (struct score_frame_info));
312
  f->gp_reg_size = 0;
313
  f->mask = 0;
314
  f->var_size = SCORE_STACK_ALIGN (size);
315
  f->args_size = crtl->outgoing_args_size;
316
  f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
317
  if (f->var_size == 0 && current_function_is_leaf)
318
    f->args_size = f->cprestore_size = 0;
319
 
320
  if (f->args_size == 0 && cfun->calls_alloca)
321
    f->args_size = UNITS_PER_WORD;
322
 
323
  f->total_size = f->var_size + f->args_size + f->cprestore_size;
324
  for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
325
    {
326
      if (score_save_reg_p (regno))
327
        {
328
          f->gp_reg_size += GET_MODE_SIZE (SImode);
329
          f->mask |= 1 << (regno - GP_REG_FIRST);
330
        }
331
    }
332
 
333
  if (crtl->calls_eh_return)
334
    {
335
      unsigned int i;
336
      for (i = 0;; ++i)
337
        {
338
          regno = EH_RETURN_DATA_REGNO (i);
339
          if (regno == INVALID_REGNUM)
340
            break;
341
          f->gp_reg_size += GET_MODE_SIZE (SImode);
342
          f->mask |= 1 << (regno - GP_REG_FIRST);
343
        }
344
    }
345
 
346
  f->total_size += f->gp_reg_size;
347
  f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
348
 
349
  if (f->mask)
350
    {
351
      HOST_WIDE_INT offset;
352
      offset = (f->args_size + f->cprestore_size + f->var_size
353
                + f->gp_reg_size - GET_MODE_SIZE (SImode));
354
      f->gp_sp_offset = offset;
355
    }
356
  else
357
    f->gp_sp_offset = 0;
358
 
359
  return f;
360
}
361
 
362
/* Return true if X is a valid base register for the given mode.
363
   Allow only hard registers if STRICT.  */
364
static int
365
score_valid_base_register_p (rtx x, int strict)
366
{
367
  if (!strict && GET_CODE (x) == SUBREG)
368
    x = SUBREG_REG (x);
369
 
370
  return (GET_CODE (x) == REG
371
          && score_regno_mode_ok_for_base_p (REGNO (x), strict));
372
}
373
 
374
/* Return true if X is a valid address for machine mode MODE.  If it is,
375
   fill in INFO appropriately.  STRICT is true if we should only accept
376
   hard base registers.  */
377
static int
378
score_classify_address (struct score_address_info *info,
379
                        enum machine_mode mode, rtx x, int strict)
380
{
381
  info->code = GET_CODE (x);
382
 
383
  switch (info->code)
384
    {
385
    case REG:
386
    case SUBREG:
387
      info->type = SCORE_ADD_REG;
388
      info->reg = x;
389
      info->offset = const0_rtx;
390
      return score_valid_base_register_p (info->reg, strict);
391
    case PLUS:
392
      info->type = SCORE_ADD_REG;
393
      info->reg = XEXP (x, 0);
394
      info->offset = XEXP (x, 1);
395
      return (score_valid_base_register_p (info->reg, strict)
396
              && GET_CODE (info->offset) == CONST_INT
397
              && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
398
    case PRE_DEC:
399
    case POST_DEC:
400
    case PRE_INC:
401
    case POST_INC:
402
      if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
403
        return false;
404
      info->type = SCORE_ADD_REG;
405
      info->reg = XEXP (x, 0);
406
      info->offset = GEN_INT (GET_MODE_SIZE (mode));
407
      return score_valid_base_register_p (info->reg, strict);
408
    case CONST_INT:
409
      info->type = SCORE_ADD_CONST_INT;
410
      return IMM_IN_RANGE (INTVAL (x), 15, 1);
411
    case CONST:
412
    case LABEL_REF:
413
    case SYMBOL_REF:
414
      info->type = SCORE_ADD_SYMBOLIC;
415
      return (score_symbolic_constant_p (x, &info->symbol_type)
416
              && (info->symbol_type == SYMBOL_GENERAL
417
                  || info->symbol_type == SYMBOL_SMALL_DATA));
418
    default:
419
      return 0;
420
    }
421
}
422
 
423
/* Implement TARGET_RETURN_IN_MEMORY.  In S+core,
424
   small structures are returned in a register.
425
   Objects with varying size must still be returned in memory.  */
426
static bool
427
score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
428
{
429
    return ((TYPE_MODE (type) == BLKmode)
430
            || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
431
            || (int_size_in_bytes (type) == -1));
432
}
433
 
434
/* Return a legitimate address for REG + OFFSET.  */
435
static rtx
436
score_add_offset (rtx reg, HOST_WIDE_INT offset)
437
{
438
  if (!IMM_IN_RANGE (offset, 15, 1))
439
    {
440
      reg = expand_simple_binop (GET_MODE (reg), PLUS,
441
                                 gen_int_mode (offset & 0xffffc000,
442
                                               GET_MODE (reg)),
443
                                 reg, NULL, 0, OPTAB_WIDEN);
444
      offset &= 0x3fff;
445
    }
446
 
447
  return plus_constant (reg, offset);
448
}
449
 
450
/* Implement TARGET_ASM_OUTPUT_MI_THUNK.  Generate rtl rather than asm text
451
   in order to avoid duplicating too much logic from elsewhere.  */
452
static void
453
score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
454
                       HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
455
                       tree function)
456
{
457
  rtx this_rtx, temp1, insn, fnaddr;
458
 
459
  /* Pretend to be a post-reload pass while generating rtl.  */
460
  reload_completed = 1;
461
 
462
  /* Mark the end of the (empty) prologue.  */
463
  emit_note (NOTE_INSN_PROLOGUE_END);
464
 
465
  /* We need two temporary registers in some cases.  */
466
  temp1 = gen_rtx_REG (Pmode, 8);
467
 
468
  /* Find out which register contains the "this" pointer.  */
469
  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
470
    this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
471
  else
472
    this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
473
 
474
  /* Add DELTA to THIS_RTX.  */
475
  if (delta != 0)
476
    {
477
      rtx offset = GEN_INT (delta);
478
      if (!(delta >= -32768 && delta <= 32767))
479
        {
480
          emit_move_insn (temp1, offset);
481
          offset = temp1;
482
        }
483
      emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
484
    }
485
 
486
  /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX.  */
487
  if (vcall_offset != 0)
488
    {
489
      rtx addr;
490
 
491
      /* Set TEMP1 to *THIS_RTX.  */
492
      emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
493
 
494
      /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET.  */
495
      addr = score_add_offset (temp1, vcall_offset);
496
 
497
      /* Load the offset and add it to THIS_RTX.  */
498
      emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
499
      emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
500
    }
501
 
502
  /* Jump to the target function.  */
503
  fnaddr = XEXP (DECL_RTL (function), 0);
504
  insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx));
505
  SIBLING_CALL_P (insn) = 1;
506
 
507
  /* Run just enough of rest_of_compilation.  This sequence was
508
     "borrowed" from alpha.c.  */
509
  insn = get_insns ();
510
  insn_locators_alloc ();
511
  split_all_insns_noflow ();
512
  shorten_branches (insn);
513
  final_start_function (insn, file, 1);
514
  final (insn, file, 1);
515
  final_end_function ();
516
 
517
  /* Clean up the vars set above.  Note that final_end_function resets
518
     the global pointer for us.  */
519
  reload_completed = 0;
520
}
521
 
522
/* Copy VALUE to a register and return that register.  If new psuedos
523
   are allowed, copy it into a new register, otherwise use DEST.  */
524
static rtx
525
score_force_temporary (rtx dest, rtx value)
526
{
527
  if (can_create_pseudo_p ())
528
    return force_reg (Pmode, value);
529
  else
530
    {
531
      emit_move_insn (copy_rtx (dest), value);
532
      return dest;
533
    }
534
}
535
 
536
/* Return a LO_SUM expression for ADDR.  TEMP is as for score_force_temporary
537
   and is used to load the high part into a register.  */
538
static rtx
539
score_split_symbol (rtx temp, rtx addr)
540
{
541
  rtx high = score_force_temporary (temp,
542
                                     gen_rtx_HIGH (Pmode, copy_rtx (addr)));
543
  return gen_rtx_LO_SUM (Pmode, high, addr);
544
}
545
 
546
/* This function is used to implement LEGITIMIZE_ADDRESS.  If X can
547
   be legitimized in a way that the generic machinery might not expect,
548
   return the new address.  */
549
static rtx
550
score_legitimize_address (rtx x)
551
{
552
  enum score_symbol_type symbol_type;
553
 
554
  if (score_symbolic_constant_p (x, &symbol_type)
555
      && symbol_type == SYMBOL_GENERAL)
556
    return score_split_symbol (0, x);
557
 
558
  if (GET_CODE (x) == PLUS
559
      && GET_CODE (XEXP (x, 1)) == CONST_INT)
560
    {
561
      rtx reg = XEXP (x, 0);
562
      if (!score_valid_base_register_p (reg, 0))
563
        reg = copy_to_mode_reg (Pmode, reg);
564
      return score_add_offset (reg, INTVAL (XEXP (x, 1)));
565
    }
566
 
567
  return x;
568
}
569
 
570
/* Fill INFO with information about a single argument.  CUM is the
571
   cumulative state for earlier arguments.  MODE is the mode of this
572
   argument and TYPE is its type (if known).  NAMED is true if this
573
   is a named (fixed) argument rather than a variable one.  */
574
static void
575
score_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
576
                    const_tree type, bool named, struct score_arg_info *info)
577
{
578
  int even_reg_p;
579
  unsigned int num_words, max_regs;
580
 
581
  even_reg_p = 0;
582
  if (GET_MODE_CLASS (mode) == MODE_INT
583
      || GET_MODE_CLASS (mode) == MODE_FLOAT)
584
    even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
585
  else
586
    if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
587
      even_reg_p = 1;
588
 
589
  if (TARGET_MUST_PASS_IN_STACK (mode, type))
590
    info->reg_offset = ARG_REG_NUM;
591
  else
592
    {
593
      info->reg_offset = cum->num_gprs;
594
      if (even_reg_p)
595
        info->reg_offset += info->reg_offset & 1;
596
    }
597
 
598
  if (mode == BLKmode)
599
    info->num_bytes = int_size_in_bytes (type);
600
  else
601
    info->num_bytes = GET_MODE_SIZE (mode);
602
 
603
  num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
604
  max_regs = ARG_REG_NUM - info->reg_offset;
605
 
606
  /* Partition the argument between registers and stack.  */
607
  info->reg_words = MIN (num_words, max_regs);
608
  info->stack_words = num_words - info->reg_words;
609
 
610
  /* The alignment applied to registers is also applied to stack arguments.  */
611
  if (info->stack_words)
612
    {
613
      info->stack_offset = cum->stack_words;
614
      if (even_reg_p)
615
        info->stack_offset += info->stack_offset & 1;
616
    }
617
}
618
 
619
/* Set up the stack and frame (if desired) for the function.  */
620
static void
621
score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
622
{
623
  const char *fnname;
624
  struct score_frame_info *f = score_cached_frame ();
625
  HOST_WIDE_INT tsize = f->total_size;
626
 
627
  fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
628
  if (!flag_inhibit_size_directive)
629
    {
630
      fputs ("\t.ent\t", file);
631
      assemble_name (file, fnname);
632
      fputs ("\n", file);
633
    }
634
  assemble_name (file, fnname);
635
  fputs (":\n", file);
636
 
637
  if (!flag_inhibit_size_directive)
638
    {
639
      fprintf (file,
640
               "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
641
               "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
642
               ", args= " HOST_WIDE_INT_PRINT_DEC
643
               ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
644
               (reg_names[(frame_pointer_needed)
645
                ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
646
               tsize,
647
               reg_names[RA_REGNUM],
648
               current_function_is_leaf ? 1 : 0,
649
               f->var_size,
650
               f->num_gp,
651
               f->args_size,
652
               f->cprestore_size);
653
 
654
      fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
655
              f->mask,
656
              (f->gp_sp_offset - f->total_size));
657
    }
658
}
659
 
660
/* Do any necessary cleanup after a function to restore stack, frame,
661
   and regs.  */
662
static void
663
score_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
664
{
665
  if (!flag_inhibit_size_directive)
666
    {
667
      const char *fnname;
668
      fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
669
      fputs ("\t.end\t", file);
670
      assemble_name (file, fnname);
671
      fputs ("\n", file);
672
    }
673
}
674
 
675
/* Returns true if X contains a SYMBOL_REF.  */
676
static bool
677
score_symbolic_expression_p (rtx x)
678
{
679
  if (GET_CODE (x) == SYMBOL_REF)
680
    return true;
681
 
682
  if (GET_CODE (x) == CONST)
683
    return score_symbolic_expression_p (XEXP (x, 0));
684
 
685
  if (UNARY_P (x))
686
    return score_symbolic_expression_p (XEXP (x, 0));
687
 
688
  if (ARITHMETIC_P (x))
689
    return (score_symbolic_expression_p (XEXP (x, 0))
690
            || score_symbolic_expression_p (XEXP (x, 1)));
691
 
692
  return false;
693
}
694
 
695
/* Choose the section to use for the constant rtx expression X that has
696
   mode MODE.  */
697
static section *
698
score_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align)
699
{
700
  if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
701
    return get_named_section (0, ".sdata", 0);
702
  else if (flag_pic && score_symbolic_expression_p (x))
703
    return get_named_section (0, ".data.rel.ro", 3);
704
  else
705
    return mergeable_constant_section (mode, align, 0);
706
}
707
 
708
/* Implement TARGET_IN_SMALL_DATA_P.  */
709
static bool
710
score_in_small_data_p (const_tree decl)
711
{
712
  HOST_WIDE_INT size;
713
 
714
  if (TREE_CODE (decl) == STRING_CST
715
      || TREE_CODE (decl) == FUNCTION_DECL)
716
    return false;
717
 
718
  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
719
    {
720
      const char *name;
721
      name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
722
      if (strcmp (name, ".sdata") != 0
723
          && strcmp (name, ".sbss") != 0)
724
        return true;
725
      if (!DECL_EXTERNAL (decl))
726
        return false;
727
    }
728
  size = int_size_in_bytes (TREE_TYPE (decl));
729
  return (size > 0 && size <= SCORE_SDATA_MAX);
730
}
731
 
732
/* Implement TARGET_ASM_FILE_START.  */
733
static void
734
score_asm_file_start (void)
735
{
736
  default_file_start ();
737
  fprintf (asm_out_file, ASM_COMMENT_START
738
           "GCC for S+core %s \n", SCORE_GCC_VERSION);
739
 
740
  if (flag_pic)
741
    fprintf (asm_out_file, "\t.set pic\n");
742
}
743
 
744
/* Implement TARGET_ASM_FILE_END.  When using assembler macros, emit
745
   .externs for any small-data variables that turned out to be external.  */
746
static void
747
score_asm_file_end (void)
748
{
749
  tree name_tree;
750
  struct extern_list *p;
751
  if (extern_head)
752
    {
753
      fputs ("\n", asm_out_file);
754
      for (p = extern_head; p != 0; p = p->next)
755
        {
756
          name_tree = get_identifier (p->name);
757
          if (!TREE_ASM_WRITTEN (name_tree)
758
              && TREE_SYMBOL_REFERENCED (name_tree))
759
            {
760
              TREE_ASM_WRITTEN (name_tree) = 1;
761
              fputs ("\t.extern\t", asm_out_file);
762
              assemble_name (asm_out_file, p->name);
763
              fprintf (asm_out_file, ", %d\n", p->size);
764
            }
765
        }
766
    }
767
}
768
 
769
/* Implement TARGET_OPTION_OVERRIDE hook.  */
770
static void
771
score_option_override (void)
772
{
773
  flag_pic = false;
774
  score_sdata_max = SCORE_DEFAULT_SDATA_MAX;
775
 
776
}
777
 
778
/* Implement REGNO_REG_CLASS macro.  */
779
int
780
score_reg_class (int regno)
781
{
782
  int c;
783
  gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
784
 
785
  if (regno == FRAME_POINTER_REGNUM
786
      || regno == ARG_POINTER_REGNUM)
787
    return ALL_REGS;
788
 
789
  for (c = 0; c < N_REG_CLASSES; c++)
790
    if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
791
      return c;
792
 
793
  return NO_REGS;
794
}
795
 
796
/* Implement PREFERRED_RELOAD_CLASS macro.  */
797
enum reg_class
798
score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
799
{
800
  if (reg_class_subset_p (G16_REGS, rclass))
801
    return G16_REGS;
802
  if (reg_class_subset_p (G32_REGS, rclass))
803
    return G32_REGS;
804
  return rclass;
805
}
806
 
807
/* Implement SECONDARY_INPUT_RELOAD_CLASS
808
   and SECONDARY_OUTPUT_RELOAD_CLASS macro.  */
809
enum reg_class
810
score_secondary_reload_class (enum reg_class rclass,
811
                              enum machine_mode mode ATTRIBUTE_UNUSED,
812
                              rtx x)
813
{
814
  int regno = -1;
815
  if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
816
    regno = true_regnum (x);
817
 
818
  if (!GR_REG_CLASS_P (rclass))
819
    return GP_REG_P (regno) ? NO_REGS : G32_REGS;
820
  return NO_REGS;
821
}
822
 
823
 
824
/* Return truth value on whether or not a given hard register
825
   can support a given mode.  */
826
int
827
score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
828
{
829
  int size = GET_MODE_SIZE (mode);
830
  enum mode_class mclass = GET_MODE_CLASS (mode);
831
 
832
  if (mclass == MODE_CC)
833
    return regno == CC_REGNUM;
834
  else if (regno == FRAME_POINTER_REGNUM
835
           || regno == ARG_POINTER_REGNUM)
836
    return mclass == MODE_INT;
837
  else if (GP_REG_P (regno))
838
    /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1)  */
839
    return !(regno & 1) || (size <= UNITS_PER_WORD);
840
  else if (CE_REG_P (regno))
841
    return (mclass == MODE_INT
842
            && ((size <= UNITS_PER_WORD)
843
                || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
844
  else
845
    return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
846
}
847
 
848
/* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
849
   pointer or argument pointer.  TO is either the stack pointer or
850
   hard frame pointer.  */
851
HOST_WIDE_INT
852
score_initial_elimination_offset (int from,
853
                                  int to ATTRIBUTE_UNUSED)
854
{
855
  struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
856
  switch (from)
857
    {
858
    case ARG_POINTER_REGNUM:
859
      return f->total_size;
860
    case FRAME_POINTER_REGNUM:
861
      return 0;
862
    default:
863
      gcc_unreachable ();
864
    }
865
}
866
 
867
/* Implement TARGET_FUNCTION_ARG_ADVANCE hook.  */
868
static void
869
score_function_arg_advance (cumulative_args_t cum_args, enum machine_mode mode,
870
                            const_tree type, bool named)
871
{
872
  struct score_arg_info info;
873
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
874
  score_classify_arg (cum, mode, type, named, &info);
875
  cum->num_gprs = info.reg_offset + info.reg_words;
876
  if (info.stack_words > 0)
877
    cum->stack_words = info.stack_offset + info.stack_words;
878
  cum->arg_number++;
879
}
880
 
881
/* Implement TARGET_ARG_PARTIAL_BYTES macro.  */
882
int
883
score_arg_partial_bytes (cumulative_args_t cum_args,
884
                         enum machine_mode mode, tree type, bool named)
885
{
886
  struct score_arg_info info;
887
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
888
  score_classify_arg (cum, mode, type, named, &info);
889
  return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
890
}
891
 
892
/* Implement TARGET_FUNCTION_ARG hook.  */
893
static rtx
894
score_function_arg (cumulative_args_t cum_args, enum machine_mode mode,
895
                    const_tree type, bool named)
896
{
897
  struct score_arg_info info;
898
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
899
 
900
  if (mode == VOIDmode || !named)
901
    return 0;
902
 
903
  score_classify_arg (cum, mode, type, named, &info);
904
 
905
  if (info.reg_offset == ARG_REG_NUM)
906
    return 0;
907
 
908
  if (!info.stack_words)
909
    return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
910
  else
911
    {
912
      rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
913
      unsigned int i, part_offset = 0;
914
      for (i = 0; i < info.reg_words; i++)
915
        {
916
          rtx reg;
917
          reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
918
          XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
919
                                                   GEN_INT (part_offset));
920
          part_offset += UNITS_PER_WORD;
921
        }
922
      return ret;
923
    }
924
}
925
 
926
/* Implement FUNCTION_VALUE and LIBCALL_VALUE.  For normal calls,
927
   VALTYPE is the return type and MODE is VOIDmode.  For libcalls,
928
   VALTYPE is null and MODE is the mode of the return value.  */
929
rtx
930
score_function_value (const_tree valtype, const_tree func, enum machine_mode mode)
931
{
932
  if (valtype)
933
    {
934
      int unsignedp;
935
      mode = TYPE_MODE (valtype);
936
      unsignedp = TYPE_UNSIGNED (valtype);
937
      mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
938
    }
939
  return gen_rtx_REG (mode, RT_REGNUM);
940
}
941
 
942
/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE.  */
943
 
944
static void
945
score_asm_trampoline_template (FILE *f)
946
{
947
  fprintf (f, "\t.set r1\n");
948
  fprintf (f, "\tmv r31, r3\n");
949
  fprintf (f, "\tbl nextinsn\n");
950
  fprintf (f, "nextinsn:\n");
951
  fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
952
  fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
953
  fprintf (f, "\tmv r3, r31\n");
954
  fprintf (f, "\tbr! r1\n");
955
  fprintf (f, "\tnop!\n");
956
  fprintf (f, "\t.set nor1\n");
957
}
958
 
959
/* Implement TARGET_TRAMPOLINE_INIT.  */
960
static void
961
score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
962
{
963
#define CODE_SIZE        (TRAMPOLINE_INSNS * UNITS_PER_WORD)
964
 
965
  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
966
  rtx mem;
967
 
968
  emit_block_move (m_tramp, assemble_trampoline_template (),
969
                   GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
970
 
971
  mem = adjust_address (m_tramp, SImode, CODE_SIZE);
972
  emit_move_insn (mem, fnaddr);
973
  mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
974
  emit_move_insn (mem, chain_value);
975
 
976
#undef CODE_SIZE
977
}
978
 
979
/* This function is used to implement REG_MODE_OK_FOR_BASE_P macro.  */
980
int
981
score_regno_mode_ok_for_base_p (int regno, int strict)
982
{
983
  if (regno >= FIRST_PSEUDO_REGISTER)
984
    {
985
      if (!strict)
986
        return 1;
987
      regno = reg_renumber[regno];
988
    }
989
  if (regno == ARG_POINTER_REGNUM
990
      || regno == FRAME_POINTER_REGNUM)
991
    return 1;
992
  return GP_REG_P (regno);
993
}
994
 
995
/* Implement TARGET_LEGITIMATE_ADDRESS_P macro.  */
996
static bool
997
score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
998
{
999
  struct score_address_info addr;
1000
 
1001
  return score_classify_address (&addr, mode, x, strict);
1002
}
1003
 
1004
/* Implement TARGET_REGISTER_MOVE_COST.
1005
 
1006
   Return a number assessing the cost of moving a register in class
1007
   FROM to class TO. */
1008
static int
1009
score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1010
                          reg_class_t from, reg_class_t to)
1011
{
1012
  if (GR_REG_CLASS_P (from))
1013
    {
1014
      if (GR_REG_CLASS_P (to))
1015
        return 2;
1016
      else if (SP_REG_CLASS_P (to))
1017
        return 4;
1018
      else if (CP_REG_CLASS_P (to))
1019
        return 5;
1020
      else if (CE_REG_CLASS_P (to))
1021
        return 6;
1022
    }
1023
  if (GR_REG_CLASS_P (to))
1024
    {
1025
      if (GR_REG_CLASS_P (from))
1026
        return 2;
1027
      else if (SP_REG_CLASS_P (from))
1028
        return 4;
1029
      else if (CP_REG_CLASS_P (from))
1030
        return 5;
1031
      else if (CE_REG_CLASS_P (from))
1032
        return 6;
1033
    }
1034
  return 12;
1035
}
1036
 
1037
/* Return the number of instructions needed to load a symbol of the
1038
   given type into a register.  */
1039
static int
1040
score_symbol_insns (enum score_symbol_type type)
1041
{
1042
  switch (type)
1043
    {
1044
    case SYMBOL_GENERAL:
1045
      return 2;
1046
 
1047
    case SYMBOL_SMALL_DATA:
1048
      return 1;
1049
    }
1050
 
1051
  gcc_unreachable ();
1052
}
1053
 
1054
/* Return the number of instructions needed to load or store a value
1055
   of mode MODE at X.  Return 0 if X isn't valid for MODE.  */
1056
static int
1057
score_address_insns (rtx x, enum machine_mode mode)
1058
{
1059
  struct score_address_info addr;
1060
  int factor;
1061
 
1062
  if (mode == BLKmode)
1063
    factor = 1;
1064
  else
1065
    factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1066
 
1067
  if (score_classify_address (&addr, mode, x, false))
1068
    switch (addr.type)
1069
      {
1070
      case SCORE_ADD_REG:
1071
      case SCORE_ADD_CONST_INT:
1072
        return factor;
1073
 
1074
      case SCORE_ADD_SYMBOLIC:
1075
        return factor * score_symbol_insns (addr.symbol_type);
1076
      }
1077
  return 0;
1078
}
1079
 
1080
/* Implement TARGET_RTX_COSTS macro.  */
1081
bool
1082
score_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
1083
                 int *total, bool speed ATTRIBUTE_UNUSED)
1084
{
1085
  enum machine_mode mode = GET_MODE (x);
1086
 
1087
  switch (code)
1088
    {
1089
    case CONST_INT:
1090
      if (outer_code == SET)
1091
        {
1092
          if (((INTVAL (x) & 0xffff) == 0)
1093
              || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1094
            *total = COSTS_N_INSNS (1);
1095
          else
1096
            *total = COSTS_N_INSNS (2);
1097
        }
1098
      else if (outer_code == PLUS || outer_code == MINUS)
1099
        {
1100
          if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191)
1101
            *total = 0;
1102
          else if (((INTVAL (x) & 0xffff) == 0)
1103
                   || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1104
            *total = 1;
1105
          else
1106
            *total = COSTS_N_INSNS (2);
1107
        }
1108
      else if (outer_code == AND || outer_code == IOR)
1109
        {
1110
          if (INTVAL (x) >= 0 && INTVAL (x) <= 16383)
1111
            *total = 0;
1112
          else if (((INTVAL (x) & 0xffff) == 0)
1113
                   || (INTVAL (x) >= 0 && INTVAL (x) <= 65535))
1114
            *total = 1;
1115
          else
1116
            *total = COSTS_N_INSNS (2);
1117
        }
1118
      else
1119
        {
1120
          *total = 0;
1121
        }
1122
      return true;
1123
 
1124
    case CONST:
1125
    case SYMBOL_REF:
1126
    case LABEL_REF:
1127
    case CONST_DOUBLE:
1128
      *total = COSTS_N_INSNS (2);
1129
      return true;
1130
 
1131
    case MEM:
1132
      {
1133
        /* If the address is legitimate, return the number of
1134
           instructions it needs, otherwise use the default handling.  */
1135
        int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
1136
        if (n > 0)
1137
          {
1138
            *total = COSTS_N_INSNS (n + 1);
1139
            return true;
1140
          }
1141
        return false;
1142
      }
1143
 
1144
    case FFS:
1145
      *total = COSTS_N_INSNS (6);
1146
      return true;
1147
 
1148
    case NOT:
1149
      *total = COSTS_N_INSNS (1);
1150
      return true;
1151
 
1152
    case AND:
1153
    case IOR:
1154
    case XOR:
1155
      if (mode == DImode)
1156
        {
1157
          *total = COSTS_N_INSNS (2);
1158
          return true;
1159
        }
1160
      return false;
1161
 
1162
    case ASHIFT:
1163
    case ASHIFTRT:
1164
    case LSHIFTRT:
1165
      if (mode == DImode)
1166
        {
1167
          *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1168
                                  ? 4 : 12);
1169
          return true;
1170
        }
1171
      return false;
1172
 
1173
    case ABS:
1174
      *total = COSTS_N_INSNS (4);
1175
      return true;
1176
 
1177
    case PLUS:
1178
    case MINUS:
1179
      if (mode == DImode)
1180
        {
1181
          *total = COSTS_N_INSNS (4);
1182
          return true;
1183
        }
1184
      *total = COSTS_N_INSNS (1);
1185
      return true;
1186
 
1187
    case NEG:
1188
      if (mode == DImode)
1189
        {
1190
          *total = COSTS_N_INSNS (4);
1191
          return true;
1192
        }
1193
      return false;
1194
 
1195
    case MULT:
1196
      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1197
      return true;
1198
 
1199
    case DIV:
1200
    case MOD:
1201
    case UDIV:
1202
    case UMOD:
1203
      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1204
      return true;
1205
 
1206
    case SIGN_EXTEND:
1207
    case ZERO_EXTEND:
1208
      switch (GET_MODE (XEXP (x, 0)))
1209
        {
1210
        case QImode:
1211
        case HImode:
1212
          if (GET_CODE (XEXP (x, 0)) == MEM)
1213
            {
1214
              *total = COSTS_N_INSNS (2);
1215
 
1216
              if (!TARGET_LITTLE_ENDIAN &&
1217
                  side_effects_p (XEXP (XEXP (x, 0), 0)))
1218
                *total = 100;
1219
            }
1220
          else
1221
            *total = COSTS_N_INSNS (1);
1222
          break;
1223
 
1224
        default:
1225
          *total = COSTS_N_INSNS (1);
1226
          break;
1227
        }
1228
      return true;
1229
 
1230
    default:
1231
      return false;
1232
    }
1233
}
1234
 
1235
/* Implement TARGET_ADDRESS_COST macro.  */
1236
int
1237
score_address_cost (rtx addr,
1238
                    bool speed ATTRIBUTE_UNUSED)
1239
{
1240
  return score_address_insns (addr, SImode);
1241
}
1242
 
1243
/* Implement ASM_OUTPUT_EXTERNAL macro.  */
1244
int
1245
score_output_external (FILE *file ATTRIBUTE_UNUSED,
1246
                       tree decl, const char *name)
1247
{
1248
  register struct extern_list *p;
1249
 
1250
  if (score_in_small_data_p (decl))
1251
    {
1252
      p = ggc_alloc_extern_list ();
1253
      p->next = extern_head;
1254
      p->name = name;
1255
      p->size = int_size_in_bytes (TREE_TYPE (decl));
1256
      extern_head = p;
1257
    }
1258
  return 0;
1259
}
1260
 
1261
/* Implement RETURN_ADDR_RTX.  Note, we do not support moving
1262
   back to a previous frame.  */
1263
rtx
1264
score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1265
{
1266
  if (count != 0)
1267
    return const0_rtx;
1268
  return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1269
}
1270
 
1271
/* Implement PRINT_OPERAND macro.  */
1272
/* Score-specific operand codes:
1273
   '['        print .set nor1 directive
1274
   ']'        print .set r1 directive
1275
   'U'        print hi part of a CONST_INT rtx
1276
   'E'        print log2(v)
1277
   'F'        print log2(~v)
1278
   'D'        print SFmode const double
1279
   'S'        selectively print "!" if operand is 15bit instruction accessible
1280
   'V'        print "v!" if operand is 15bit instruction accessible, or "lfh!"
1281
   'L'        low  part of DImode reg operand
1282
   'H'        high part of DImode reg operand
1283
   'C'        print part of opcode for a branch condition.  */
1284
void
1285
score_print_operand (FILE *file, rtx op, int c)
1286
{
1287
  enum rtx_code code = UNKNOWN;
1288
  if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1289
    code = GET_CODE (op);
1290
 
1291
  if (c == '[')
1292
    {
1293
      fprintf (file, ".set r1\n");
1294
    }
1295
  else if (c == ']')
1296
    {
1297
      fprintf (file, "\n\t.set nor1");
1298
    }
1299
  else if (c == 'U')
1300
    {
1301
      gcc_assert (code == CONST_INT);
1302
      fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1303
               (INTVAL (op) >> 16) & 0xffff);
1304
    }
1305
  else if (c == 'D')
1306
    {
1307
      if (GET_CODE (op) == CONST_DOUBLE)
1308
        {
1309
          rtx temp = gen_lowpart (SImode, op);
1310
          gcc_assert (GET_MODE (op) == SFmode);
1311
          fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1312
        }
1313
      else
1314
        output_addr_const (file, op);
1315
    }
1316
  else if (c == 'S')
1317
    {
1318
      gcc_assert (code == REG);
1319
      if (G16_REG_P (REGNO (op)))
1320
        fprintf (file, "!");
1321
    }
1322
  else if (c == 'V')
1323
    {
1324
      gcc_assert (code == REG);
1325
      fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1326
    }
1327
  else if (c == 'C')
1328
    {
1329
      enum machine_mode mode = GET_MODE (XEXP (op, 0));
1330
 
1331
      switch (code)
1332
        {
1333
        case EQ: fputs ("eq", file); break;
1334
        case NE: fputs ("ne", file); break;
1335
        case GT: fputs ("gt", file); break;
1336
        case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1337
        case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1338
        case LE: fputs ("le", file); break;
1339
        case GTU: fputs ("gtu", file); break;
1340
        case GEU: fputs ("cs", file); break;
1341
        case LTU: fputs ("cc", file); break;
1342
        case LEU: fputs ("leu", file); break;
1343
        default:
1344
          output_operand_lossage ("invalid operand for code: '%c'", code);
1345
        }
1346
    }
1347
  else if (c == 'E')
1348
    {
1349
      unsigned HOST_WIDE_INT i;
1350
      unsigned HOST_WIDE_INT pow2mask = 1;
1351
      unsigned HOST_WIDE_INT val;
1352
 
1353
      val = INTVAL (op);
1354
      for (i = 0; i < 32; i++)
1355
        {
1356
          if (val == pow2mask)
1357
            break;
1358
          pow2mask <<= 1;
1359
        }
1360
      gcc_assert (i < 32);
1361
      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1362
    }
1363
  else if (c == 'F')
1364
    {
1365
      unsigned HOST_WIDE_INT i;
1366
      unsigned HOST_WIDE_INT pow2mask = 1;
1367
      unsigned HOST_WIDE_INT val;
1368
 
1369
      val = ~INTVAL (op);
1370
      for (i = 0; i < 32; i++)
1371
        {
1372
          if (val == pow2mask)
1373
            break;
1374
          pow2mask <<= 1;
1375
        }
1376
      gcc_assert (i < 32);
1377
      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1378
    }
1379
  else if (code == REG)
1380
    {
1381
      int regnum = REGNO (op);
1382
      if ((c == 'H' && !WORDS_BIG_ENDIAN)
1383
          || (c == 'L' && WORDS_BIG_ENDIAN))
1384
        regnum ++;
1385
      fprintf (file, "%s", reg_names[regnum]);
1386
    }
1387
  else
1388
    {
1389
      switch (code)
1390
        {
1391
        case MEM:
1392
          score_print_operand_address (file, op);
1393
          break;
1394
        default:
1395
          output_addr_const (file, op);
1396
        }
1397
    }
1398
}
1399
 
1400
/* Implement PRINT_OPERAND_ADDRESS macro.  */
1401
void
1402
score_print_operand_address (FILE *file, rtx x)
1403
{
1404
  struct score_address_info addr;
1405
  enum rtx_code code = GET_CODE (x);
1406
  enum machine_mode mode = GET_MODE (x);
1407
 
1408
  if (code == MEM)
1409
    x = XEXP (x, 0);
1410
 
1411
  if (score_classify_address (&addr, mode, x, true))
1412
    {
1413
      switch (addr.type)
1414
        {
1415
        case SCORE_ADD_REG:
1416
          {
1417
            switch (addr.code)
1418
              {
1419
              case PRE_DEC:
1420
                fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1421
                         INTVAL (addr.offset));
1422
                break;
1423
              case POST_DEC:
1424
                fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1425
                         INTVAL (addr.offset));
1426
                break;
1427
              case PRE_INC:
1428
                fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1429
                         INTVAL (addr.offset));
1430
                break;
1431
              case POST_INC:
1432
                fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1433
                         INTVAL (addr.offset));
1434
                break;
1435
              default:
1436
                if (INTVAL(addr.offset) == 0)
1437
                  fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1438
                else
1439
                  fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1440
                          INTVAL(addr.offset));
1441
                break;
1442
              }
1443
          }
1444
          return;
1445
        case SCORE_ADD_CONST_INT:
1446
        case SCORE_ADD_SYMBOLIC:
1447
          output_addr_const (file, x);
1448
          return;
1449
        }
1450
    }
1451
  print_rtl (stderr, x);
1452
  gcc_unreachable ();
1453
}
1454
 
1455
/* Implement SELECT_CC_MODE macro.  */
1456
enum machine_mode
1457
score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1458
{
1459
  if ((op == EQ || op == NE || op == LT || op == GE)
1460
      && y == const0_rtx
1461
      && GET_MODE (x) == SImode)
1462
    {
1463
      switch (GET_CODE (x))
1464
        {
1465
        case PLUS:
1466
        case MINUS:
1467
        case NEG:
1468
        case AND:
1469
        case IOR:
1470
        case XOR:
1471
        case NOT:
1472
        case ASHIFT:
1473
        case LSHIFTRT:
1474
        case ASHIFTRT:
1475
          return CC_NZmode;
1476
 
1477
        case SIGN_EXTEND:
1478
        case ZERO_EXTEND:
1479
        case ROTATE:
1480
        case ROTATERT:
1481
          return (op == LT || op == GE) ? CC_Nmode : CCmode;
1482
 
1483
        default:
1484
          return CCmode;
1485
        }
1486
    }
1487
 
1488
  if ((op == EQ || op == NE)
1489
      && (GET_CODE (y) == NEG)
1490
      && register_operand (XEXP (y, 0), SImode)
1491
      && register_operand (x, SImode))
1492
    {
1493
      return CC_NZmode;
1494
    }
1495
 
1496
  return CCmode;
1497
}
1498
 
1499
/* Generate the prologue instructions for entry into a S+core function.  */
1500
void
1501
score_prologue (void)
1502
{
1503
#define EMIT_PL(_rtx)        RTX_FRAME_RELATED_P (_rtx) = 1
1504
 
1505
  struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1506
  HOST_WIDE_INT size;
1507
  int regno;
1508
 
1509
  size = f->total_size - f->gp_reg_size;
1510
 
1511
  if (flag_pic)
1512
    emit_insn (gen_cpload_score7 ());
1513
 
1514
  for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1515
    {
1516
      if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1517
        {
1518
          rtx mem = gen_rtx_MEM (SImode,
1519
                                 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1520
          rtx reg = gen_rtx_REG (SImode, regno);
1521
          if (!crtl->calls_eh_return)
1522
            MEM_READONLY_P (mem) = 1;
1523
          EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1524
        }
1525
    }
1526
 
1527
  if (size > 0)
1528
    {
1529
      rtx insn;
1530
 
1531
      if (size >= -32768 && size <= 32767)
1532
        EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1533
                                           stack_pointer_rtx,
1534
                                           GEN_INT (-size))));
1535
      else
1536
        {
1537
          EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE_PROLOGUE_TEMP_REGNUM),
1538
                                   GEN_INT (size)));
1539
          EMIT_PL (emit_insn
1540
                   (gen_sub3_insn (stack_pointer_rtx,
1541
                                   stack_pointer_rtx,
1542
                                   gen_rtx_REG (Pmode,
1543
                                                SCORE_PROLOGUE_TEMP_REGNUM))));
1544
        }
1545
      insn = get_last_insn ();
1546
      REG_NOTES (insn) =
1547
        alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1548
                         gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1549
                                      plus_constant (stack_pointer_rtx,
1550
                                                     -size)),
1551
                                      REG_NOTES (insn));
1552
    }
1553
 
1554
  if (frame_pointer_needed)
1555
    EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1556
 
1557
  if (flag_pic && f->cprestore_size)
1558
    {
1559
      if (frame_pointer_needed)
1560
        emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1561
      else
1562
        emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1563
    }
1564
 
1565
#undef EMIT_PL
1566
}
1567
 
1568
/* Generate the epilogue instructions in a S+core function.  */
1569
void
1570
score_epilogue (int sibcall_p)
1571
{
1572
  struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1573
  HOST_WIDE_INT size;
1574
  int regno;
1575
  rtx base;
1576
 
1577
  size = f->total_size - f->gp_reg_size;
1578
 
1579
  if (!frame_pointer_needed)
1580
    base = stack_pointer_rtx;
1581
  else
1582
    base = hard_frame_pointer_rtx;
1583
 
1584
  if (size)
1585
    {
1586
      if (size >= -32768 && size <= 32767)
1587
        emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1588
      else
1589
        {
1590
          emit_move_insn (gen_rtx_REG (Pmode, SCORE_EPILOGUE_TEMP_REGNUM),
1591
                          GEN_INT (size));
1592
          emit_insn (gen_add3_insn (base, base,
1593
                                    gen_rtx_REG (Pmode,
1594
                                                 SCORE_EPILOGUE_TEMP_REGNUM)));
1595
        }
1596
    }
1597
 
1598
  if (base != stack_pointer_rtx)
1599
    emit_move_insn (stack_pointer_rtx, base);
1600
 
1601
  if (crtl->calls_eh_return)
1602
    emit_insn (gen_add3_insn (stack_pointer_rtx,
1603
                              stack_pointer_rtx,
1604
                              EH_RETURN_STACKADJ_RTX));
1605
 
1606
  for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1607
    {
1608
      if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1609
        {
1610
          rtx mem = gen_rtx_MEM (SImode,
1611
                                 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1612
          rtx reg = gen_rtx_REG (SImode, regno);
1613
 
1614
          if (!crtl->calls_eh_return)
1615
            MEM_READONLY_P (mem) = 1;
1616
 
1617
          emit_insn (gen_popsi_score7 (reg, mem));
1618
        }
1619
    }
1620
 
1621
  if (!sibcall_p)
1622
    emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1623
}
1624
 
1625
/* Return true if X is a symbolic constant that can be calculated in
1626
   the same way as a bare symbol.  If it is, store the type of the
1627
   symbol in *SYMBOL_TYPE.  */
1628
int
1629
score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1630
{
1631
  HOST_WIDE_INT offset;
1632
 
1633
  score_split_const (x, &x, &offset);
1634
  if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1635
    *symbol_type = score_classify_symbol (x);
1636
  else
1637
    return 0;
1638
 
1639
  if (offset == 0)
1640
    return 1;
1641
 
1642
  /* if offset > 15bit, must reload  */
1643
  if (!IMM_IN_RANGE (offset, 15, 1))
1644
    return 0;
1645
 
1646
  switch (*symbol_type)
1647
    {
1648
    case SYMBOL_GENERAL:
1649
      return 1;
1650
    case SYMBOL_SMALL_DATA:
1651
      return score_offset_within_object_p (x, offset);
1652
    }
1653
  gcc_unreachable ();
1654
}
1655
 
1656
void
1657
score_movsicc (rtx *ops)
1658
{
1659
  enum machine_mode mode;
1660
 
1661
  mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1662
  emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1663
                          gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1664
                                           XEXP (ops[1], 1))));
1665
}
1666
 
1667
/* Call and sibcall pattern all need call this function.  */
1668
void
1669
score_call (rtx *ops, bool sib)
1670
{
1671
  rtx addr = XEXP (ops[0], 0);
1672
  if (!call_insn_operand (addr, VOIDmode))
1673
    {
1674
      rtx oaddr = addr;
1675
      addr = gen_reg_rtx (Pmode);
1676
      gen_move_insn (addr, oaddr);
1677
    }
1678
 
1679
  if (sib)
1680
    emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1681
  else
1682
    emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1683
}
1684
 
1685
/* Call value and sibcall value pattern all need call this function.  */
1686
void
1687
score_call_value (rtx *ops, bool sib)
1688
{
1689
  rtx result = ops[0];
1690
  rtx addr = XEXP (ops[1], 0);
1691
  rtx arg = ops[2];
1692
 
1693
  if (!call_insn_operand (addr, VOIDmode))
1694
    {
1695
      rtx oaddr = addr;
1696
      addr = gen_reg_rtx (Pmode);
1697
      gen_move_insn (addr, oaddr);
1698
    }
1699
 
1700
  if (sib)
1701
    emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1702
  else
1703
    emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1704
}
1705
 
1706
/* Machine Split  */
1707
void
1708
score_movdi (rtx *ops)
1709
{
1710
  rtx dst = ops[0];
1711
  rtx src = ops[1];
1712
  rtx dst0 = score_subw (dst, 0);
1713
  rtx dst1 = score_subw (dst, 1);
1714
  rtx src0 = score_subw (src, 0);
1715
  rtx src1 = score_subw (src, 1);
1716
 
1717
  if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1718
    {
1719
      emit_move_insn (dst1, src1);
1720
      emit_move_insn (dst0, src0);
1721
    }
1722
  else
1723
    {
1724
      emit_move_insn (dst0, src0);
1725
      emit_move_insn (dst1, src1);
1726
    }
1727
}
1728
 
1729
void
1730
score_zero_extract_andi (rtx *ops)
1731
{
1732
  if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1733
    emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1734
  else
1735
    {
1736
      unsigned HOST_WIDE_INT mask;
1737
      mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1738
      mask = mask << INTVAL (ops[2]);
1739
      emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1740
                                 gen_int_mode (mask, SImode)));
1741
    }
1742
}
1743
 
1744
/* Check addr could be present as PRE/POST mode.  */
1745
static bool
1746
score_pindex_mem (rtx addr)
1747
{
1748
  if (GET_CODE (addr) == MEM)
1749
    {
1750
      switch (GET_CODE (XEXP (addr, 0)))
1751
        {
1752
        case PRE_DEC:
1753
        case POST_DEC:
1754
        case PRE_INC:
1755
        case POST_INC:
1756
          return true;
1757
        default:
1758
          break;
1759
        }
1760
    }
1761
  return false;
1762
}
1763
 
1764
/* Output asm code for ld/sw insn.  */
1765
static int
1766
score_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1767
{
1768
  struct score_address_info ai;
1769
 
1770
  gcc_assert (GET_CODE (ops[idata]) == REG);
1771
  gcc_assert (score_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1772
 
1773
  if (!score_pindex_mem (ops[iaddr])
1774
      && ai.type == SCORE_ADD_REG
1775
      && GET_CODE (ai.offset) == CONST_INT
1776
      && G16_REG_P (REGNO (ops[idata]))
1777
      && G16_REG_P (REGNO (ai.reg)))
1778
    {
1779
      if (INTVAL (ai.offset) == 0)
1780
        {
1781
          ops[iaddr] = ai.reg;
1782
          return snprintf (ip, INS_BUF_SZ,
1783
                           "!\t%%%d, [%%%d]", idata, iaddr);
1784
        }
1785
      if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1786
        {
1787
          HOST_WIDE_INT offset = INTVAL (ai.offset);
1788
          if (SCORE_ALIGN_UNIT (offset, unit)
1789
              && (((offset >> unit) >= 0) && ((offset >> unit) <= 31)))
1790
            {
1791
              ops[iaddr] = ai.offset;
1792
              return snprintf (ip, INS_BUF_SZ,
1793
                               "p!\t%%%d, %%c%d", idata, iaddr);
1794
            }
1795
        }
1796
    }
1797
  return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1798
}
1799
 
1800
/* Output asm insn for load.  */
1801
const char *
1802
score_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1803
{
1804
  const char *pre_ins[] =
1805
    {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1806
  char *ip;
1807
 
1808
  strcpy (score_ins, pre_ins[(sign ? 4 : 0) + unit]);
1809
  ip = score_ins + strlen (score_ins);
1810
 
1811
  if ((!sign && unit != SCORE_HWORD)
1812
      || (sign && unit != SCORE_BYTE))
1813
    score_pr_addr_post (ops, 0, 1, ip, unit);
1814
  else
1815
    snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1816
 
1817
  return score_ins;
1818
}
1819
 
1820
/* Output asm insn for store.  */
1821
const char *
1822
score_sinsn (rtx *ops, enum score_mem_unit unit)
1823
{
1824
  const char *pre_ins[] = {"sb", "sh", "sw"};
1825
  char *ip;
1826
 
1827
  strcpy (score_ins, pre_ins[unit]);
1828
  ip = score_ins + strlen (score_ins);
1829
  score_pr_addr_post (ops, 1, 0, ip, unit);
1830
  return score_ins;
1831
}
1832
 
1833
/* Output asm insn for load immediate.  */
1834
const char *
1835
score_limm (rtx *ops)
1836
{
1837
  HOST_WIDE_INT v;
1838
 
1839
  gcc_assert (GET_CODE (ops[0]) == REG);
1840
  gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1841
 
1842
  v = INTVAL (ops[1]);
1843
  if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1844
    return "ldiu!\t%0, %c1";
1845
  else if (IMM_IN_RANGE (v, 16, 1))
1846
    return "ldi\t%0, %c1";
1847
  else if ((v & 0xffff) == 0)
1848
    return "ldis\t%0, %U1";
1849
  else
1850
    return "li\t%0, %c1";
1851
}
1852
 
1853
/* Output asm insn for move.  */
1854
const char *
1855
score_move (rtx *ops)
1856
{
1857
  gcc_assert (GET_CODE (ops[0]) == REG);
1858
  gcc_assert (GET_CODE (ops[1]) == REG);
1859
 
1860
  if (G16_REG_P (REGNO (ops[0])))
1861
    {
1862
      if (G16_REG_P (REGNO (ops[1])))
1863
        return "mv!\t%0, %1";
1864
      else
1865
        return "mlfh!\t%0, %1";
1866
    }
1867
  else if (G16_REG_P (REGNO (ops[1])))
1868
    return "mhfl!\t%0, %1";
1869
  else
1870
    return "mv\t%0, %1";
1871
}
1872
 
1873
/* Generate add insn.  */
1874
const char *
1875
score_select_add_imm (rtx *ops, bool set_cc)
1876
{
1877
  HOST_WIDE_INT v = INTVAL (ops[2]);
1878
 
1879
  gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1880
  gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1881
 
1882
  if (set_cc && G16_REG_P (REGNO (ops[0])))
1883
    {
1884
      if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1885
        {
1886
          ops[2] = GEN_INT (ffs (v) - 1);
1887
          return "addei!\t%0, %c2";
1888
        }
1889
 
1890
      if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1891
        {
1892
          ops[2] = GEN_INT (ffs (-v) - 1);
1893
          return "subei!\t%0, %c2";
1894
        }
1895
    }
1896
 
1897
  if (set_cc)
1898
    return "addi.c\t%0, %c2";
1899
  else
1900
    return "addi\t%0, %c2";
1901
}
1902
 
1903
/* Output arith insn.  */
1904
const char *
1905
score_select (rtx *ops, const char *inst_pre,
1906
              bool commu, const char *letter, bool set_cc)
1907
{
1908
  gcc_assert (GET_CODE (ops[0]) == REG);
1909
  gcc_assert (GET_CODE (ops[1]) == REG);
1910
 
1911
  if (set_cc && G16_REG_P (REGNO (ops[0]))
1912
      && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1913
      && REGNO (ops[0]) == REGNO (ops[1]))
1914
    {
1915
      snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1916
      return score_ins;
1917
    }
1918
 
1919
  if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1920
      && G16_REG_P (REGNO (ops[1]))
1921
      && REGNO (ops[0]) == REGNO (ops[2]))
1922
    {
1923
      gcc_assert (GET_CODE (ops[2]) == REG);
1924
      snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1925
      return score_ins;
1926
    }
1927
 
1928
  if (set_cc)
1929
    snprintf (score_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1930
  else
1931
    snprintf (score_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1932
  return score_ins;
1933
}
1934
 
1935
/* Return nonzero when an argument must be passed by reference.  */
1936
static bool
1937
score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
1938
                         enum machine_mode mode, const_tree type,
1939
                         bool named ATTRIBUTE_UNUSED)
1940
{
1941
  /* If we have a variable-sized parameter, we have no choice.  */
1942
  return targetm.calls.must_pass_in_stack (mode, type);
1943
}
1944
 
1945
/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
1946
static bool
1947
score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
1948
                               ATTRIBUTE_UNUSED tree exp)
1949
{
1950
  return true;
1951
}
1952
 
1953
/* Implement TARGET_SCHED_ISSUE_RATE.  */
1954
static int
1955
score_issue_rate (void)
1956
{
1957
  return 1;
1958
}
1959
 
1960
/* We can always eliminate to the hard frame pointer.  We can eliminate
1961
   to the stack pointer unless a frame pointer is needed.  */
1962
 
1963
static bool
1964
score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
1965
{
1966
  return (to == HARD_FRAME_POINTER_REGNUM
1967
          || (to  == STACK_POINTER_REGNUM && !frame_pointer_needed));
1968
}
1969
 
1970
/* Argument support functions.  */
1971
 
1972
/* Initialize CUMULATIVE_ARGS for a function.  */
1973
void
1974
score_init_cumulative_args (CUMULATIVE_ARGS *cum,
1975
                            tree fntype ATTRIBUTE_UNUSED,
1976
                            rtx libname ATTRIBUTE_UNUSED)
1977
{
1978
  memset (cum, 0, sizeof (CUMULATIVE_ARGS));
1979
}
1980
 
1981
static void
1982
score_conditional_register_usage (void)
1983
{
1984
   if (!flag_pic)
1985
     fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
1986
     call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;
1987
}
1988
 
1989
struct gcc_target targetm = TARGET_INITIALIZER;

powered by: WebSVN 2.1.0

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