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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [config/] [score/] [score7.c] - Blame information for rev 826

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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