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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [score/] [score3.c] - Blame information for rev 414

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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