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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [score/] [score.c] - Blame information for rev 827

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

Line No. Rev Author Line
1 38 julius
/* Output routines for Sunplus S+CORE processor
2
   Copyright (C) 2005, 2007 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 <signal.h>
26
#include "rtl.h"
27
#include "regs.h"
28
#include "hard-reg-set.h"
29
#include "real.h"
30
#include "insn-config.h"
31
#include "conditions.h"
32
#include "insn-attr.h"
33
#include "recog.h"
34
#include "toplev.h"
35
#include "output.h"
36
#include "tree.h"
37
#include "function.h"
38
#include "expr.h"
39
#include "optabs.h"
40
#include "flags.h"
41
#include "reload.h"
42
#include "tm_p.h"
43
#include "ggc.h"
44
#include "gstab.h"
45
#include "hashtab.h"
46
#include "debug.h"
47
#include "target.h"
48
#include "target-def.h"
49
#include "integrate.h"
50
#include "langhooks.h"
51
#include "cfglayout.h"
52
#include "score-mdaux.h"
53
 
54
#define GR_REG_CLASS_P(C)        ((C) == G16_REGS || (C) == G32_REGS)
55
#define SP_REG_CLASS_P(C) \
56
  ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS)
57
#define CP_REG_CLASS_P(C) \
58
  ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS)
59
#define CE_REG_CLASS_P(C) \
60
  ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS)
61
 
62
static int score_arg_partial_bytes (const CUMULATIVE_ARGS *,
63
                                    enum machine_mode, tree, int);
64
 
65
static int score_symbol_insns (enum score_symbol_type);
66
 
67
static int score_address_insns (rtx, enum machine_mode);
68
 
69
static bool score_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *);
70
 
71
static int score_address_cost (rtx);
72
 
73
#undef  TARGET_ASM_FILE_START
74
#define TARGET_ASM_FILE_START           th_asm_file_start
75
 
76
#undef  TARGET_ASM_FILE_END
77
#define TARGET_ASM_FILE_END             th_asm_file_end
78
 
79
#undef  TARGET_ASM_FUNCTION_PROLOGUE
80
#define TARGET_ASM_FUNCTION_PROLOGUE    th_function_prologue
81
 
82
#undef  TARGET_ASM_FUNCTION_EPILOGUE
83
#define TARGET_ASM_FUNCTION_EPILOGUE    th_function_epilogue
84
 
85
#undef  TARGET_SCHED_ISSUE_RATE
86
#define TARGET_SCHED_ISSUE_RATE         th_issue_rate
87
 
88
#undef TARGET_ASM_SELECT_RTX_SECTION
89
#define TARGET_ASM_SELECT_RTX_SECTION   th_select_rtx_section
90
 
91
#undef  TARGET_IN_SMALL_DATA_P
92
#define TARGET_IN_SMALL_DATA_P          th_in_small_data_p
93
 
94
#undef  TARGET_FUNCTION_OK_FOR_SIBCALL
95
#define TARGET_FUNCTION_OK_FOR_SIBCALL  th_function_ok_for_sibcall
96
 
97
#undef TARGET_STRICT_ARGUMENT_NAMING
98
#define TARGET_STRICT_ARGUMENT_NAMING   th_strict_argument_naming
99
 
100
#undef TARGET_ASM_OUTPUT_MI_THUNK
101
#define TARGET_ASM_OUTPUT_MI_THUNK      th_output_mi_thunk
102
 
103
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
104
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK  hook_bool_tree_hwi_hwi_tree_true
105
 
106
#undef TARGET_PROMOTE_FUNCTION_ARGS
107
#define TARGET_PROMOTE_FUNCTION_ARGS    hook_bool_tree_true
108
 
109
#undef TARGET_PROMOTE_FUNCTION_RETURN
110
#define TARGET_PROMOTE_FUNCTION_RETURN  hook_bool_tree_true
111
 
112
#undef TARGET_PROMOTE_PROTOTYPES
113
#define TARGET_PROMOTE_PROTOTYPES       hook_bool_tree_true
114
 
115
#undef TARGET_MUST_PASS_IN_STACK
116
#define TARGET_MUST_PASS_IN_STACK       must_pass_in_stack_var_size
117
 
118
#undef TARGET_ARG_PARTIAL_BYTES
119
#define TARGET_ARG_PARTIAL_BYTES        score_arg_partial_bytes
120
 
121
#undef TARGET_PASS_BY_REFERENCE
122
#define TARGET_PASS_BY_REFERENCE        score_pass_by_reference
123
 
124
#undef TARGET_RETURN_IN_MEMORY
125
#define TARGET_RETURN_IN_MEMORY         score_return_in_memory
126
 
127
#undef TARGET_RTX_COSTS
128
#define TARGET_RTX_COSTS                score_rtx_costs
129
 
130
#undef TARGET_ADDRESS_COST
131
#define TARGET_ADDRESS_COST             score_address_cost
132
 
133
#undef TARGET_DEFAULT_TARGET_FLAGS
134
#define TARGET_DEFAULT_TARGET_FLAGS     TARGET_DEFAULT
135
 
136
/* Implement TARGET_RETURN_IN_MEMORY.  In S+core,
137
   small structures are returned in a register.
138
   Objects with varying size must still be returned in memory.  */
139
static bool
140
score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
141
{
142
  return ((TYPE_MODE (type) == BLKmode)
143
          || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
144
          || (int_size_in_bytes (type) == -1));
145
}
146
 
147
/* Return nonzero when an argument must be passed by reference.  */
148
static bool
149
score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
150
                         enum machine_mode mode, tree type,
151
                         bool named ATTRIBUTE_UNUSED)
152
{
153
  /* If we have a variable-sized parameter, we have no choice.  */
154
  return targetm.calls.must_pass_in_stack (mode, type);
155
}
156
 
157
/* Return a legitimate address for REG + OFFSET.  */
158
static rtx
159
score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
160
{
161
  if (!IMM_IN_RANGE (offset, 15, 1))
162
    {
163
      reg = expand_simple_binop (GET_MODE (reg), PLUS,
164
                                 gen_int_mode (offset & 0xffffc000,
165
                                               GET_MODE (reg)),
166
                                 reg, NULL, 0, OPTAB_WIDEN);
167
      offset &= 0x3fff;
168
    }
169
 
170
  return plus_constant (reg, offset);
171
}
172
 
173
/* Implement TARGET_ASM_OUTPUT_MI_THUNK.  Generate rtl rather than asm text
174
   in order to avoid duplicating too much logic from elsewhere.  */
175
static void
176
th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
177
                    HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
178
                    tree function)
179
{
180
  rtx this, temp1, temp2, insn, fnaddr;
181
 
182
  /* Pretend to be a post-reload pass while generating rtl.  */
183
  no_new_pseudos = 1;
184
  reload_completed = 1;
185
  reset_block_changes ();
186
 
187
  /* We need two temporary registers in some cases.  */
188
  temp1 = gen_rtx_REG (Pmode, 8);
189
  temp2 = gen_rtx_REG (Pmode, 9);
190
 
191
  /* Find out which register contains the "this" pointer.  */
192
  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
193
    this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
194
  else
195
    this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
196
 
197
  /* Add DELTA to THIS.  */
198
  if (delta != 0)
199
    {
200
      rtx offset = GEN_INT (delta);
201
      if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
202
        {
203
          emit_move_insn (temp1, offset);
204
          offset = temp1;
205
        }
206
      emit_insn (gen_add3_insn (this, this, offset));
207
    }
208
 
209
  /* If needed, add *(*THIS + VCALL_OFFSET) to THIS.  */
210
  if (vcall_offset != 0)
211
    {
212
      rtx addr;
213
 
214
      /* Set TEMP1 to *THIS.  */
215
      emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
216
 
217
      /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET.  */
218
      addr = score_add_offset (temp2, temp1, vcall_offset);
219
 
220
      /* Load the offset and add it to THIS.  */
221
      emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
222
      emit_insn (gen_add3_insn (this, this, temp1));
223
    }
224
 
225
  /* Jump to the target function.  */
226
  fnaddr = XEXP (DECL_RTL (function), 0);
227
  insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx));
228
  SIBLING_CALL_P (insn) = 1;
229
 
230
  /* Run just enough of rest_of_compilation.  This sequence was
231
     "borrowed" from alpha.c.  */
232
  insn = get_insns ();
233
  insn_locators_initialize ();
234
  split_all_insns_noflow ();
235
  shorten_branches (insn);
236
  final_start_function (insn, file, 1);
237
  final (insn, file, 1);
238
  final_end_function ();
239
 
240
  /* Clean up the vars set above.  Note that final_end_function resets
241
     the global pointer for us.  */
242
  reload_completed = 0;
243
  no_new_pseudos = 0;
244
}
245
 
246
/* Implement TARGET_STRICT_ARGUMENT_NAMING.  */
247
static bool
248
th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
249
{
250
  return true;
251
}
252
 
253
/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
254
static bool
255
th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
256
                            ATTRIBUTE_UNUSED tree exp)
257
{
258
  return true;
259
}
260
 
261
struct score_arg_info
262
{
263
  /* The argument's size, in bytes.  */
264
  unsigned int num_bytes;
265
 
266
  /* The number of words passed in registers, rounded up.  */
267
  unsigned int reg_words;
268
 
269
  /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST,
270
     or ARG_REG_NUM if the argument is passed entirely on the stack.  */
271
  unsigned int reg_offset;
272
 
273
  /* The number of words that must be passed on the stack, rounded up.  */
274
  unsigned int stack_words;
275
 
276
  /* The offset from the start of the stack overflow area of the argument's
277
     first stack word.  Only meaningful when STACK_WORDS is nonzero.  */
278
  unsigned int stack_offset;
279
};
280
 
281
/* Fill INFO with information about a single argument.  CUM is the
282
   cumulative state for earlier arguments.  MODE is the mode of this
283
   argument and TYPE is its type (if known).  NAMED is true if this
284
   is a named (fixed) argument rather than a variable one.  */
285
static void
286
classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
287
              tree type, int named, struct score_arg_info *info)
288
{
289
  int even_reg_p;
290
  unsigned int num_words, max_regs;
291
 
292
  even_reg_p = 0;
293
  if (GET_MODE_CLASS (mode) == MODE_INT
294
      || GET_MODE_CLASS (mode) == MODE_FLOAT)
295
    even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
296
  else
297
    if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
298
      even_reg_p = 1;
299
 
300
  if (TARGET_MUST_PASS_IN_STACK (mode, type))
301
    info->reg_offset = ARG_REG_NUM;
302
  else
303
    {
304
      info->reg_offset = cum->num_gprs;
305
      if (even_reg_p)
306
        info->reg_offset += info->reg_offset & 1;
307
    }
308
 
309
  if (mode == BLKmode)
310
    info->num_bytes = int_size_in_bytes (type);
311
  else
312
    info->num_bytes = GET_MODE_SIZE (mode);
313
 
314
  num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
315
  max_regs = ARG_REG_NUM - info->reg_offset;
316
 
317
  /* Partition the argument between registers and stack.  */
318
  info->reg_words = MIN (num_words, max_regs);
319
  info->stack_words = num_words - info->reg_words;
320
 
321
  /* The alignment applied to registers is also applied to stack arguments.  */
322
  if (info->stack_words)
323
    {
324
      info->stack_offset = cum->stack_words;
325
      if (even_reg_p)
326
        info->stack_offset += info->stack_offset & 1;
327
    }
328
}
329
 
330
/* Set up the stack and frame (if desired) for the function.  */
331
static void
332
th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
333
{
334
  const char *fnname;
335
  struct score_frame_info *f = mda_cached_frame ();
336
  HOST_WIDE_INT tsize = f->total_size;
337
 
338
  fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
339
  if (!flag_inhibit_size_directive)
340
    {
341
      fputs ("\t.ent\t", file);
342
      assemble_name (file, fnname);
343
      fputs ("\n", file);
344
    }
345
  assemble_name (file, fnname);
346
  fputs (":\n", file);
347
 
348
  if (!flag_inhibit_size_directive)
349
    {
350
      fprintf (file,
351
               "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
352
               "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
353
               ", args= " HOST_WIDE_INT_PRINT_DEC
354
               ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
355
               (reg_names[(frame_pointer_needed)
356
                ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
357
               tsize,
358
               reg_names[RA_REGNUM],
359
               current_function_is_leaf ? 1 : 0,
360
               f->var_size,
361
               f->num_gp,
362
               f->args_size,
363
               f->cprestore_size);
364
 
365
      fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
366
              f->mask,
367
              (f->gp_sp_offset - f->total_size));
368
    }
369
}
370
 
371
/* Do any necessary cleanup after a function to restore stack, frame,
372
   and regs.  */
373
static void
374
th_function_epilogue (FILE *file,
375
                      HOST_WIDE_INT size ATTRIBUTE_UNUSED)
376
{
377
  if (!flag_inhibit_size_directive)
378
    {
379
      const char *fnname;
380
      fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
381
      fputs ("\t.end\t", file);
382
      assemble_name (file, fnname);
383
      fputs ("\n", file);
384
    }
385
}
386
 
387
/* Implement TARGET_SCHED_ISSUE_RATE.  */
388
static int
389
th_issue_rate (void)
390
{
391
  return 1;
392
}
393
 
394
/* Returns true if X contains a SYMBOL_REF.  */
395
static bool
396
symbolic_expression_p (rtx x)
397
{
398
  if (GET_CODE (x) == SYMBOL_REF)
399
    return true;
400
 
401
  if (GET_CODE (x) == CONST)
402
    return symbolic_expression_p (XEXP (x, 0));
403
 
404
  if (UNARY_P (x))
405
    return symbolic_expression_p (XEXP (x, 0));
406
 
407
  if (ARITHMETIC_P (x))
408
    return (symbolic_expression_p (XEXP (x, 0))
409
            || symbolic_expression_p (XEXP (x, 1)));
410
 
411
  return false;
412
}
413
 
414
/* Choose the section to use for the constant rtx expression X that has
415
   mode MODE.  */
416
static section *
417
th_select_rtx_section (enum machine_mode mode, rtx x,
418
                       unsigned HOST_WIDE_INT align)
419
{
420
  if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
421
    return get_named_section (0, ".sdata", 0);
422
  else if (flag_pic && symbolic_expression_p (x))
423
    return get_named_section (0, ".data.rel.ro", 3);
424
  else
425
    return mergeable_constant_section (mode, align, 0);
426
}
427
 
428
/* Implement TARGET_IN_SMALL_DATA_P.  */
429
static bool
430
th_in_small_data_p (tree decl)
431
{
432
  HOST_WIDE_INT size;
433
 
434
  if (TREE_CODE (decl) == STRING_CST
435
      || TREE_CODE (decl) == FUNCTION_DECL)
436
    return false;
437
 
438
  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
439
    {
440
      const char *name;
441
      name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
442
      if (strcmp (name, ".sdata") != 0
443
          && strcmp (name, ".sbss") != 0)
444
        return true;
445
      if (!DECL_EXTERNAL (decl))
446
        return false;
447
    }
448
  size = int_size_in_bytes (TREE_TYPE (decl));
449
  return (size > 0 && size <= SCORE_SDATA_MAX);
450
}
451
 
452
/* Implement TARGET_ASM_FILE_START.  */
453
static void
454
th_asm_file_start (void)
455
{
456
  default_file_start ();
457
  fprintf (asm_out_file, ASM_COMMENT_START
458
           "GCC for S+core %s \n", SCORE_GCC_VERSION);
459
 
460
  if (flag_pic)
461
    fprintf (asm_out_file, "\t.set pic\n");
462
}
463
 
464
/* Implement TARGET_ASM_FILE_END.  When using assembler macros, emit
465
   .externs for any small-data variables that turned out to be external.  */
466
struct extern_list *extern_head = 0;
467
 
468
static void
469
th_asm_file_end (void)
470
{
471
  tree name_tree;
472
  struct extern_list *p;
473
  if (extern_head)
474
    {
475
      fputs ("\n", asm_out_file);
476
      for (p = extern_head; p != 0; p = p->next)
477
        {
478
          name_tree = get_identifier (p->name);
479
          if (!TREE_ASM_WRITTEN (name_tree)
480
              && TREE_SYMBOL_REFERENCED (name_tree))
481
            {
482
              TREE_ASM_WRITTEN (name_tree) = 1;
483
              fputs ("\t.extern\t", asm_out_file);
484
              assemble_name (asm_out_file, p->name);
485
              fprintf (asm_out_file, ", %d\n", p->size);
486
            }
487
        }
488
    }
489
}
490
 
491
static unsigned int sdata_max;
492
 
493
int
494
score_sdata_max (void)
495
{
496
  return sdata_max;
497
}
498
 
499
/* default 0 = NO_REGS  */
500
enum reg_class score_char_to_class[256];
501
 
502
/* Implement OVERRIDE_OPTIONS macro.  */
503
void
504
score_override_options (void)
505
{
506
  flag_pic = false;
507
  if (!flag_pic)
508
    sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
509
  else
510
    {
511
      sdata_max = 0;
512
      if (g_switch_set && (g_switch_value != 0))
513
        warning (0, "-fPIC and -G are incompatible");
514
    }
515
 
516
  score_char_to_class['d'] = G32_REGS;
517
  score_char_to_class['e'] = G16_REGS;
518
  score_char_to_class['t'] = T32_REGS;
519
 
520
  score_char_to_class['h'] = HI_REG;
521
  score_char_to_class['l'] = LO_REG;
522
  score_char_to_class['x'] = CE_REGS;
523
 
524
  score_char_to_class['q'] = CN_REG;
525
  score_char_to_class['y'] = LC_REG;
526
  score_char_to_class['z'] = SC_REG;
527
  score_char_to_class['a'] = SP_REGS;
528
 
529
  score_char_to_class['c'] = CR_REGS;
530
 
531
  score_char_to_class['b'] = CP1_REGS;
532
  score_char_to_class['f'] = CP2_REGS;
533
  score_char_to_class['i'] = CP3_REGS;
534
  score_char_to_class['j'] = CPA_REGS;
535
}
536
 
537
/* Implement REGNO_REG_CLASS macro.  */
538
int
539
score_reg_class (int regno)
540
{
541
  int c;
542
  gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
543
 
544
  if (regno == FRAME_POINTER_REGNUM
545
      || regno == ARG_POINTER_REGNUM)
546
    return ALL_REGS;
547
 
548
  for (c = 0; c < N_REG_CLASSES; c++)
549
    if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
550
      return c;
551
 
552
  return NO_REGS;
553
}
554
 
555
/* Implement PREFERRED_RELOAD_CLASS macro.  */
556
enum reg_class
557
score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
558
{
559
  if (reg_class_subset_p (G16_REGS, class))
560
    return G16_REGS;
561
  if (reg_class_subset_p (G32_REGS, class))
562
    return G32_REGS;
563
  return class;
564
}
565
 
566
/* Implement SECONDARY_INPUT_RELOAD_CLASS
567
   and SECONDARY_OUTPUT_RELOAD_CLASS macro.  */
568
enum reg_class
569
score_secondary_reload_class (enum reg_class class,
570
                              enum machine_mode mode ATTRIBUTE_UNUSED,
571
                              rtx x)
572
{
573
  int regno = -1;
574
  if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
575
    regno = true_regnum (x);
576
 
577
  if (!GR_REG_CLASS_P (class))
578
    return GP_REG_P (regno) ? NO_REGS : G32_REGS;
579
  return NO_REGS;
580
}
581
 
582
/* Implement CONST_OK_FOR_LETTER_P macro.  */
583
/* imm constraints
584
   I        imm16 << 16
585
   J        uimm5
586
   K        uimm16
587
   L        simm16
588
   M        uimm14
589
   N        simm14  */
590
int
591
score_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
592
{
593
  switch (c)
594
    {
595
    case 'I': return ((value & 0xffff) == 0);
596
    case 'J': return IMM_IN_RANGE (value, 5, 0);
597
    case 'K': return IMM_IN_RANGE (value, 16, 0);
598
    case 'L': return IMM_IN_RANGE (value, 16, 1);
599
    case 'M': return IMM_IN_RANGE (value, 14, 0);
600
    case 'N': return IMM_IN_RANGE (value, 14, 1);
601
    default : return 0;
602
    }
603
}
604
 
605
/* Implement EXTRA_CONSTRAINT macro.  */
606
/* Z        symbol_ref  */
607
int
608
score_extra_constraint (rtx op, char c)
609
{
610
  switch (c)
611
    {
612
    case 'Z':
613
      return GET_CODE (op) == SYMBOL_REF;
614
    default:
615
      gcc_unreachable ();
616
    }
617
}
618
 
619
/* Return truth value on whether or not a given hard register
620
   can support a given mode.  */
621
int
622
score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
623
{
624
  int size = GET_MODE_SIZE (mode);
625
  enum mode_class class = GET_MODE_CLASS (mode);
626
 
627
  if (class == MODE_CC)
628
    return regno == CC_REGNUM;
629
  else if (regno == FRAME_POINTER_REGNUM
630
           || regno == ARG_POINTER_REGNUM)
631
    return class == MODE_INT;
632
  else if (GP_REG_P (regno))
633
    /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1)  */
634
    return !(regno & 1) || (size <= UNITS_PER_WORD);
635
  else if (CE_REG_P (regno))
636
    return (class == MODE_INT
637
            && ((size <= UNITS_PER_WORD)
638
                || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
639
  else
640
    return (class == MODE_INT) && (size <= UNITS_PER_WORD);
641
}
642
 
643
/* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
644
   pointer or argument pointer.  TO is either the stack pointer or
645
   hard frame pointer.  */
646
HOST_WIDE_INT
647
score_initial_elimination_offset (int from,
648
                                  int to ATTRIBUTE_UNUSED)
649
{
650
  struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
651
  switch (from)
652
    {
653
    case ARG_POINTER_REGNUM:
654
      return f->total_size;
655
    case FRAME_POINTER_REGNUM:
656
      return 0;
657
    default:
658
      gcc_unreachable ();
659
    }
660
}
661
 
662
/* Argument support functions.  */
663
 
664
/* Initialize CUMULATIVE_ARGS for a function.  */
665
void
666
score_init_cumulative_args (CUMULATIVE_ARGS *cum,
667
                            tree fntype ATTRIBUTE_UNUSED,
668
                            rtx libname ATTRIBUTE_UNUSED)
669
{
670
  memset (cum, 0, sizeof (CUMULATIVE_ARGS));
671
}
672
 
673
/* Implement FUNCTION_ARG_ADVANCE macro.  */
674
void
675
score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
676
                            tree type, int named)
677
{
678
  struct score_arg_info info;
679
  classify_arg (cum, mode, type, named, &info);
680
  cum->num_gprs = info.reg_offset + info.reg_words;
681
  if (info.stack_words > 0)
682
    cum->stack_words = info.stack_offset + info.stack_words;
683
  cum->arg_number++;
684
}
685
 
686
/* Implement TARGET_ARG_PARTIAL_BYTES macro.  */
687
static int
688
score_arg_partial_bytes (const CUMULATIVE_ARGS *cum,
689
                         enum machine_mode mode, tree type, int named)
690
{
691
  struct score_arg_info info;
692
  classify_arg (cum, mode, type, named, &info);
693
  return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
694
}
695
 
696
/* Implement FUNCTION_ARG macro.  */
697
rtx
698
score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
699
                    tree type, int named)
700
{
701
  struct score_arg_info info;
702
 
703
  if (mode == VOIDmode || !named)
704
    return 0;
705
 
706
  classify_arg (cum, mode, type, named, &info);
707
 
708
  if (info.reg_offset == ARG_REG_NUM)
709
    return 0;
710
 
711
  if (!info.stack_words)
712
    return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
713
  else
714
    {
715
      rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
716
      unsigned int i, part_offset = 0;
717
      for (i = 0; i < info.reg_words; i++)
718
        {
719
          rtx reg;
720
          reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
721
          XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
722
                                                   GEN_INT (part_offset));
723
          part_offset += UNITS_PER_WORD;
724
        }
725
      return ret;
726
    }
727
}
728
 
729
/* Implement FUNCTION_VALUE and LIBCALL_VALUE.  For normal calls,
730
   VALTYPE is the return type and MODE is VOIDmode.  For libcalls,
731
   VALTYPE is null and MODE is the mode of the return value.  */
732
rtx
733
score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
734
                      enum machine_mode mode)
735
{
736
  if (valtype)
737
    {
738
      int unsignedp;
739
      mode = TYPE_MODE (valtype);
740
      unsignedp = TYPE_UNSIGNED (valtype);
741
      mode = promote_mode (valtype, mode, &unsignedp, 1);
742
    }
743
  return gen_rtx_REG (mode, RT_REGNUM);
744
}
745
 
746
/* Implement INITIALIZE_TRAMPOLINE macro.  */
747
void
748
score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
749
{
750
#define FFCACHE          "_flush_cache"
751
#define CODE_SIZE        (TRAMPOLINE_INSNS * UNITS_PER_WORD)
752
 
753
  rtx pfunc, pchain;
754
 
755
  pfunc = plus_constant (ADDR, CODE_SIZE);
756
  pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
757
 
758
  emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
759
  emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
760
  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
761
                     0, VOIDmode, 2,
762
                     ADDR, Pmode,
763
                     GEN_INT (TRAMPOLINE_SIZE), SImode);
764
#undef FFCACHE
765
#undef CODE_SIZE
766
}
767
 
768
/* This function is used to implement REG_MODE_OK_FOR_BASE_P macro.  */
769
int
770
score_regno_mode_ok_for_base_p (int regno, int strict)
771
{
772
  if (regno >= FIRST_PSEUDO_REGISTER)
773
    {
774
      if (!strict)
775
        return 1;
776
      regno = reg_renumber[regno];
777
    }
778
  if (regno == ARG_POINTER_REGNUM
779
      || regno == FRAME_POINTER_REGNUM)
780
    return 1;
781
  return GP_REG_P (regno);
782
}
783
 
784
/* Implement GO_IF_LEGITIMATE_ADDRESS macro.  */
785
int
786
score_address_p (enum machine_mode mode, rtx x, int strict)
787
{
788
  struct score_address_info addr;
789
 
790
  return mda_classify_address (&addr, mode, x, strict);
791
}
792
 
793
/* Copy VALUE to a register and return that register.  If new psuedos
794
   are allowed, copy it into a new register, otherwise use DEST.  */
795
static rtx
796
score_force_temporary (rtx dest, rtx value)
797
{
798
  if (!no_new_pseudos)
799
    return force_reg (Pmode, value);
800
  else
801
    {
802
      emit_move_insn (copy_rtx (dest), value);
803
      return dest;
804
    }
805
}
806
 
807
/* Return a LO_SUM expression for ADDR.  TEMP is as for score_force_temporary
808
   and is used to load the high part into a register.  */
809
static rtx
810
score_split_symbol (rtx temp, rtx addr)
811
{
812
  rtx high = score_force_temporary (temp,
813
                                    gen_rtx_HIGH (Pmode, copy_rtx (addr)));
814
  return gen_rtx_LO_SUM (Pmode, high, addr);
815
}
816
 
817
/* This function is used to implement LEGITIMIZE_ADDRESS.  If *XLOC can
818
   be legitimized in a way that the generic machinery might not expect,
819
   put the new address in *XLOC and return true.  */
820
int
821
score_legitimize_address (rtx *xloc)
822
{
823
  enum score_symbol_type symbol_type;
824
 
825
  if (mda_symbolic_constant_p (*xloc, &symbol_type)
826
      && symbol_type == SYMBOL_GENERAL)
827
    {
828
      *xloc = score_split_symbol (0, *xloc);
829
      return 1;
830
    }
831
 
832
  if (GET_CODE (*xloc) == PLUS
833
      && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
834
    {
835
      rtx reg = XEXP (*xloc, 0);
836
      if (!mda_valid_base_register_p (reg, 0))
837
        reg = copy_to_mode_reg (Pmode, reg);
838
      *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1)));
839
      return 1;
840
    }
841
  return 0;
842
}
843
 
844
/* Return a number assessing the cost of moving a register in class
845
   FROM to class TO. */
846
int
847
score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
848
                          enum reg_class from, enum reg_class to)
849
{
850
  if (GR_REG_CLASS_P (from))
851
    {
852
      if (GR_REG_CLASS_P (to))
853
        return 2;
854
      else if (SP_REG_CLASS_P (to))
855
        return 4;
856
      else if (CP_REG_CLASS_P (to))
857
        return 5;
858
      else if (CE_REG_CLASS_P (to))
859
        return 6;
860
    }
861
  if (GR_REG_CLASS_P (to))
862
    {
863
      if (GR_REG_CLASS_P (from))
864
        return 2;
865
      else if (SP_REG_CLASS_P (from))
866
        return 4;
867
      else if (CP_REG_CLASS_P (from))
868
        return 5;
869
      else if (CE_REG_CLASS_P (from))
870
        return 6;
871
    }
872
  return 12;
873
}
874
 
875
/* Return the number of instructions needed to load a symbol of the
876
   given type into a register.  */
877
static int
878
score_symbol_insns (enum score_symbol_type type)
879
{
880
  switch (type)
881
    {
882
    case SYMBOL_GENERAL:
883
      return 2;
884
 
885
    case SYMBOL_SMALL_DATA:
886
      return 1;
887
    }
888
 
889
  gcc_unreachable ();
890
}
891
 
892
/* Return the number of instructions needed to load or store a value
893
   of mode MODE at X.  Return 0 if X isn't valid for MODE.  */
894
static int
895
score_address_insns (rtx x, enum machine_mode mode)
896
{
897
  struct score_address_info addr;
898
  int factor;
899
 
900
  if (mode == BLKmode)
901
    factor = 1;
902
  else
903
    factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
904
 
905
  if (mda_classify_address (&addr, mode, x, false))
906
    switch (addr.type)
907
      {
908
      case ADD_REG:
909
      case ADD_CONST_INT:
910
        return factor;
911
 
912
      case ADD_SYMBOLIC:
913
        return factor * score_symbol_insns (addr.symbol_type);
914
      }
915
  return 0;
916
}
917
 
918
/* Implement TARGET_RTX_COSTS macro.  */
919
static bool
920
score_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
921
                 int *total)
922
{
923
  enum machine_mode mode = GET_MODE (x);
924
 
925
  switch (code)
926
    {
927
    case CONST_INT:
928
      if (outer_code == SET)
929
        {
930
          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
931
              || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
932
            *total = COSTS_N_INSNS (1);
933
          else
934
            *total = COSTS_N_INSNS (2);
935
        }
936
      else if (outer_code == PLUS || outer_code == MINUS)
937
        {
938
          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
939
            *total = 0;
940
          else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
941
                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
942
            *total = 1;
943
          else
944
            *total = COSTS_N_INSNS (2);
945
        }
946
      else if (outer_code == AND || outer_code == IOR)
947
        {
948
          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
949
            *total = 0;
950
          else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
951
                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
952
            *total = 1;
953
          else
954
            *total = COSTS_N_INSNS (2);
955
        }
956
      else
957
        {
958
          *total = 0;
959
        }
960
      return true;
961
 
962
    case CONST:
963
    case SYMBOL_REF:
964
    case LABEL_REF:
965
    case CONST_DOUBLE:
966
      *total = COSTS_N_INSNS (2);
967
      return true;
968
 
969
    case MEM:
970
      {
971
        /* If the address is legitimate, return the number of
972
           instructions it needs, otherwise use the default handling.  */
973
        int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
974
        if (n > 0)
975
          {
976
            *total = COSTS_N_INSNS (n + 1);
977
            return true;
978
          }
979
        return false;
980
      }
981
 
982
    case FFS:
983
      *total = COSTS_N_INSNS (6);
984
      return true;
985
 
986
    case NOT:
987
      *total = COSTS_N_INSNS (1);
988
      return true;
989
 
990
    case AND:
991
    case IOR:
992
    case XOR:
993
      if (mode == DImode)
994
        {
995
          *total = COSTS_N_INSNS (2);
996
          return true;
997
        }
998
      return false;
999
 
1000
    case ASHIFT:
1001
    case ASHIFTRT:
1002
    case LSHIFTRT:
1003
      if (mode == DImode)
1004
        {
1005
          *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1006
                                  ? 4 : 12);
1007
          return true;
1008
        }
1009
      return false;
1010
 
1011
    case ABS:
1012
      *total = COSTS_N_INSNS (4);
1013
      return true;
1014
 
1015
    case PLUS:
1016
    case MINUS:
1017
      if (mode == DImode)
1018
        {
1019
          *total = COSTS_N_INSNS (4);
1020
          return true;
1021
        }
1022
      *total = COSTS_N_INSNS (1);
1023
      return true;
1024
 
1025
    case NEG:
1026
      if (mode == DImode)
1027
        {
1028
          *total = COSTS_N_INSNS (4);
1029
          return true;
1030
        }
1031
      return false;
1032
 
1033
    case MULT:
1034
      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1035
      return true;
1036
 
1037
    case DIV:
1038
    case MOD:
1039
    case UDIV:
1040
    case UMOD:
1041
      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1042
      return true;
1043
 
1044
    case SIGN_EXTEND:
1045
    case ZERO_EXTEND:
1046
      switch (GET_MODE (XEXP (x, 0)))
1047
        {
1048
        case QImode:
1049
        case HImode:
1050
          if (GET_CODE (XEXP (x, 0)) == MEM)
1051
            {
1052
              *total = COSTS_N_INSNS (2);
1053
 
1054
              if (!TARGET_LITTLE_ENDIAN &&
1055
                  side_effects_p (XEXP (XEXP (x, 0), 0)))
1056
                *total = 100;
1057
            }
1058
          else
1059
            *total = COSTS_N_INSNS (1);
1060
          break;
1061
 
1062
        default:
1063
          *total = COSTS_N_INSNS (1);
1064
          break;
1065
        }
1066
      return true;
1067
 
1068
    default:
1069
      return false;
1070
    }
1071
}
1072
 
1073
/* Implement TARGET_ADDRESS_COST macro.  */
1074
int
1075
score_address_cost (rtx addr)
1076
{
1077
  return score_address_insns (addr, SImode);
1078
}
1079
 
1080
/* Implement ASM_OUTPUT_EXTERNAL macro.  */
1081
int
1082
score_output_external (FILE *file ATTRIBUTE_UNUSED,
1083
                       tree decl, const char *name)
1084
{
1085
  register struct extern_list *p;
1086
 
1087
  if (th_in_small_data_p (decl))
1088
    {
1089
      p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1090
      p->next = extern_head;
1091
      p->name = name;
1092
      p->size = int_size_in_bytes (TREE_TYPE (decl));
1093
      extern_head = p;
1094
    }
1095
  return 0;
1096
}
1097
 
1098
/* Output format asm string.  */
1099
void
1100
score_declare_object (FILE *stream, const char *name,
1101
                      const char *directive, const char *fmt, ...)
1102
{
1103
  va_list ap;
1104
  fputs (directive, stream);
1105
  assemble_name (stream, name);
1106
  va_start (ap, fmt);
1107
  vfprintf (stream, fmt, ap);
1108
  va_end (ap);
1109
}
1110
 
1111
/* Implement RETURN_ADDR_RTX.  Note, we do not support moving
1112
   back to a previous frame.  */
1113
rtx
1114
score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1115
{
1116
  if (count != 0)
1117
    return const0_rtx;
1118
  return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1119
}
1120
 
1121
/* Implement PRINT_OPERAND macro.  */
1122
/* Score-specific operand codes:
1123
   '['        print .set nor1 directive
1124
   ']'        print .set r1 directive
1125
   'U'        print hi part of a CONST_INT rtx
1126
   'E'        print log2(v)
1127
   'F'        print log2(~v)
1128
   'D'        print SFmode const double
1129
   'S'        selectively print "!" if operand is 15bit instruction accessible
1130
   'V'        print "v!" if operand is 15bit instruction accessible, or "lfh!"
1131
   'L'        low  part of DImode reg operand
1132
   'H'        high part of DImode reg operand
1133
   'C'        print part of opcode for a branch condition.  */
1134
void
1135
score_print_operand (FILE *file, rtx op, int c)
1136
{
1137
  enum rtx_code code = -1;
1138
  if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1139
    code = GET_CODE (op);
1140
 
1141
  if (c == '[')
1142
    {
1143
      fprintf (file, ".set r1\n");
1144
    }
1145
  else if (c == ']')
1146
    {
1147
      fprintf (file, "\n\t.set nor1");
1148
    }
1149
  else if (c == 'U')
1150
    {
1151
      gcc_assert (code == CONST_INT);
1152
      fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1153
               (INTVAL (op) >> 16) & 0xffff);
1154
    }
1155
  else if (c == 'D')
1156
    {
1157
      if (GET_CODE (op) == CONST_DOUBLE)
1158
        {
1159
          rtx temp = gen_lowpart (SImode, op);
1160
          gcc_assert (GET_MODE (op) == SFmode);
1161
          fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1162
        }
1163
      else
1164
        output_addr_const (file, op);
1165
    }
1166
  else if (c == 'S')
1167
    {
1168
      gcc_assert (code == REG);
1169
      if (G16_REG_P (REGNO (op)))
1170
        fprintf (file, "!");
1171
    }
1172
  else if (c == 'V')
1173
    {
1174
      gcc_assert (code == REG);
1175
      fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1176
    }
1177
  else if (c == 'C')
1178
    {
1179
      enum machine_mode mode = GET_MODE (XEXP (op, 0));
1180
 
1181
      switch (code)
1182
        {
1183
        case EQ: fputs ("eq", file); break;
1184
        case NE: fputs ("ne", file); break;
1185
        case GT: fputs ("gt", file); break;
1186
        case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1187
        case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1188
        case LE: fputs ("le", file); break;
1189
        case GTU: fputs ("gtu", file); break;
1190
        case GEU: fputs ("cs", file); break;
1191
        case LTU: fputs ("cc", file); break;
1192
        case LEU: fputs ("leu", file); break;
1193
        default:
1194
          output_operand_lossage ("invalid operand for code: '%c'", code);
1195
        }
1196
    }
1197
  else if (c == 'E')
1198
    {
1199
      unsigned HOST_WIDE_INT i;
1200
      unsigned HOST_WIDE_INT pow2mask = 1;
1201
      unsigned HOST_WIDE_INT val;
1202
 
1203
      val = INTVAL (op);
1204
      for (i = 0; i < 32; i++)
1205
        {
1206
          if (val == pow2mask)
1207
            break;
1208
          pow2mask <<= 1;
1209
        }
1210
      gcc_assert (i < 32);
1211
      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1212
    }
1213
  else if (c == 'F')
1214
    {
1215
      unsigned HOST_WIDE_INT i;
1216
      unsigned HOST_WIDE_INT pow2mask = 1;
1217
      unsigned HOST_WIDE_INT val;
1218
 
1219
      val = ~INTVAL (op);
1220
      for (i = 0; i < 32; i++)
1221
        {
1222
          if (val == pow2mask)
1223
            break;
1224
          pow2mask <<= 1;
1225
        }
1226
      gcc_assert (i < 32);
1227
      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1228
    }
1229
  else if (code == REG)
1230
    {
1231
      int regnum = REGNO (op);
1232
      if ((c == 'H' && !WORDS_BIG_ENDIAN)
1233
          || (c == 'L' && WORDS_BIG_ENDIAN))
1234
        regnum ++;
1235
      fprintf (file, "%s", reg_names[regnum]);
1236
    }
1237
  else
1238
    {
1239
      switch (code)
1240
        {
1241
        case MEM:
1242
          score_print_operand_address (file, op);
1243
          break;
1244
        default:
1245
          output_addr_const (file, op);
1246
        }
1247
    }
1248
}
1249
 
1250
/* Implement PRINT_OPERAND_ADDRESS macro.  */
1251
void
1252
score_print_operand_address (FILE *file, rtx x)
1253
{
1254
  struct score_address_info addr;
1255
  enum rtx_code code = GET_CODE (x);
1256
  enum machine_mode mode = GET_MODE (x);
1257
 
1258
  if (code == MEM)
1259
    x = XEXP (x, 0);
1260
 
1261
  if (mda_classify_address (&addr, mode, x, true))
1262
    {
1263
      switch (addr.type)
1264
        {
1265
        case ADD_REG:
1266
          {
1267
            switch (addr.code)
1268
              {
1269
              case PRE_DEC:
1270
                fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1271
                         INTVAL (addr.offset));
1272
                break;
1273
              case POST_DEC:
1274
                fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1275
                         INTVAL (addr.offset));
1276
                break;
1277
              case PRE_INC:
1278
                fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1279
                         INTVAL (addr.offset));
1280
                break;
1281
              case POST_INC:
1282
                fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1283
                         INTVAL (addr.offset));
1284
                break;
1285
              default:
1286
                if (INTVAL(addr.offset) == 0)
1287
                  fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1288
                else
1289
                  fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1290
                          INTVAL(addr.offset));
1291
                break;
1292
              }
1293
          }
1294
          return;
1295
        case ADD_CONST_INT:
1296
        case ADD_SYMBOLIC:
1297
          output_addr_const (file, x);
1298
          return;
1299
        }
1300
    }
1301
  print_rtl (stderr, x);
1302
  gcc_unreachable ();
1303
}
1304
 
1305
/* Implement SELECT_CC_MODE macro.  */
1306
enum machine_mode
1307
score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1308
{
1309
  if ((op == EQ || op == NE || op == LT || op == GE)
1310
      && y == const0_rtx
1311
      && GET_MODE (x) == SImode)
1312
    {
1313
      switch (GET_CODE (x))
1314
        {
1315
        case PLUS:
1316
        case MINUS:
1317
        case NEG:
1318
        case AND:
1319
        case IOR:
1320
        case XOR:
1321
        case NOT:
1322
        case ASHIFT:
1323
        case LSHIFTRT:
1324
        case ASHIFTRT:
1325
          return CC_NZmode;
1326
 
1327
        case SIGN_EXTEND:
1328
        case ZERO_EXTEND:
1329
        case ROTATE:
1330
        case ROTATERT:
1331
          return (op == LT || op == GE) ? CC_Nmode : CCmode;
1332
 
1333
        default:
1334
          return CCmode;
1335
        }
1336
    }
1337
 
1338
  if ((op == EQ || op == NE)
1339
      && (GET_CODE (y) == NEG)
1340
      && register_operand (XEXP (y, 0), SImode)
1341
      && register_operand (x, SImode))
1342
    {
1343
      return CC_NZmode;
1344
    }
1345
 
1346
  return CCmode;
1347
}
1348
 
1349
struct gcc_target targetm = TARGET_INITIALIZER;

powered by: WebSVN 2.1.0

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