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

Subversion Repositories openrisc

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

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

Line No. Rev Author Line
1 709 jeremybenn
/* Subroutines used for code generation on Xilinx MicroBlaze.
2
   Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
3
 
4
   Contributed by Michael Eager <eager@eagercon.com>.
5
 
6
   This file is part of GCC.
7
 
8
   GCC is free software; you can redistribute it and/or modify it
9
   under the terms of the GNU General Public License as published
10
   by the Free Software Foundation; either version 3, or (at your
11
   option) any later version.
12
 
13
   GCC is distributed in the hope that it will be useful, but WITHOUT
14
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16
   License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with GCC; see the file COPYING3.  If not see
20
   <http://www.gnu.org/licenses/>.  */
21
 
22
#include "config.h"
23
#include "system.h"
24
#include "coretypes.h"
25
#include "tm.h"
26
#include "rtl.h"
27
#include "regs.h"
28
#include "hard-reg-set.h"
29
#include "real.h"
30
#include "insn-config.h"
31
#include "conditions.h"
32
#include "insn-flags.h"
33
#include "insn-attr.h"
34
#include "integrate.h"
35
#include "recog.h"
36
#include "tree.h"
37
#include "function.h"
38
#include "expr.h"
39
#include "flags.h"
40
#include "reload.h"
41
#include "output.h"
42
#include "ggc.h"
43
#include "hashtab.h"
44
#include "target.h"
45
#include "target-def.h"
46
#include "tm_p.h"
47
#include "gstab.h"
48
#include "df.h"
49
#include "optabs.h"
50
#include "diagnostic-core.h"
51
 
52
#define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
53
 
54
/* Classifies an address.
55
 
56
ADDRESS_INVALID
57
An invalid address.
58
 
59
ADDRESS_REG
60
 
61
A natural register or a register + const_int offset address.
62
The register satisfies microblaze_valid_base_register_p and the
63
offset is a const_arith_operand.
64
 
65
ADDRESS_REG_INDEX
66
 
67
A natural register offset by the index contained in an index register. The base
68
register satisfies microblaze_valid_base_register_p and the index register
69
satisfies microblaze_valid_index_register_p
70
 
71
ADDRESS_CONST_INT
72
 
73
A signed 16/32-bit constant address.
74
 
75
ADDRESS_SYMBOLIC:
76
 
77
A constant symbolic address or a (register + symbol).  */
78
 
79
enum microblaze_address_type
80
{
81
  ADDRESS_INVALID,
82
  ADDRESS_REG,
83
  ADDRESS_REG_INDEX,
84
  ADDRESS_CONST_INT,
85
  ADDRESS_SYMBOLIC,
86
  ADDRESS_GOTOFF,
87
  ADDRESS_PLT
88
};
89
 
90
/* Classifies symbols
91
 
92
SYMBOL_TYPE_GENERAL
93
 
94
A general symbol.  */
95
enum microblaze_symbol_type
96
{
97
  SYMBOL_TYPE_INVALID,
98
  SYMBOL_TYPE_GENERAL
99
};
100
 
101
/* Classification of a MicroBlaze address.  */
102
struct microblaze_address_info
103
{
104
  enum microblaze_address_type type;
105
  rtx regA;     /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
106
                   ADDRESS_SYMBOLIC.  */
107
  rtx regB;     /* Contains valid values on ADDRESS_REG_INDEX.  */
108
  rtx offset;   /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG.  */
109
  rtx symbol;   /* Contains valid values on ADDRESS_SYMBOLIC.  */
110
  enum microblaze_symbol_type symbol_type;
111
};
112
 
113
/* Structure to be filled in by compute_frame_size with register
114
   save masks, and offsets for the current function.  */
115
 
116
struct GTY(()) microblaze_frame_info {
117
  long total_size;              /* # bytes that the entire frame takes up.  */
118
  long var_size;                /* # bytes that variables take up.  */
119
  long args_size;               /* # bytes that outgoing arguments take up.  */
120
  int link_debug_size;          /* # bytes for the link reg and back pointer.  */
121
  int gp_reg_size;              /* # bytes needed to store gp regs.  */
122
  long gp_offset;               /* offset from new sp to store gp registers.  */
123
  long mask;                    /* mask of saved gp registers.  */
124
  int initialized;              /* != 0 if frame size already calculated.  */
125
  int num_gp;                   /* number of gp registers saved.  */
126
  long insns_len;               /* length of insns.  */
127
  int alloc_stack;              /* Flag to indicate if the current function
128
                                   must not create stack space. (As an optimization).  */
129
};
130
 
131
/* Global variables for machine-dependent things.  */
132
 
133
/* Toggle which pipleline interface to use.  */
134
static GTY(()) int microblaze_sched_use_dfa = 0;
135
 
136
/* Threshold for data being put into the small data/bss area, instead
137
   of the normal data area (references to the small data/bss area take
138
   1 instruction, and use the global pointer, references to the normal
139
   data area takes 2 instructions).  */
140
int microblaze_section_threshold = -1;
141
 
142
/* Prevent scheduling potentially exception causing instructions in
143
   delay slots.  -mcpu=v3.00.a or v4.00.a turns this on.  */
144
int microblaze_no_unsafe_delay;
145
 
146
/* Which CPU pipeline do we use. We haven't really standardized on a CPU
147
   version having only a particular type of pipeline. There can still be
148
   options on the CPU to scale pipeline features up or down. :(
149
   Bad Presentation (??), so we let the MD file rely on the value of
150
   this variable instead Making PIPE_5 the default. It should be backward
151
   optimal with PIPE_3 MicroBlazes.  */
152
enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
153
 
154
/* High and low marks for floating point values which we will accept
155
   as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P.  These are
156
   initialized in override_options.  */
157
REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
158
 
159
/* Array giving truth value on whether or not a given hard register
160
   can support a given mode.  */
161
char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
162
                                  [FIRST_PSEUDO_REGISTER];
163
 
164
/* Current frame information calculated by compute_frame_size.  */
165
struct microblaze_frame_info current_frame_info;
166
 
167
/* Zero structure to initialize current_frame_info.  */
168
struct microblaze_frame_info zero_frame_info;
169
 
170
/* List of all MICROBLAZE punctuation characters used by print_operand.  */
171
char microblaze_print_operand_punct[256];
172
 
173
/* Map GCC register number to debugger register number.  */
174
int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
175
 
176
/* Map hard register number to register class.  */
177
enum reg_class microblaze_regno_to_class[] =
178
{
179
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
180
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
181
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
182
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
183
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
184
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
185
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
186
  GR_REGS,      GR_REGS,        GR_REGS,        GR_REGS,
187
  ST_REGS,      GR_REGS,        GR_REGS,        GR_REGS
188
};
189
 
190
/* MicroBlaze specific machine attributes.
191
   interrupt_handler - Interrupt handler attribute to add interrupt prologue
192
                       and epilogue and use appropriate interrupt return.
193
   save_volatiles    - Similiar to interrupt handler, but use normal return.  */
194
int interrupt_handler;
195
int save_volatiles;
196
 
197
const struct attribute_spec microblaze_attribute_table[] = {
198
  /* name         min_len, max_len, decl_req, type_req, fn_type, req_handler,
199
     affects_type_identity */
200
  {"interrupt_handler", 0,       0,     true,    false,   false,        NULL,
201
    false },
202
  {"save_volatiles"   , 0,       0,     true,    false,   false,        NULL,
203
    false },
204
  { NULL,               0,       0,    false,    false,   false,        NULL,
205
    false }
206
};
207
 
208
static int microblaze_interrupt_function_p (tree);
209
 
210
section *sdata2_section;
211
 
212
/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant.  */
213
static bool
214
microblaze_const_double_ok (rtx op, enum machine_mode mode)
215
{
216
  REAL_VALUE_TYPE d;
217
 
218
  if (GET_CODE (op) != CONST_DOUBLE)
219
    return 0;
220
 
221
  if (GET_MODE (op) == VOIDmode)
222
    return 1;
223
 
224
  if (mode != SFmode && mode != DFmode)
225
    return 0;
226
 
227
  if (op == CONST0_RTX (mode))
228
    return 1;
229
 
230
  REAL_VALUE_FROM_CONST_DOUBLE (d, op);
231
 
232
  if (REAL_VALUE_ISNAN (d))
233
    return FALSE;
234
 
235
  if (REAL_VALUE_NEGATIVE (d))
236
    d = real_value_negate (&d);
237
 
238
  if (mode == DFmode)
239
    {
240
      if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
241
        return 1;
242
    }
243
  else
244
    {
245
      if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
246
        return 1;
247
    }
248
 
249
  return 0;
250
}
251
 
252
/* Return truth value if a memory operand fits in a single instruction
253
   (ie, register + small offset) or (register + register).  */
254
 
255
int
256
simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
257
{
258
  rtx addr, plus0, plus1;
259
 
260
  /* Eliminate non-memory operations.  */
261
  if (GET_CODE (op) != MEM)
262
    return 0;
263
 
264
  /* dword operations really put out 2 instructions, so eliminate them.  */
265
  /* ??? This isn't strictly correct.  It is OK to accept multiword modes
266
     here, since the length attributes are being set correctly, but only
267
     if the address is offsettable.  */
268
  if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
269
    return 0;
270
 
271
 
272
  /* Decode the address now.  */
273
  addr = XEXP (op, 0);
274
  switch (GET_CODE (addr))
275
 
276
    {
277
    case REG:
278
      return 1;
279
 
280
    case PLUS:
281
      plus0 = XEXP (addr, 0);
282
      plus1 = XEXP (addr, 1);
283
 
284
      if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
285
          && SMALL_INT (plus1))
286
        {
287
          return 1;
288
        }
289
      else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
290
        {
291
          return 1;
292
        }
293
      else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
294
        {
295
          return 1;
296
        }
297
      else
298
        return 0;
299
 
300
    case SYMBOL_REF:
301
      return 0;
302
 
303
    default:
304
      break;
305
    }
306
 
307
  return 0;
308
}
309
 
310
/* Return nonzero for a memory address that can be used to load or store
311
   a doubleword.  */
312
 
313
int
314
double_memory_operand (rtx op, enum machine_mode mode)
315
{
316
  rtx addr;
317
 
318
  if (GET_CODE (op) != MEM || !memory_operand (op, mode))
319
    {
320
      /* During reload, we accept a pseudo register if it has an
321
         appropriate memory address.  If we don't do this, we will
322
         wind up reloading into a register, and then reloading that
323
         register from memory, when we could just reload directly from
324
         memory.  */
325
      if (reload_in_progress
326
          && GET_CODE (op) == REG
327
          && REGNO (op) >= FIRST_PSEUDO_REGISTER
328
          && reg_renumber[REGNO (op)] < 0
329
          && reg_equiv_mem (REGNO (op)) != 0
330
          && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
331
        return 1;
332
      return 0;
333
    }
334
 
335
  /* Make sure that 4 added to the address is a valid memory address.
336
     This essentially just checks for overflow in an added constant.  */
337
 
338
  addr = XEXP (op, 0);
339
 
340
  if (CONSTANT_ADDRESS_P (addr))
341
    return 1;
342
 
343
  return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
344
                            ? SImode : SFmode), plus_constant (addr, 4));
345
}
346
 
347
/* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P.  */
348
int
349
microblaze_regno_ok_for_base_p (int regno, int strict)
350
{
351
  if (regno >= FIRST_PSEUDO_REGISTER)
352
    {
353
      if (!strict)
354
        return true;
355
      regno = reg_renumber[regno];
356
    }
357
 
358
  /* These fake registers will be eliminated to either the stack or
359
     hard frame pointer, both of which are usually valid base registers.
360
     Reload deals with the cases where the eliminated form isn't valid.  */
361
  if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
362
    return true;
363
 
364
  return GP_REG_P (regno);
365
}
366
 
367
/* Return true if X is a valid base register for the given mode.
368
   Allow only hard registers if STRICT.  */
369
 
370
static bool
371
microblaze_valid_base_register_p (rtx x,
372
                                  enum machine_mode mode ATTRIBUTE_UNUSED,
373
                                  int strict)
374
{
375
  if (!strict && GET_CODE (x) == SUBREG)
376
    x = SUBREG_REG (x);
377
 
378
  return (GET_CODE (x) == REG
379
          && microblaze_regno_ok_for_base_p (REGNO (x), strict));
380
}
381
 
382
static bool
383
microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
384
{
385
  info->symbol_type = SYMBOL_TYPE_GENERAL;
386
  info->symbol = XVECEXP (x, 0, 0);
387
 
388
  if (XINT (x, 1) == UNSPEC_GOTOFF)
389
    {
390
      info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
391
      info->type = ADDRESS_GOTOFF;
392
    }
393
  else if (XINT (x, 1) == UNSPEC_PLT)
394
    {
395
      info->type = ADDRESS_PLT;
396
    }
397
  else
398
    {
399
      return false;
400
    }
401
  return true;
402
}
403
 
404
 
405
/* Return true if X is a valid index register for the given mode.
406
   Allow only hard registers if STRICT.  */
407
 
408
static bool
409
microblaze_valid_index_register_p (rtx x,
410
                                   enum machine_mode mode ATTRIBUTE_UNUSED,
411
                                   int strict)
412
{
413
  if (!strict && GET_CODE (x) == SUBREG)
414
    x = SUBREG_REG (x);
415
 
416
  return (GET_CODE (x) == REG
417
          /* A base register is good enough to be an index register on MicroBlaze.  */
418
          && microblaze_regno_ok_for_base_p (REGNO (x), strict));
419
}
420
 
421
/* Get the base register for accessing a value from the memory or
422
   Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization.  */
423
static int
424
get_base_reg (rtx x)
425
{
426
  tree decl;
427
  int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM);
428
 
429
  if (TARGET_XLGPOPT
430
      && GET_CODE (x) == SYMBOL_REF
431
      && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
432
    {
433
      if (TREE_READONLY (decl))
434
        base_reg = MB_ABI_GPRO_REGNUM;
435
      else
436
        base_reg = MB_ABI_GPRW_REGNUM;
437
    }
438
 
439
  return base_reg;
440
}
441
 
442
/* Return true if X is a valid address for machine mode MODE.  If it is,
443
   fill in INFO appropriately.  STRICT is true if we should only accept
444
   hard base registers.
445
 
446
      type                     regA      regB    offset      symbol
447
 
448
   ADDRESS_INVALID             NULL      NULL     NULL        NULL
449
 
450
   ADDRESS_REG                 %0        NULL     const_0 /   NULL
451
                                                  const_int
452
   ADDRESS_REG_INDEX           %0        %1       NULL        NULL
453
 
454
   ADDRESS_SYMBOLIC            r0 /      NULL     NULL        symbol
455
                           sda_base_reg
456
 
457
   ADDRESS_CONST_INT           r0       NULL      const       NULL
458
 
459
   For modes spanning multiple registers (DFmode in 32-bit GPRs,
460
   DImode, TImode), indexed addressing cannot be used because
461
   adjacent memory cells are accessed by adding word-sized offsets
462
   during assembly output.  */
463
 
464
static bool
465
microblaze_classify_address (struct microblaze_address_info *info, rtx x,
466
                             enum machine_mode mode, int strict)
467
{
468
  rtx xplus0;
469
  rtx xplus1;
470
 
471
  info->type = ADDRESS_INVALID;
472
  info->regA = NULL;
473
  info->regB = NULL;
474
  info->offset = NULL;
475
  info->symbol = NULL;
476
  info->symbol_type = SYMBOL_TYPE_INVALID;
477
 
478
  switch (GET_CODE (x))
479
    {
480
    case REG:
481
    case SUBREG:
482
      {
483
        info->type = ADDRESS_REG;
484
        info->regA = x;
485
        info->offset = const0_rtx;
486
        return microblaze_valid_base_register_p (info->regA, mode, strict);
487
      }
488
    case PLUS:
489
      {
490
        xplus0 = XEXP (x, 0);
491
        xplus1 = XEXP (x, 1);
492
 
493
        if (microblaze_valid_base_register_p (xplus0, mode, strict))
494
          {
495
            info->type = ADDRESS_REG;
496
            info->regA = xplus0;
497
 
498
            if (GET_CODE (xplus1) == CONST_INT)
499
              {
500
                info->offset = xplus1;
501
                return true;
502
              }
503
            else if (GET_CODE (xplus1) == UNSPEC)
504
              {
505
                return microblaze_classify_unspec (info, xplus1);
506
              }
507
            else if ((GET_CODE (xplus1) == SYMBOL_REF ||
508
                      GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2)
509
              {
510
                return false;
511
              }
512
            else if (GET_CODE (xplus1) == SYMBOL_REF ||
513
                     GET_CODE (xplus1) == LABEL_REF ||
514
                     GET_CODE (xplus1) == CONST)
515
              {
516
                if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC)
517
                  return microblaze_classify_unspec (info, XEXP (xplus1, 0));
518
                else if (flag_pic == 2)
519
                  {
520
                    return false;
521
                  }
522
                info->type = ADDRESS_SYMBOLIC;
523
                info->symbol = xplus1;
524
                info->symbol_type = SYMBOL_TYPE_GENERAL;
525
                return true;
526
              }
527
            else if (GET_CODE (xplus1) == REG
528
                     && microblaze_valid_index_register_p (xplus1, mode,
529
                                                           strict)
530
                     && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
531
              {
532
                /* Restrict larger than word-width modes from using an index register.  */
533
                info->type = ADDRESS_REG_INDEX;
534
                info->regB = xplus1;
535
                return true;
536
              }
537
          }
538
        break;
539
      }
540
    case CONST_INT:
541
      {
542
        info->regA = gen_rtx_raw_REG (mode, 0);
543
        info->type = ADDRESS_CONST_INT;
544
        info->offset = x;
545
        return true;
546
      }
547
    case CONST:
548
    case LABEL_REF:
549
    case SYMBOL_REF:
550
      {
551
        info->type = ADDRESS_SYMBOLIC;
552
        info->symbol_type = SYMBOL_TYPE_GENERAL;
553
        info->symbol = x;
554
        info->regA = gen_rtx_raw_REG (mode, get_base_reg (x));
555
 
556
        if (GET_CODE (x) == CONST)
557
          {
558
            return !(flag_pic && pic_address_needs_scratch (x));
559
          }
560
        else if (flag_pic == 2)
561
          {
562
            return false;
563
          }
564
 
565
        return true;
566
      }
567
 
568
    case UNSPEC:
569
      {
570
        if (reload_in_progress)
571
          df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
572
        return microblaze_classify_unspec (info, x);
573
      }
574
 
575
    default:
576
      return false;
577
    }
578
 
579
  return false;
580
}
581
 
582
/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS.  It
583
   returns a nonzero value if X is a legitimate address for a memory
584
   operand of the indicated MODE.  STRICT is nonzero if this function
585
   is called during reload.  */
586
 
587
bool
588
microblaze_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
589
{
590
  struct microblaze_address_info addr;
591
 
592
  return microblaze_classify_address (&addr, x, mode, strict);
593
}
594
 
595
 
596
/* Try machine-dependent ways of modifying an illegitimate address
597
   to be legitimate.  If we find one, return the new, valid address.
598
   This is used from only one place: `memory_address' in explow.c.
599
 
600
   OLDX is the address as it was before break_out_memory_refs was
601
   called.  In some cases it is useful to look at this to decide what
602
   needs to be done.
603
 
604
   It is always safe for this function to do nothing.  It exists to
605
   recognize opportunities to optimize the output.
606
 
607
   For the MicroBlaze, transform:
608
 
609
   memory(X + <large int>)
610
 
611
   into:
612
 
613
   Y = <large int> & ~0x7fff;
614
   Z = X + Y
615
   memory (Z + (<large int> & 0x7fff));
616
 
617
   This is for CSE to find several similar references, and only use one Z.
618
 
619
   When PIC, convert addresses of the form memory (symbol+large int) to
620
   memory (reg+large int).  */
621
 
622
static rtx
623
microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
624
                               enum machine_mode mode ATTRIBUTE_UNUSED)
625
{
626
  register rtx xinsn = x, result;
627
 
628
  if (GET_CODE (xinsn) == CONST
629
      && flag_pic && pic_address_needs_scratch (xinsn))
630
    {
631
      rtx ptr_reg = gen_reg_rtx (Pmode);
632
      rtx constant = XEXP (XEXP (xinsn, 0), 1);
633
 
634
      emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
635
 
636
      result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
637
      if (SMALL_INT (constant))
638
        return result;
639
      /* Otherwise we fall through so the code below will fix the
640
         constant.  */
641
      xinsn = result;
642
    }
643
 
644
  if (GET_CODE (xinsn) == PLUS)
645
    {
646
      register rtx xplus0 = XEXP (xinsn, 0);
647
      register rtx xplus1 = XEXP (xinsn, 1);
648
      register enum rtx_code code0 = GET_CODE (xplus0);
649
      register enum rtx_code code1 = GET_CODE (xplus1);
650
 
651
      if (code0 != REG && code1 == REG)
652
        {
653
          xplus0 = XEXP (xinsn, 1);
654
          xplus1 = XEXP (xinsn, 0);
655
          code0 = GET_CODE (xplus0);
656
          code1 = GET_CODE (xplus1);
657
        }
658
 
659
      if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
660
          && code1 == CONST_INT && !SMALL_INT (xplus1))
661
        {
662
          rtx int_reg = gen_reg_rtx (Pmode);
663
          rtx ptr_reg = gen_reg_rtx (Pmode);
664
 
665
          emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
666
 
667
          emit_insn (gen_rtx_SET (VOIDmode,
668
                                  ptr_reg,
669
                                  gen_rtx_PLUS (Pmode, xplus0, int_reg)));
670
 
671
          result = gen_rtx_PLUS (Pmode, ptr_reg,
672
                                 GEN_INT (INTVAL (xplus1) & 0x7fff));
673
          return result;
674
        }
675
 
676
      if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2)
677
        {
678
          if (reload_in_progress)
679
            df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
680
          if (code1 == CONST)
681
            {
682
              xplus1 = XEXP (xplus1, 0);
683
              code1 = GET_CODE (xplus1);
684
            }
685
          if (code1 == SYMBOL_REF)
686
            {
687
              result =
688
                gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF);
689
              result = gen_rtx_CONST (Pmode, result);
690
              result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
691
              result = gen_const_mem (Pmode, result);
692
              result = gen_rtx_PLUS (Pmode, xplus0, result);
693
              return result;
694
            }
695
        }
696
    }
697
 
698
  if (GET_CODE (xinsn) == SYMBOL_REF)
699
    {
700
      if (reload_in_progress)
701
        df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
702
      result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
703
      result = gen_rtx_CONST (Pmode, result);
704
      result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
705
      result = gen_const_mem (Pmode, result);
706
      return result;
707
    }
708
 
709
  return x;
710
}
711
 
712
/* Block Moves.  */
713
 
714
#define MAX_MOVE_REGS 8
715
#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
716
 
717
/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
718
   Assume that the areas do not overlap.  */
719
 
720
static void
721
microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
722
{
723
  HOST_WIDE_INT offset, delta;
724
  unsigned HOST_WIDE_INT bits;
725
  int i;
726
  enum machine_mode mode;
727
  rtx *regs;
728
 
729
  bits = BITS_PER_WORD;
730
  mode = mode_for_size (bits, MODE_INT, 0);
731
  delta = bits / BITS_PER_UNIT;
732
 
733
  /* Allocate a buffer for the temporary registers.  */
734
  regs = XALLOCAVEC (rtx, length / delta);
735
 
736
  /* Load as many BITS-sized chunks as possible.  Use a normal load if
737
     the source has enough alignment, otherwise use left/right pairs.  */
738
  for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
739
    {
740
      regs[i] = gen_reg_rtx (mode);
741
      emit_move_insn (regs[i], adjust_address (src, mode, offset));
742
    }
743
 
744
  /* Copy the chunks to the destination.  */
745
  for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
746
    emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
747
 
748
  /* Mop up any left-over bytes.  */
749
  if (offset < length)
750
    {
751
      src = adjust_address (src, BLKmode, offset);
752
      dest = adjust_address (dest, BLKmode, offset);
753
      move_by_pieces (dest, src, length - offset,
754
                      MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
755
    }
756
}
757
 
758
/* Helper function for doing a loop-based block operation on memory
759
   reference MEM.  Each iteration of the loop will operate on LENGTH
760
   bytes of MEM.
761
 
762
   Create a new base register for use within the loop and point it to
763
   the start of MEM.  Create a new memory reference that uses this
764
   register.  Store them in *LOOP_REG and *LOOP_MEM respectively.  */
765
 
766
static void
767
microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
768
                             rtx * loop_reg, rtx * loop_mem)
769
{
770
  *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
771
 
772
  /* Although the new mem does not refer to a known location,
773
     it does keep up to LENGTH bytes of alignment.  */
774
  *loop_mem = change_address (mem, BLKmode, *loop_reg);
775
  set_mem_align (*loop_mem,
776
                 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
777
                      length * BITS_PER_UNIT));
778
}
779
 
780
 
781
/* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
782
   per iteration.  LENGTH must be at least MAX_MOVE_BYTES.  Assume that the
783
   memory regions do not overlap.  */
784
 
785
static void
786
microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
787
{
788
  rtx label, src_reg, dest_reg, final_src;
789
  HOST_WIDE_INT leftover;
790
 
791
  leftover = length % MAX_MOVE_BYTES;
792
  length -= leftover;
793
 
794
  /* Create registers and memory references for use within the loop.  */
795
  microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
796
  microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
797
 
798
  /* Calculate the value that SRC_REG should have after the last iteration
799
     of the loop.  */
800
  final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
801
                                   0, 0, OPTAB_WIDEN);
802
 
803
  /* Emit the start of the loop.  */
804
  label = gen_label_rtx ();
805
  emit_label (label);
806
 
807
  /* Emit the loop body.  */
808
  microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
809
 
810
  /* Move on to the next block.  */
811
  emit_move_insn (src_reg, plus_constant (src_reg, MAX_MOVE_BYTES));
812
  emit_move_insn (dest_reg, plus_constant (dest_reg, MAX_MOVE_BYTES));
813
 
814
  /* Emit the test & branch.  */
815
  emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
816
                             src_reg, final_src, label));
817
 
818
  /* Mop up any left-over bytes.  */
819
  if (leftover)
820
    microblaze_block_move_straight (dest, src, leftover);
821
}
822
 
823
/* Expand a movmemsi instruction.  */
824
 
825
bool
826
microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
827
{
828
 
829
  if (GET_CODE (length) == CONST_INT)
830
    {
831
      HOST_WIDE_INT bytes = INTVAL (length);
832
      int align = INTVAL (align_rtx);
833
 
834
      if (align > UNITS_PER_WORD)
835
        {
836
          align = UNITS_PER_WORD;       /* We can't do any better.  */
837
        }
838
      else if (align < UNITS_PER_WORD)
839
        {
840
          if (INTVAL (length) <= MAX_MOVE_BYTES)
841
            {
842
              move_by_pieces (dest, src, bytes, align, 0);
843
              return true;
844
            }
845
          else
846
            return false;
847
        }
848
 
849
      if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
850
        {
851
          microblaze_block_move_straight (dest, src, INTVAL (length));
852
          return true;
853
        }
854
      else if (optimize)
855
        {
856
          microblaze_block_move_loop (dest, src, INTVAL (length));
857
          return true;
858
        }
859
    }
860
  return false;
861
}
862
 
863
static bool
864
microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
865
                      int opno ATTRIBUTE_UNUSED, int *total,
866
                      bool speed ATTRIBUTE_UNUSED)
867
{
868
  enum machine_mode mode = GET_MODE (x);
869
 
870
  switch (code)
871
    {
872
    case MEM:
873
      {
874
        int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
875
        if (simple_memory_operand (x, mode))
876
          *total = COSTS_N_INSNS (2 * num_words);
877
        else
878
          *total = COSTS_N_INSNS (2 * (2 * num_words));
879
 
880
        return true;
881
      }
882
    case NOT:
883
      {
884
        if (mode == DImode)
885
          {
886
            *total = COSTS_N_INSNS (2);
887
          }
888
        else
889
          *total = COSTS_N_INSNS (1);
890
        return false;
891
      }
892
    case AND:
893
    case IOR:
894
    case XOR:
895
      {
896
        if (mode == DImode)
897
          {
898
            *total = COSTS_N_INSNS (2);
899
          }
900
        else
901
          *total = COSTS_N_INSNS (1);
902
 
903
        return false;
904
      }
905
    case ASHIFT:
906
    case ASHIFTRT:
907
    case LSHIFTRT:
908
      {
909
        if (TARGET_BARREL_SHIFT)
910
          {
911
            if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
912
                >= 0)
913
              *total = COSTS_N_INSNS (1);
914
            else
915
              *total = COSTS_N_INSNS (2);
916
          }
917
        else if (!TARGET_SOFT_MUL)
918
          *total = COSTS_N_INSNS (1);
919
        else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
920
          {
921
            /* Add 1 to make shift slightly more expensive than add.  */
922
            *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
923
            /* Reduce shift costs for special circumstances.  */
924
            if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
925
              *total -= 2;
926
            if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
927
              *total -= 2;
928
          }
929
        else
930
          /* Double the worst cost of shifts when there is no barrel shifter and
931
             the shift amount is in a reg.  */
932
          *total = COSTS_N_INSNS (32 * 4);
933
        return true;
934
      }
935
    case PLUS:
936
    case MINUS:
937
      {
938
        if (mode == SFmode || mode == DFmode)
939
          {
940
            if (TARGET_HARD_FLOAT)
941
              *total = COSTS_N_INSNS (6);
942
            return true;
943
          }
944
        else if (mode == DImode)
945
          {
946
            *total = COSTS_N_INSNS (4);
947
            return true;
948
          }
949
        else
950
          {
951
            *total = COSTS_N_INSNS (1);
952
            return true;
953
          }
954
 
955
        return false;
956
      }
957
    case NEG:
958
      {
959
        if (mode == DImode)
960
          *total = COSTS_N_INSNS (4);
961
 
962
        return false;
963
      }
964
    case MULT:
965
      {
966
        if (mode == SFmode)
967
          {
968
            if (TARGET_HARD_FLOAT)
969
              *total = COSTS_N_INSNS (6);
970
          }
971
        else if (!TARGET_SOFT_MUL)
972
          {
973
            if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
974
                >= 0)
975
              *total = COSTS_N_INSNS (1);
976
            else
977
              *total = COSTS_N_INSNS (3);
978
          }
979
        else
980
          *total = COSTS_N_INSNS (10);
981
        return true;
982
      }
983
    case DIV:
984
    case UDIV:
985
      {
986
        if (mode == SFmode)
987
          {
988
            if (TARGET_HARD_FLOAT)
989
              *total = COSTS_N_INSNS (23);
990
          }
991
        return false;
992
      }
993
    case SIGN_EXTEND:
994
      {
995
        *total = COSTS_N_INSNS (1);
996
        return false;
997
      }
998
    case ZERO_EXTEND:
999
      {
1000
        *total = COSTS_N_INSNS (1);
1001
        return false;
1002
      }
1003
    }
1004
 
1005
  return false;
1006
}
1007
 
1008
/* Return the number of instructions needed to load or store a value
1009
   of mode MODE at X.  Return 0 if X isn't valid for MODE.  */
1010
 
1011
static int
1012
microblaze_address_insns (rtx x, enum machine_mode mode)
1013
{
1014
  struct microblaze_address_info addr;
1015
 
1016
  if (microblaze_classify_address (&addr, x, mode, false))
1017
    {
1018
      switch (addr.type)
1019
        {
1020
        case ADDRESS_REG:
1021
          if (SMALL_INT (addr.offset))
1022
            return 1;
1023
          else
1024
            return 2;
1025
        case ADDRESS_CONST_INT:
1026
          if (SMALL_INT (x))
1027
            return 1;
1028
          else
1029
            return 2;
1030
        case ADDRESS_REG_INDEX:
1031
        case ADDRESS_SYMBOLIC:
1032
          return 1;
1033
        case ADDRESS_GOTOFF:
1034
          return 2;
1035
        default:
1036
          break;
1037
        }
1038
    }
1039
  return 0;
1040
}
1041
 
1042
/* Provide the costs of an addressing mode that contains ADDR.
1043
   If ADDR is not a valid address, its cost is irrelevant.  */
1044
static int
1045
microblaze_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
1046
{
1047
  return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1048
}
1049
 
1050
/* Return nonzero if X is an address which needs a temporary register when
1051
   reloaded while generating PIC code.  */
1052
 
1053
int
1054
pic_address_needs_scratch (rtx x)
1055
{
1056
  /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
1057
  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
1058
      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
1059
      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
1060
      && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1))))
1061
    return 1;
1062
 
1063
  return 0;
1064
}
1065
 
1066
/* Argument support functions.  */
1067
/* Initialize CUMULATIVE_ARGS for a function.  */
1068
 
1069
void
1070
init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1071
                      rtx libname ATTRIBUTE_UNUSED)
1072
{
1073
  static CUMULATIVE_ARGS zero_cum;
1074
  tree param, next_param;
1075
 
1076
  *cum = zero_cum;
1077
 
1078
  /* Determine if this function has variable arguments.  This is
1079
     indicated by the last argument being 'void_type_mode' if there
1080
     are no variable arguments.  The standard MicroBlaze calling sequence
1081
     passes all arguments in the general purpose registers in this case. */
1082
 
1083
  for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1084
       param != 0; param = next_param)
1085
    {
1086
      next_param = TREE_CHAIN (param);
1087
      if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1088
        cum->gp_reg_found = 1;
1089
    }
1090
}
1091
 
1092
/* Advance the argument to the next argument position.  */
1093
 
1094
static void
1095
microblaze_function_arg_advance (cumulative_args_t cum_v,
1096
                                 enum machine_mode mode,
1097
                                 const_tree type, bool named ATTRIBUTE_UNUSED)
1098
{
1099
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1100
 
1101
  cum->arg_number++;
1102
  switch (mode)
1103
    {
1104
    case VOIDmode:
1105
      break;
1106
 
1107
    default:
1108
      gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1109
          || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1110
 
1111
      cum->gp_reg_found = 1;
1112
      cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1113
                         / UNITS_PER_WORD);
1114
      break;
1115
 
1116
    case BLKmode:
1117
      cum->gp_reg_found = 1;
1118
      cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1119
                         / UNITS_PER_WORD);
1120
      break;
1121
 
1122
    case SFmode:
1123
      cum->arg_words++;
1124
      if (!cum->gp_reg_found && cum->arg_number <= 2)
1125
        cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1126
      break;
1127
 
1128
    case DFmode:
1129
      cum->arg_words += 2;
1130
      if (!cum->gp_reg_found && cum->arg_number <= 2)
1131
        cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1132
      break;
1133
 
1134
    case DImode:
1135
      cum->gp_reg_found = 1;
1136
      cum->arg_words += 2;
1137
      break;
1138
 
1139
    case QImode:
1140
    case HImode:
1141
    case SImode:
1142
    case TImode:
1143
      cum->gp_reg_found = 1;
1144
      cum->arg_words++;
1145
      break;
1146
    }
1147
}
1148
 
1149
/* Return an RTL expression containing the register for the given mode,
1150
   or 0 if the argument is to be passed on the stack.  */
1151
 
1152
static rtx
1153
microblaze_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
1154
                         const_tree type ATTRIBUTE_UNUSED,
1155
                         bool named ATTRIBUTE_UNUSED)
1156
{
1157
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1158
 
1159
  rtx ret;
1160
  int regbase = -1;
1161
  int *arg_words = &cum->arg_words;
1162
 
1163
  cum->last_arg_fp = 0;
1164
  switch (mode)
1165
    {
1166
    case SFmode:
1167
    case DFmode:
1168
    case VOIDmode:
1169
    case QImode:
1170
    case HImode:
1171
    case SImode:
1172
    case DImode:
1173
    case TImode:
1174
      regbase = GP_ARG_FIRST;
1175
      break;
1176
    default:
1177
      gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1178
          || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1179
      /* Drops through.  */
1180
    case BLKmode:
1181
      regbase = GP_ARG_FIRST;
1182
      break;
1183
    }
1184
 
1185
  if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1186
    ret = 0;
1187
  else
1188
    {
1189
      gcc_assert (regbase != -1);
1190
 
1191
      ret = gen_rtx_REG (mode, regbase + *arg_words);
1192
    }
1193
 
1194
  if (mode == VOIDmode)
1195
    {
1196
      if (cum->num_adjusts > 0)
1197
        ret = gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code,
1198
                                gen_rtvec_v (cum->num_adjusts, cum->adjust));
1199
    }
1200
 
1201
  return ret;
1202
}
1203
 
1204
/* Return number of bytes of argument to put in registers. */
1205
static int
1206
function_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode,
1207
                            tree type, bool named ATTRIBUTE_UNUSED)
1208
{
1209
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1210
 
1211
  if ((mode == BLKmode
1212
       || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1213
       || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1214
      && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1215
    {
1216
      int words;
1217
      if (mode == BLKmode)
1218
        words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1219
                 / UNITS_PER_WORD);
1220
      else
1221
        words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1222
 
1223
      if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1224
        return 0;                /* structure fits in registers */
1225
 
1226
      return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1227
    }
1228
 
1229
  else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1230
    return UNITS_PER_WORD;
1231
 
1232
  return 0;
1233
}
1234
 
1235
/*  Convert a version number of the form "vX.YY.Z" to an integer encoding
1236
    for easier range comparison.  */
1237
static int
1238
microblaze_version_to_int (const char *version)
1239
{
1240
  const char *p, *v;
1241
  const char *tmpl = "vX.YY.Z";
1242
  int iver = 0;
1243
 
1244
  p = version;
1245
  v = tmpl;
1246
 
1247
  while (*v)
1248
    {
1249
      if (*v == 'X')
1250
        {                       /* Looking for major  */
1251
          if (!(*p >= '0' && *p <= '9'))
1252
            return -1;
1253
          iver += (int) (*p - '0');
1254
          iver *= 10;
1255
        }
1256
      else if (*v == 'Y')
1257
        {                       /* Looking for minor  */
1258
          if (!(*p >= '0' && *p <= '9'))
1259
            return -1;
1260
          iver += (int) (*p - '0');
1261
          iver *= 10;
1262
        }
1263
      else if (*v == 'Z')
1264
        {                       /* Looking for compat  */
1265
          if (!(*p >= 'a' && *p <= 'z'))
1266
            return -1;
1267
          iver *= 10;
1268
          iver += (int) (*p - 'a');
1269
        }
1270
      else
1271
        {
1272
          if (*p != *v)
1273
            return -1;
1274
        }
1275
 
1276
      v++;
1277
      p++;
1278
    }
1279
 
1280
  if (*p)
1281
    return -1;
1282
 
1283
  return iver;
1284
}
1285
 
1286
 
1287
static void
1288
microblaze_option_override (void)
1289
{
1290
  register int i, start;
1291
  register int regno;
1292
  register enum machine_mode mode;
1293
  int ver;
1294
 
1295
  microblaze_section_threshold = (global_options_set.x_g_switch_value
1296
                                  ? g_switch_value
1297
                                  : MICROBLAZE_DEFAULT_GVALUE);
1298
 
1299
  /* Check the MicroBlaze CPU version for any special action to be done.  */
1300
  if (microblaze_select_cpu == NULL)
1301
    microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1302
  ver = microblaze_version_to_int (microblaze_select_cpu);
1303
  if (ver == -1)
1304
    {
1305
      error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1306
    }
1307
 
1308
  ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1309
  if (ver < 0)
1310
    {
1311
      /* No hardware exceptions in earlier versions. So no worries.  */
1312
#if 0
1313
      microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1314
#endif
1315
      microblaze_no_unsafe_delay = 0;
1316
      microblaze_pipe = MICROBLAZE_PIPE_3;
1317
    }
1318
  else if (ver == 0
1319
           || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1320
               == 0))
1321
    {
1322
#if 0
1323
      microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1324
#endif
1325
      microblaze_no_unsafe_delay = 1;
1326
      microblaze_pipe = MICROBLAZE_PIPE_3;
1327
    }
1328
  else
1329
    {
1330
      /* We agree to use 5 pipe-stage model even on area optimized 3
1331
         pipe-stage variants.  */
1332
#if 0
1333
      microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1334
#endif
1335
      microblaze_no_unsafe_delay = 0;
1336
      microblaze_pipe = MICROBLAZE_PIPE_5;
1337
      if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1338
          || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1339
                                         "v5.00.b") == 0
1340
          || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1341
                                         "v5.00.c") == 0)
1342
        {
1343
          /* Pattern compares are to be turned on by default only when
1344
             compiling for MB v5.00.'z'.  */
1345
          target_flags |= MASK_PATTERN_COMPARE;
1346
        }
1347
    }
1348
 
1349
  ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1350
  if (ver < 0)
1351
    {
1352
      if (TARGET_MULTIPLY_HIGH)
1353
        warning (0,
1354
                 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1355
    }
1356
 
1357
  if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1358
    error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1359
 
1360
  /* Always use DFA scheduler.  */
1361
  microblaze_sched_use_dfa = 1;
1362
 
1363
#if 0
1364
  microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1365
#endif
1366
 
1367
  /* Initialize the high, low values for legit floating point constants.  */
1368
  real_maxval (&dfhigh, 0, DFmode);
1369
  real_maxval (&dflow, 1, DFmode);
1370
  real_maxval (&sfhigh, 0, SFmode);
1371
  real_maxval (&sflow, 1, SFmode);
1372
 
1373
  microblaze_print_operand_punct['?'] = 1;
1374
  microblaze_print_operand_punct['#'] = 1;
1375
  microblaze_print_operand_punct['&'] = 1;
1376
  microblaze_print_operand_punct['!'] = 1;
1377
  microblaze_print_operand_punct['*'] = 1;
1378
  microblaze_print_operand_punct['@'] = 1;
1379
  microblaze_print_operand_punct['.'] = 1;
1380
  microblaze_print_operand_punct['('] = 1;
1381
  microblaze_print_operand_punct[')'] = 1;
1382
  microblaze_print_operand_punct['['] = 1;
1383
  microblaze_print_operand_punct[']'] = 1;
1384
  microblaze_print_operand_punct['<'] = 1;
1385
  microblaze_print_operand_punct['>'] = 1;
1386
  microblaze_print_operand_punct['{'] = 1;
1387
  microblaze_print_operand_punct['}'] = 1;
1388
  microblaze_print_operand_punct['^'] = 1;
1389
  microblaze_print_operand_punct['$'] = 1;
1390
  microblaze_print_operand_punct['+'] = 1;
1391
 
1392
  /* Set up array to map GCC register number to debug register number.
1393
     Ignore the special purpose register numbers.  */
1394
 
1395
  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1396
    microblaze_dbx_regno[i] = -1;
1397
 
1398
  start = GP_DBX_FIRST - GP_REG_FIRST;
1399
  for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1400
    microblaze_dbx_regno[i] = i + start;
1401
 
1402
  /* Set up array giving whether a given register can hold a given mode.   */
1403
 
1404
  for (mode = VOIDmode;
1405
       mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1))
1406
    {
1407
      register int size = GET_MODE_SIZE (mode);
1408
 
1409
      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1410
        {
1411
          register int ok;
1412
 
1413
          if (mode == CCmode)
1414
            {
1415
              ok = (ST_REG_P (regno) || GP_REG_P (regno));
1416
            }
1417
          else if (GP_REG_P (regno))
1418
            ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1419
          else
1420
            ok = 0;
1421
 
1422
          microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1423
        }
1424
    }
1425
}
1426
 
1427
/* Return true if FUNC is an interrupt function as specified
1428
   by the "interrupt_handler" attribute.  */
1429
 
1430
static int
1431
microblaze_interrupt_function_p (tree func)
1432
{
1433
  tree a;
1434
 
1435
  if (TREE_CODE (func) != FUNCTION_DECL)
1436
    return 0;
1437
 
1438
  a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1439
  return a != NULL_TREE;
1440
}
1441
 
1442
/* Return true if FUNC is an interrupt function which uses
1443
   normal return, indicated by the "save_volatiles" attribute.  */
1444
 
1445
static int
1446
microblaze_save_volatiles (tree func)
1447
{
1448
  tree a;
1449
 
1450
  if (TREE_CODE (func) != FUNCTION_DECL)
1451
    return 0;
1452
 
1453
  a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1454
  return a != NULL_TREE;
1455
}
1456
 
1457
/* Return whether function is tagged with 'interrupt_handler'
1458
   attribute.  Return true if function should use return from
1459
   interrupt rather than normal function return.  */
1460
int
1461
microblaze_is_interrupt_handler (void)
1462
{
1463
  return interrupt_handler;
1464
}
1465
 
1466
/* Determine of register must be saved/restored in call.  */
1467
static int
1468
microblaze_must_save_register (int regno)
1469
{
1470
  if (pic_offset_table_rtx &&
1471
      (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1472
    return 1;
1473
 
1474
  if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1475
    return 1;
1476
 
1477
  if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1478
    return 1;
1479
 
1480
  if (!current_function_is_leaf)
1481
    {
1482
      if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1483
        return 1;
1484
      if ((interrupt_handler || save_volatiles) &&
1485
          (regno >= 3 && regno <= 12))
1486
        return 1;
1487
    }
1488
 
1489
  if (interrupt_handler)
1490
    {
1491
      if (df_regs_ever_live_p (regno)
1492
          || regno == MB_ABI_MSR_SAVE_REG
1493
          || regno == MB_ABI_ASM_TEMP_REGNUM
1494
          || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1495
        return 1;
1496
    }
1497
 
1498
  if (save_volatiles)
1499
    {
1500
      if (df_regs_ever_live_p (regno)
1501
          || regno == MB_ABI_ASM_TEMP_REGNUM
1502
          || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1503
        return 1;
1504
    }
1505
 
1506
  return 0;
1507
}
1508
 
1509
/* Return the bytes needed to compute the frame pointer from the current
1510
   stack pointer.
1511
 
1512
   MicroBlaze stack frames look like:
1513
 
1514
 
1515
 
1516
             Before call                        After call
1517
        +-----------------------+       +-----------------------+
1518
   high |                       |       |                       |
1519
   mem. |  local variables,     |       |  local variables,     |
1520
        |  callee saved and     |       |  callee saved and     |
1521
        |  temps                |       |  temps                |
1522
        +-----------------------+       +-----------------------+
1523
        |  arguments for called |       |  arguments for called |
1524
        |  subroutines          |       |  subroutines          |
1525
        |  (optional)           |       |  (optional)           |
1526
        +-----------------------+       +-----------------------+
1527
        |  Link register        |       |  Link register        |
1528
    SP->|                       |       |                       |
1529
        +-----------------------+       +-----------------------+
1530
                                        |                       |
1531
                                        |  local variables,     |
1532
                                        |  callee saved and     |
1533
                                        |  temps                |
1534
                                        +-----------------------+
1535
                                        |   MSR (optional if,   |
1536
                                        |   interrupt handler)  |
1537
                                        +-----------------------+
1538
                                        |                       |
1539
                                        |  alloca allocations   |
1540
                                        |                       |
1541
                                        +-----------------------+
1542
                                        |                       |
1543
                                        |  arguments for called |
1544
                                        |  subroutines          |
1545
                                        |  (optional)           |
1546
                                        |                       |
1547
                                        +-----------------------+
1548
                                        |  Link register        |
1549
   low                           FP,SP->|                       |
1550
   memory                               +-----------------------+
1551
 
1552
*/
1553
 
1554
static HOST_WIDE_INT
1555
compute_frame_size (HOST_WIDE_INT size)
1556
{
1557
  int regno;
1558
  HOST_WIDE_INT total_size;     /* # bytes that the entire frame takes up.  */
1559
  HOST_WIDE_INT var_size;       /* # bytes that local variables take up.  */
1560
  HOST_WIDE_INT args_size;      /* # bytes that outgoing arguments take up.  */
1561
  int link_debug_size;          /* # bytes for link register.  */
1562
  HOST_WIDE_INT gp_reg_size;    /* # bytes needed to store calle-saved gp regs.  */
1563
  long mask;                    /* mask of saved gp registers.  */
1564
 
1565
  interrupt_handler =
1566
    microblaze_interrupt_function_p (current_function_decl);
1567
  save_volatiles = microblaze_save_volatiles (current_function_decl);
1568
 
1569
  gp_reg_size = 0;
1570
  mask = 0;
1571
  var_size = size;
1572
  args_size = crtl->outgoing_args_size;
1573
 
1574
  if ((args_size == 0) && cfun->calls_alloca)
1575
    args_size = NUM_OF_ARGS * UNITS_PER_WORD;
1576
 
1577
  total_size = var_size + args_size;
1578
 
1579
  if (flag_pic == 2)
1580
    /* force setting GOT.  */
1581
    df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
1582
 
1583
  /* Calculate space needed for gp registers.  */
1584
  for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
1585
    {
1586
      if (microblaze_must_save_register (regno))
1587
        {
1588
 
1589
          if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
1590
            /* Don't account for link register. It is accounted specially below.  */
1591
            gp_reg_size += GET_MODE_SIZE (SImode);
1592
 
1593
          mask |= (1L << (regno - GP_REG_FIRST));
1594
        }
1595
    }
1596
 
1597
  total_size += gp_reg_size;
1598
 
1599
  /* Add 4 bytes for MSR.  */
1600
  if (interrupt_handler)
1601
    total_size += 4;
1602
 
1603
  /* No space to be allocated for link register in leaf functions with no other
1604
     stack requirements.  */
1605
  if (total_size == 0 && current_function_is_leaf)
1606
    link_debug_size = 0;
1607
  else
1608
    link_debug_size = UNITS_PER_WORD;
1609
 
1610
  total_size += link_debug_size;
1611
 
1612
  /* Save other computed information.  */
1613
  current_frame_info.total_size = total_size;
1614
  current_frame_info.var_size = var_size;
1615
  current_frame_info.args_size = args_size;
1616
  current_frame_info.gp_reg_size = gp_reg_size;
1617
  current_frame_info.mask = mask;
1618
  current_frame_info.initialized = reload_completed;
1619
  current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
1620
  current_frame_info.link_debug_size = link_debug_size;
1621
 
1622
  if (mask)
1623
    /* Offset from which to callee-save GP regs.  */
1624
    current_frame_info.gp_offset = (total_size - gp_reg_size);
1625
  else
1626
    current_frame_info.gp_offset = 0;
1627
 
1628
  /* Ok, we're done.  */
1629
  return total_size;
1630
}
1631
 
1632
/* Make sure that we're not trying to eliminate to the wrong hard frame
1633
   pointer.  */
1634
 
1635
static bool
1636
microblaze_can_eliminate (const int from, const int to)
1637
{
1638
  return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
1639
          || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
1640
          || (from != RETURN_ADDRESS_POINTER_REGNUM
1641
              && (to == HARD_FRAME_POINTER_REGNUM
1642
                  || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
1643
}
1644
 
1645
/* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
1646
   pointer or argument pointer or the return address pointer.  TO is either
1647
   the stack pointer or hard frame pointer.  */
1648
 
1649
HOST_WIDE_INT
1650
microblaze_initial_elimination_offset (int from, int to)
1651
{
1652
  HOST_WIDE_INT offset;
1653
 
1654
  switch (from)
1655
    {
1656
    case FRAME_POINTER_REGNUM:
1657
      offset = 0;
1658
      break;
1659
    case ARG_POINTER_REGNUM:
1660
      if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
1661
        offset = compute_frame_size (get_frame_size ());
1662
      else
1663
        gcc_unreachable ();
1664
      break;
1665
    case RETURN_ADDRESS_POINTER_REGNUM:
1666
      if (current_function_is_leaf)
1667
        offset = 0;
1668
      else
1669
        offset = current_frame_info.gp_offset +
1670
          ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
1671
      break;
1672
    default:
1673
      gcc_unreachable ();
1674
    }
1675
  return offset;
1676
}
1677
 
1678
/* Print operands using format code.
1679
 
1680
   The MicroBlaze specific codes are:
1681
 
1682
   'X'  X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
1683
   'x'  X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
1684
   'F'  op is CONST_DOUBLE, print 32 bits in hex,
1685
   'd'  output integer constant in decimal,
1686
   'z'  if the operand is 0, use $0 instead of normal operand.
1687
   'D'  print second register of double-word register operand.
1688
   'L'  print low-order register of double-word register operand.
1689
   'M'  print high-order register of double-word register operand.
1690
   'C'  print part of opcode for a branch condition.
1691
   'N'  print part of opcode for a branch condition, inverted.
1692
   'S'  X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
1693
   'B'  print 'z' for EQ, 'n' for NE
1694
   'b'  print 'n' for EQ, 'z' for NE
1695
   'T'  print 'f' for EQ, 't' for NE
1696
   't'  print 't' for EQ, 'f' for NE
1697
   'm'  Print 1<<operand.
1698
   'i'  Print 'i' if MEM operand has immediate value
1699
   'o'  Print operand address+4
1700
   '?'  Print 'd' if we use a branch with delay slot instead of normal branch.
1701
   'h'  Print high word of const_double (int or float) value as hex
1702
   'j'  Print low word of const_double (int or float) value as hex
1703
   's'  Print -1 if operand is negative, 0 if positive (sign extend)
1704
   '@'  Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
1705
   '#'  Print nop if the delay slot of a branch is not filled.
1706
*/
1707
 
1708
void
1709
print_operand (FILE * file, rtx op, int letter)
1710
{
1711
  register enum rtx_code code;
1712
 
1713
  if (PRINT_OPERAND_PUNCT_VALID_P (letter))
1714
    {
1715
      switch (letter)
1716
        {
1717
        case '?':
1718
          /* Conditionally add a 'd' to indicate filled delay slot.  */
1719
          if (final_sequence != NULL)
1720
            fputs ("d", file);
1721
          break;
1722
 
1723
        case '#':
1724
          /* Conditionally add a nop in unfilled delay slot.  */
1725
          if (final_sequence == NULL)
1726
            fputs ("nop\t\t# Unfilled delay slot\n", file);
1727
          break;
1728
 
1729
        case '@':
1730
          fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
1731
          break;
1732
 
1733
        default:
1734
          output_operand_lossage ("unknown punctuation '%c'", letter);
1735
          break;
1736
        }
1737
 
1738
      return;
1739
    }
1740
 
1741
  if (!op)
1742
    {
1743
      output_operand_lossage ("null pointer");
1744
      return;
1745
    }
1746
 
1747
  code = GET_CODE (op);
1748
 
1749
  if (code == SIGN_EXTEND)
1750
    op = XEXP (op, 0), code = GET_CODE (op);
1751
 
1752
  if (letter == 'C')
1753
    switch (code)
1754
      {
1755
      case EQ:
1756
        fputs ("eq", file);
1757
        break;
1758
      case NE:
1759
        fputs ("ne", file);
1760
        break;
1761
      case GT:
1762
      case GTU:
1763
        fputs ("gt", file);
1764
        break;
1765
      case GE:
1766
      case GEU:
1767
        fputs ("ge", file);
1768
        break;
1769
      case LT:
1770
      case LTU:
1771
        fputs ("lt", file);
1772
        break;
1773
      case LE:
1774
      case LEU:
1775
        fputs ("le", file);
1776
        break;
1777
      default:
1778
        fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
1779
      }
1780
 
1781
  else if (letter == 'N')
1782
    switch (code)
1783
      {
1784
      case EQ:
1785
        fputs ("ne", file);
1786
        break;
1787
      case NE:
1788
        fputs ("eq", file);
1789
        break;
1790
      case GT:
1791
      case GTU:
1792
        fputs ("le", file);
1793
        break;
1794
      case GE:
1795
      case GEU:
1796
        fputs ("lt", file);
1797
        break;
1798
      case LT:
1799
      case LTU:
1800
        fputs ("ge", file);
1801
        break;
1802
      case LE:
1803
      case LEU:
1804
        fputs ("gt", file);
1805
        break;
1806
      default:
1807
        fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
1808
      }
1809
 
1810
  else if (letter == 'S')
1811
    {
1812
      char buffer[100];
1813
 
1814
      ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
1815
      assemble_name (file, buffer);
1816
    }
1817
 
1818
  /* Print 'i' for memory operands which have immediate values.  */
1819
  else if (letter == 'i')
1820
    {
1821
      if (code == MEM)
1822
        {
1823
          struct microblaze_address_info info;
1824
 
1825
          if (!microblaze_classify_address
1826
              (&info, XEXP (op, 0), GET_MODE (op), 1))
1827
            fatal_insn ("insn contains an invalid address !", op);
1828
 
1829
          switch (info.type)
1830
            {
1831
            case ADDRESS_REG:
1832
            case ADDRESS_CONST_INT:
1833
            case ADDRESS_SYMBOLIC:
1834
            case ADDRESS_GOTOFF:
1835
              fputs ("i", file);
1836
              break;
1837
            case ADDRESS_REG_INDEX:
1838
              break;
1839
            case ADDRESS_INVALID:
1840
            case ADDRESS_PLT:
1841
              fatal_insn ("invalid address", op);
1842
            }
1843
        }
1844
    }
1845
 
1846
  else if (code == REG || code == SUBREG)
1847
    {
1848
      register int regnum;
1849
 
1850
      if (code == REG)
1851
        regnum = REGNO (op);
1852
      else
1853
        regnum = true_regnum (op);
1854
 
1855
      if ((letter == 'M' && !WORDS_BIG_ENDIAN)
1856
          || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
1857
        regnum++;
1858
 
1859
      fprintf (file, "%s", reg_names[regnum]);
1860
    }
1861
 
1862
  else if (code == MEM)
1863
    if (letter == 'o')
1864
      {
1865
        rtx op4 = adjust_address (op, GET_MODE (op), 4);
1866
        output_address (XEXP (op4, 0));
1867
      }
1868
    else
1869
      output_address (XEXP (op, 0));
1870
 
1871
  else if (letter == 'h' || letter == 'j')
1872
    {
1873
      long val[2];
1874
      if (code == CONST_DOUBLE)
1875
        {
1876
          if (GET_MODE (op) == DFmode)
1877
            {
1878
              REAL_VALUE_TYPE value;
1879
              REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1880
              REAL_VALUE_TO_TARGET_DOUBLE (value, val);
1881
            }
1882
          else
1883
            {
1884
              val[0] = CONST_DOUBLE_HIGH (op);
1885
              val[1] = CONST_DOUBLE_LOW (op);
1886
            }
1887
        }
1888
      else if (code == CONST_INT)
1889
        {
1890
          val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
1891
          val[1] = INTVAL (op) & 0x00000000ffffffffLL;
1892
          if (val[0] == 0 && val[1] < 0)
1893
            val[0] = -1;
1894
 
1895
        }
1896
      fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
1897
    }
1898
  else if (code == CONST_DOUBLE)
1899
    {
1900
      if (letter == 'F')
1901
        {
1902
          unsigned long value_long;
1903
          REAL_VALUE_TYPE value;
1904
          REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1905
          REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
1906
          fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
1907
        }
1908
      else
1909
        {
1910
          char s[60];
1911
          real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
1912
          fputs (s, file);
1913
        }
1914
    }
1915
 
1916
  else if (code == UNSPEC)
1917
    {
1918
      print_operand_address (file, op);
1919
    }
1920
 
1921
  else if (letter == 'x' && GET_CODE (op) == CONST_INT)
1922
    fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
1923
 
1924
  else if (letter == 'X' && GET_CODE (op) == CONST_INT)
1925
    fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
1926
 
1927
  else if (letter == 'd' && GET_CODE (op) == CONST_INT)
1928
    fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
1929
 
1930
  else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
1931
    fputs (reg_names[GP_REG_FIRST], file);
1932
 
1933
  else if (letter == 's' && GET_CODE (op) == CONST_INT)
1934
    if (INTVAL (op) < 0)
1935
      fputs ("-1", file);
1936
    else
1937
      fputs ("0", file);
1938
 
1939
  else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
1940
    output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
1941
 
1942
  else if (letter == 'B')
1943
    fputs (code == EQ ? "z" : "n", file);
1944
  else if (letter == 'b')
1945
    fputs (code == EQ ? "n" : "z", file);
1946
  else if (letter == 'T')
1947
    fputs (code == EQ ? "f" : "t", file);
1948
  else if (letter == 't')
1949
    fputs (code == EQ ? "t" : "f", file);
1950
 
1951
  else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
1952
    {
1953
      print_operand (file, XEXP (op, 0), letter);
1954
    }
1955
  else if (letter == 'm')
1956
    fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
1957
  else
1958
    output_addr_const (file, op);
1959
}
1960
 
1961
/* A C compound statement to output to stdio stream STREAM the
1962
   assembler syntax for an instruction operand that is a memory
1963
   reference whose address is ADDR.  ADDR is an RTL expression.
1964
 
1965
   Possible address classifications and output formats are,
1966
 
1967
   ADDRESS_REG                  "%0, r0"
1968
 
1969
   ADDRESS_REG with non-zero    "%0, <addr_const>"
1970
   offset
1971
 
1972
   ADDRESS_REG_INDEX            "rA, RB"
1973
                                (if rA is r0, rA and rB are swapped)
1974
 
1975
   ADDRESS_CONST_INT            "r0, <addr_const>"
1976
 
1977
   ADDRESS_SYMBOLIC             "rBase, <addr_const>"
1978
                                (rBase is a base register suitable for the
1979
                                 symbol's type)
1980
*/
1981
 
1982
void
1983
print_operand_address (FILE * file, rtx addr)
1984
{
1985
  struct microblaze_address_info info;
1986
  enum microblaze_address_type type;
1987
  if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
1988
    fatal_insn ("insn contains an invalid address !", addr);
1989
 
1990
  type = info.type;
1991
  switch (info.type)
1992
    {
1993
    case ADDRESS_REG:
1994
      fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
1995
      output_addr_const (file, info.offset);
1996
      break;
1997
    case ADDRESS_REG_INDEX:
1998
      if (REGNO (info.regA) == 0)
1999
        /* Make rB == r0 instead of rA == r0. This helps reduce read port
2000
           congestion.  */
2001
        fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2002
                 reg_names[REGNO (info.regA)]);
2003
      else if (REGNO (info.regB) != 0)
2004
        /* This is a silly swap to help Dhrystone.  */
2005
        fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2006
                 reg_names[REGNO (info.regA)]);
2007
      break;
2008
    case ADDRESS_CONST_INT:
2009
      fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2010
      output_addr_const (file, info.offset);
2011
      break;
2012
    case ADDRESS_SYMBOLIC:
2013
    case ADDRESS_GOTOFF:
2014
    case ADDRESS_PLT:
2015
      if (info.regA)
2016
        fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2017
      output_addr_const (file, info.symbol);
2018
      if (type == ADDRESS_GOTOFF)
2019
        {
2020
          fputs ("@GOT", file);
2021
        }
2022
      else if (type == ADDRESS_PLT)
2023
        {
2024
          fputs ("@PLT", file);
2025
        }
2026
      break;
2027
    case ADDRESS_INVALID:
2028
      fatal_insn ("invalid address", addr);
2029
      break;
2030
    }
2031
}
2032
 
2033
/* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2034
   is used, so that we don't emit an .extern for it in
2035
   microblaze_asm_file_end.  */
2036
 
2037
void
2038
microblaze_declare_object (FILE * stream, const char *name,
2039
                           const char *section, const char *fmt, int size)
2040
{
2041
 
2042
  fputs (section, stream);
2043
  assemble_name (stream, name);
2044
  fprintf (stream, fmt, size);
2045
}
2046
 
2047
/* Common code to emit the insns (or to write the instructions to a file)
2048
   to save/restore registers.
2049
 
2050
   Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2051
   is not modified within save_restore_insns.  */
2052
 
2053
#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2054
 
2055
/* Save or restore instructions based on whether this is the prologue or
2056
   epilogue.  prologue is 1 for the prologue.  */
2057
static void
2058
save_restore_insns (int prologue)
2059
{
2060
  rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2061
    0, isr_mem_rtx = 0;
2062
  rtx isr_msr_rtx = 0, insn;
2063
  long mask = current_frame_info.mask;
2064
  HOST_WIDE_INT gp_offset;
2065
  int regno;
2066
 
2067
  if (frame_pointer_needed
2068
      && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2069
    gcc_unreachable ();
2070
 
2071
  if (mask == 0)
2072
    return;
2073
 
2074
  /* Save registers starting from high to low.  The debuggers prefer at least
2075
     the return register be stored at func+4, and also it allows us not to
2076
     need a nop in the epilog if at least one register is reloaded in
2077
     addition to return address.  */
2078
 
2079
  /* Pick which pointer to use as a base register.  For small frames, just
2080
     use the stack pointer.  Otherwise, use a temporary register.  Save 2
2081
     cycles if the save area is near the end of a large frame, by reusing
2082
     the constant created in the prologue/epilogue to adjust the stack
2083
     frame.  */
2084
 
2085
  gp_offset = current_frame_info.gp_offset;
2086
 
2087
  gcc_assert (gp_offset > 0);
2088
 
2089
  base_reg_rtx = stack_pointer_rtx;
2090
 
2091
  /* For interrupt_handlers, need to save/restore the MSR.  */
2092
  if (interrupt_handler)
2093
    {
2094
      isr_mem_rtx = gen_rtx_MEM (SImode,
2095
                                 gen_rtx_PLUS (Pmode, base_reg_rtx,
2096
                                               GEN_INT (current_frame_info.
2097
                                                        gp_offset -
2098
                                                        UNITS_PER_WORD)));
2099
 
2100
      /* Do not optimize in flow analysis.  */
2101
      MEM_VOLATILE_P (isr_mem_rtx) = 1;
2102
      isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2103
      isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2104
    }
2105
 
2106
  if (interrupt_handler && !prologue)
2107
    {
2108
      emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2109
      emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2110
      /* Do not optimize in flow analysis.  */
2111
      emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2112
      emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2113
    }
2114
 
2115
  for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2116
    {
2117
      if (BITSET_P (mask, regno - GP_REG_FIRST))
2118
        {
2119
          if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2120
            /* Don't handle here. Already handled as the first register.  */
2121
            continue;
2122
 
2123
          reg_rtx = gen_rtx_REG (SImode, regno);
2124
          insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2125
          mem_rtx = gen_rtx_MEM (SImode, insn);
2126
          if (interrupt_handler || save_volatiles)
2127
            /* Do not optimize in flow analysis.  */
2128
            MEM_VOLATILE_P (mem_rtx) = 1;
2129
 
2130
          if (prologue)
2131
            {
2132
              insn = emit_move_insn (mem_rtx, reg_rtx);
2133
              RTX_FRAME_RELATED_P (insn) = 1;
2134
            }
2135
          else
2136
            {
2137
              insn = emit_move_insn (reg_rtx, mem_rtx);
2138
            }
2139
 
2140
          gp_offset += GET_MODE_SIZE (SImode);
2141
        }
2142
    }
2143
 
2144
  if (interrupt_handler && prologue)
2145
    {
2146
      emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2147
      emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2148
 
2149
      /* Do not optimize in flow analysis.  */
2150
      emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2151
      emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2152
    }
2153
 
2154
  /* Done saving and restoring */
2155
}
2156
 
2157
 
2158
/* Set up the stack and frame (if desired) for the function.  */
2159
static void
2160
microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2161
{
2162
  const char *fnname;
2163
  long fsiz = current_frame_info.total_size;
2164
 
2165
  /* Get the function name the same way that toplev.c does before calling
2166
     assemble_start_function.  This is needed so that the name used here
2167
     exactly matches the name used in ASM_DECLARE_FUNCTION_NAME.  */
2168
  fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2169
  if (!flag_inhibit_size_directive)
2170
    {
2171
      fputs ("\t.ent\t", file);
2172
      if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2173
        fputs ("_interrupt_handler", file);
2174
      else
2175
        assemble_name (file, fnname);
2176
      fputs ("\n", file);
2177
      if (!interrupt_handler)
2178
        ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2179
    }
2180
 
2181
  assemble_name (file, fnname);
2182
  fputs (":\n", file);
2183
 
2184
  if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2185
    fputs ("_interrupt_handler:\n", file);
2186
 
2187
  if (!flag_inhibit_size_directive)
2188
    {
2189
      /* .frame FRAMEREG, FRAMESIZE, RETREG.  */
2190
      fprintf (file,
2191
               "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2192
               (reg_names[(frame_pointer_needed)
2193
                          ? HARD_FRAME_POINTER_REGNUM :
2194
                          STACK_POINTER_REGNUM]), fsiz,
2195
               reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2196
               current_frame_info.var_size, current_frame_info.num_gp,
2197
               crtl->outgoing_args_size);
2198
      fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2199
    }
2200
}
2201
 
2202
/* Output extra assembler code at the end of a prologue.  */
2203
static void
2204
microblaze_function_end_prologue (FILE * file)
2205
{
2206
  if (TARGET_STACK_CHECK)
2207
    {
2208
      fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2209
      fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2210
      fprintf (file, "cmpu\tr18,r1,r18\n\t");
2211
      fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2212
      fprintf (file, "# Stack Check Stub -- End.\n");
2213
    }
2214
}
2215
 
2216
/* Expand the prologue into a bunch of separate insns.  */
2217
 
2218
void
2219
microblaze_expand_prologue (void)
2220
{
2221
  int regno;
2222
  HOST_WIDE_INT fsiz;
2223
  const char *arg_name = 0;
2224
  tree fndecl = current_function_decl;
2225
  tree fntype = TREE_TYPE (fndecl);
2226
  tree fnargs = DECL_ARGUMENTS (fndecl);
2227
  rtx next_arg_reg;
2228
  int i;
2229
  tree next_arg;
2230
  tree cur_arg;
2231
  CUMULATIVE_ARGS args_so_far_v;
2232
  cumulative_args_t args_so_far;
2233
  rtx mem_rtx, reg_rtx;
2234
 
2235
  /* If struct value address is treated as the first argument, make it so.  */
2236
  if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2237
      && !cfun->returns_pcc_struct)
2238
    {
2239
      tree type = build_pointer_type (fntype);
2240
      tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2241
                                              NULL_TREE, type);
2242
 
2243
      DECL_ARG_TYPE (function_result_decl) = type;
2244
      TREE_CHAIN (function_result_decl) = fnargs;
2245
      fnargs = function_result_decl;
2246
    }
2247
 
2248
  /* Determine the last argument, and get its name.  */
2249
 
2250
  INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2251
  args_so_far = pack_cumulative_args (&args_so_far_v);
2252
  regno = GP_ARG_FIRST;
2253
 
2254
  for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2255
    {
2256
      tree passed_type = DECL_ARG_TYPE (cur_arg);
2257
      enum machine_mode passed_mode = TYPE_MODE (passed_type);
2258
      rtx entry_parm;
2259
 
2260
      if (TREE_ADDRESSABLE (passed_type))
2261
        {
2262
          passed_type = build_pointer_type (passed_type);
2263
          passed_mode = Pmode;
2264
        }
2265
 
2266
      entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2267
                                               passed_type, true);
2268
 
2269
      if (entry_parm)
2270
        {
2271
          int words;
2272
 
2273
          /* passed in a register, so will get homed automatically.  */
2274
          if (GET_MODE (entry_parm) == BLKmode)
2275
            words = (int_size_in_bytes (passed_type) + 3) / 4;
2276
          else
2277
            words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2278
 
2279
          regno = REGNO (entry_parm) + words - 1;
2280
        }
2281
      else
2282
        {
2283
          regno = GP_ARG_LAST + 1;
2284
          break;
2285
        }
2286
 
2287
      targetm.calls.function_arg_advance (args_so_far, passed_mode,
2288
                                          passed_type, true);
2289
 
2290
      next_arg = TREE_CHAIN (cur_arg);
2291
      if (next_arg == 0)
2292
        {
2293
          if (DECL_NAME (cur_arg))
2294
            arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2295
 
2296
          break;
2297
        }
2298
    }
2299
 
2300
  /* Split parallel insn into a sequence of insns.  */
2301
 
2302
  next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2303
                                             void_type_node, true);
2304
  if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2305
    {
2306
      rtvec adjust = XVEC (next_arg_reg, 0);
2307
      int num = GET_NUM_ELEM (adjust);
2308
 
2309
      for (i = 0; i < num; i++)
2310
        {
2311
          rtx pattern = RTVEC_ELT (adjust, i);
2312
          emit_insn (pattern);
2313
        }
2314
    }
2315
 
2316
  fsiz = compute_frame_size (get_frame_size ());
2317
 
2318
  /* If this function is a varargs function, store any registers that
2319
     would normally hold arguments ($5 - $10) on the stack.  */
2320
  if (((TYPE_ARG_TYPES (fntype) != 0
2321
        && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2322
            != void_type_node))
2323
       || (arg_name != 0
2324
           && ((arg_name[0] == '_'
2325
                && strcmp (arg_name, "__builtin_va_alist") == 0)
2326
               || (arg_name[0] == 'v'
2327
                   && strcmp (arg_name, "va_alist") == 0)))))
2328
    {
2329
      int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2330
      rtx ptr = stack_pointer_rtx;
2331
 
2332
      /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2333
      for (; regno <= GP_ARG_LAST; regno++)
2334
        {
2335
          if (offset != 0)
2336
            ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2337
          emit_move_insn (gen_rtx_MEM (SImode, ptr),
2338
                          gen_rtx_REG (SImode, regno));
2339
 
2340
          offset += GET_MODE_SIZE (SImode);
2341
        }
2342
 
2343
    }
2344
 
2345
  if (fsiz > 0)
2346
    {
2347
      rtx fsiz_rtx = GEN_INT (fsiz);
2348
 
2349
      rtx insn = NULL;
2350
      insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2351
                                    fsiz_rtx));
2352
      if (insn)
2353
        RTX_FRAME_RELATED_P (insn) = 1;
2354
 
2355
      /* Handle SUB_RETURN_ADDR_REGNUM specially at first.  */
2356
      if (!current_function_is_leaf || interrupt_handler)
2357
        {
2358
          mem_rtx = gen_rtx_MEM (SImode,
2359
                                 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2360
                                               const0_rtx));
2361
 
2362
          if (interrupt_handler)
2363
            /* Do not optimize in flow analysis.  */
2364
            MEM_VOLATILE_P (mem_rtx) = 1;
2365
 
2366
          reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2367
          insn = emit_move_insn (mem_rtx, reg_rtx);
2368
          RTX_FRAME_RELATED_P (insn) = 1;
2369
        }
2370
 
2371
      /* _save_ registers for prologue.  */
2372
      save_restore_insns (1);
2373
 
2374
      if (frame_pointer_needed)
2375
        {
2376
          rtx insn = 0;
2377
 
2378
          insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2379
                                       stack_pointer_rtx));
2380
 
2381
          if (insn)
2382
            RTX_FRAME_RELATED_P (insn) = 1;
2383
        }
2384
    }
2385
 
2386
  if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2387
    {
2388
      SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2389
      emit_insn (gen_set_got (pic_offset_table_rtx));   /* setting GOT.  */
2390
    }
2391
 
2392
  /* If we are profiling, make sure no instructions are scheduled before
2393
     the call to mcount.  */
2394
 
2395
  if (profile_flag)
2396
    emit_insn (gen_blockage ());
2397
}
2398
 
2399
/* Do necessary cleanup after a function to restore stack, frame, and regs.  */
2400
 
2401
#define RA_MASK ((long) 0x80000000)     /* 1 << 31 */
2402
#define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2403
 
2404
static void
2405
microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2406
                              HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2407
{
2408
  const char *fnname;
2409
 
2410
  /* Get the function name the same way that toplev.c does before calling
2411
     assemble_start_function.  This is needed so that the name used here
2412
     exactly matches the name used in ASM_DECLARE_FUNCTION_NAME.  */
2413
  fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2414
 
2415
  if (!flag_inhibit_size_directive)
2416
    {
2417
      fputs ("\t.end\t", file);
2418
      if (interrupt_handler)
2419
        fputs ("_interrupt_handler", file);
2420
      else
2421
        assemble_name (file, fnname);
2422
      fputs ("\n", file);
2423
    }
2424
 
2425
  /* Reset state info for each function.  */
2426
  current_frame_info = zero_frame_info;
2427
 
2428
  /* Restore the output file if optimizing the GP (optimizing the GP causes
2429
     the text to be diverted to a tempfile, so that data decls come before
2430
     references to the data).  */
2431
}
2432
 
2433
/* Expand the epilogue into a bunch of separate insns.  */
2434
 
2435
void
2436
microblaze_expand_epilogue (void)
2437
{
2438
  HOST_WIDE_INT fsiz = current_frame_info.total_size;
2439
  rtx fsiz_rtx = GEN_INT (fsiz);
2440
  rtx reg_rtx;
2441
  rtx mem_rtx;
2442
 
2443
  /* In case of interrupt handlers use addki instead of addi for changing the
2444
     stack pointer value.  */
2445
 
2446
  if (microblaze_can_use_return_insn ())
2447
    {
2448
      emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
2449
                                                        GP_REG_FIRST +
2450
                                                        MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2451
      return;
2452
    }
2453
 
2454
  if (fsiz > 0)
2455
    {
2456
      /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2457
         sequence of load-followed by a use (in rtsd) in every prologue. Saves
2458
         a load-use stall cycle  :)   This is also important to handle alloca.
2459
         (See comments for if (frame_pointer_needed) below.  */
2460
 
2461
      if (!current_function_is_leaf || interrupt_handler)
2462
        {
2463
          mem_rtx =
2464
            gen_rtx_MEM (SImode,
2465
                         gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
2466
          if (interrupt_handler)
2467
            /* Do not optimize in flow analysis.  */
2468
            MEM_VOLATILE_P (mem_rtx) = 1;
2469
          reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2470
          emit_move_insn (reg_rtx, mem_rtx);
2471
        }
2472
 
2473
      /* It is important that this is done after we restore the return address
2474
         register (above).  When alloca is used, we want to restore the
2475
         sub-routine return address only from the current stack top and not
2476
         from the frame pointer (which we restore below). (frame_pointer + 0)
2477
         might have been over-written since alloca allocates memory on the
2478
         current stack.  */
2479
      if (frame_pointer_needed)
2480
        emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
2481
 
2482
      /* _restore_ registers for epilogue.  */
2483
      save_restore_insns (0);
2484
      emit_insn (gen_blockage ());
2485
      emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
2486
    }
2487
 
2488
  emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
2489
                                                    MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2490
}
2491
 
2492
 
2493
/* Return nonzero if this function is known to have a null epilogue.
2494
   This allows the optimizer to omit jumps to jumps if no stack
2495
   was created.  */
2496
 
2497
int
2498
microblaze_can_use_return_insn (void)
2499
{
2500
  if (!reload_completed)
2501
    return 0;
2502
 
2503
  if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
2504
    return 0;
2505
 
2506
  if (current_frame_info.initialized)
2507
    return current_frame_info.total_size == 0;
2508
 
2509
  return compute_frame_size (get_frame_size ()) == 0;
2510
}
2511
 
2512
/* Implement TARGET_SECONDARY_RELOAD.  */
2513
 
2514
static reg_class_t
2515
microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
2516
                             reg_class_t rclass, enum machine_mode mode ATTRIBUTE_UNUSED,
2517
                             secondary_reload_info *sri ATTRIBUTE_UNUSED)
2518
{
2519
  if (rclass == ST_REGS)
2520
    return GR_REGS;
2521
 
2522
  return NO_REGS;
2523
}
2524
 
2525
static void
2526
microblaze_globalize_label (FILE * stream, const char *name)
2527
{
2528
  fputs ("\t.globl\t", stream);
2529
  if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
2530
    {
2531
      fputs (INTERRUPT_HANDLER_NAME, stream);
2532
      fputs ("\n\t.globl\t", stream);
2533
    }
2534
  assemble_name (stream, name);
2535
  fputs ("\n", stream);
2536
}
2537
 
2538
/* Returns true if decl should be placed into a "small data" section.  */
2539
static bool
2540
microblaze_elf_in_small_data_p (const_tree decl)
2541
{
2542
  HOST_WIDE_INT size;
2543
 
2544
  if (!TARGET_XLGPOPT)
2545
    return false;
2546
 
2547
  /* We want to merge strings, so we never consider them small data.  */
2548
  if (TREE_CODE (decl) == STRING_CST)
2549
    return false;
2550
 
2551
  /* Functions are never in the small data area.  */
2552
  if (TREE_CODE (decl) == FUNCTION_DECL)
2553
    return false;
2554
 
2555
  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
2556
    {
2557
      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
2558
      if (strcmp (section, ".sdata") == 0
2559
          || strcmp (section, ".sdata2") == 0
2560
          || strcmp (section, ".sbss") == 0
2561
          || strcmp (section, ".sbss2") == 0)
2562
        return true;
2563
    }
2564
 
2565
  size = int_size_in_bytes (TREE_TYPE (decl));
2566
 
2567
  return (size > 0 && size <= microblaze_section_threshold);
2568
}
2569
 
2570
 
2571
static section *
2572
microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
2573
{
2574
  switch (categorize_decl_for_section (decl, reloc))
2575
    {
2576
    case SECCAT_RODATA_MERGE_STR:
2577
    case SECCAT_RODATA_MERGE_STR_INIT:
2578
      /* MB binutils have various issues with mergeable string sections and
2579
         relaxation/relocation. Currently, turning mergeable sections
2580
         into regular readonly sections.  */
2581
 
2582
      return readonly_data_section;
2583
    default:
2584
      return default_elf_select_section (decl, reloc, align);
2585
    }
2586
}
2587
 
2588
/*
2589
  Encode info about sections into the RTL based on a symbol's declaration.
2590
  The default definition of this hook, default_encode_section_info in
2591
  `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
2592
 
2593
static void
2594
microblaze_encode_section_info (tree decl, rtx rtl, int first)
2595
{
2596
  default_encode_section_info (decl, rtl, first);
2597
}
2598
 
2599
static rtx
2600
expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op)
2601
{
2602
  rtx result;
2603
  result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
2604
  result = gen_rtx_CONST (Pmode, result);
2605
  result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
2606
  result = gen_const_mem (Pmode, result);
2607
  return result;
2608
}
2609
 
2610
bool
2611
microblaze_expand_move (enum machine_mode mode, rtx operands[])
2612
{
2613
  /* If operands[1] is a constant address invalid for pic, then we need to
2614
     handle it just like LEGITIMIZE_ADDRESS does.  */
2615
  if (flag_pic)
2616
    {
2617
      if (GET_CODE (operands[0]) == MEM)
2618
        {
2619
          rtx addr = XEXP (operands[0], 0);
2620
          if (GET_CODE (addr) == SYMBOL_REF)
2621
            {
2622
              rtx ptr_reg, result;
2623
 
2624
              if (reload_in_progress)
2625
                df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2626
 
2627
              addr = expand_pic_symbol_ref (mode, addr);
2628
              ptr_reg = gen_reg_rtx (Pmode);
2629
              emit_move_insn (ptr_reg, addr);
2630
              result = gen_rtx_MEM (mode, ptr_reg);
2631
              operands[0] = result;
2632
            }
2633
        }
2634
      if (GET_CODE (operands[1]) == SYMBOL_REF
2635
          || GET_CODE (operands[1]) == LABEL_REF)
2636
        {
2637
          rtx result;
2638
          if (reload_in_progress)
2639
            df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2640
          result = expand_pic_symbol_ref (mode, operands[1]);
2641
          if (GET_CODE (operands[0]) != REG)
2642
            {
2643
              rtx ptr_reg = gen_reg_rtx (Pmode);
2644
              emit_move_insn (ptr_reg, result);
2645
              emit_move_insn (operands[0], ptr_reg);
2646
            }
2647
          else
2648
            {
2649
              emit_move_insn (operands[0], result);
2650
            }
2651
          return true;
2652
        }
2653
      else if (GET_CODE (operands[1]) == MEM &&
2654
               GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
2655
        {
2656
          rtx result;
2657
          rtx ptr_reg;
2658
          if (reload_in_progress)
2659
            df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2660
          result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0));
2661
 
2662
          ptr_reg = gen_reg_rtx (Pmode);
2663
 
2664
          emit_move_insn (ptr_reg, result);
2665
          result = gen_rtx_MEM (mode, ptr_reg);
2666
          emit_move_insn (operands[0], result);
2667
          return true;
2668
        }
2669
      else if (pic_address_needs_scratch (operands[1]))
2670
        {
2671
          rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
2672
          rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
2673
 
2674
          if (reload_in_progress)
2675
            df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2676
          emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
2677
          return true;
2678
        }
2679
    }
2680
 
2681
  if ((reload_in_progress | reload_completed) == 0
2682
      && !register_operand (operands[0], SImode)
2683
      && !register_operand (operands[1], SImode)
2684
      && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
2685
    {
2686
      rtx temp = force_reg (SImode, operands[1]);
2687
      emit_move_insn (operands[0], temp);
2688
      return true;
2689
    }
2690
  return false;
2691
}
2692
 
2693
/* Expand shift operations.  */
2694
int
2695
microblaze_expand_shift (rtx operands[])
2696
{
2697
  gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
2698
              || (GET_CODE (operands[2]) == REG)
2699
              || (GET_CODE (operands[2]) == SUBREG));
2700
 
2701
  /* Shift by one -- generate pattern.  */
2702
  if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
2703
    return 0;
2704
 
2705
  /* Have barrel shifter and shift > 1: use it.  */
2706
  if (TARGET_BARREL_SHIFT)
2707
    return 0;
2708
 
2709
  gcc_assert ((GET_CODE (operands[0]) == REG)
2710
              || (GET_CODE (operands[0]) == SUBREG)
2711
              || (GET_CODE (operands[1]) == REG)
2712
              || (GET_CODE (operands[1]) == SUBREG));
2713
 
2714
  /* Shift by zero -- copy regs if necessary.  */
2715
  if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
2716
    {
2717
      if (REGNO (operands[0]) != REGNO (operands[1]))
2718
        emit_insn (gen_movsi (operands[0], operands[1]));
2719
      return 1;
2720
    }
2721
 
2722
  return 0;
2723
}
2724
 
2725
/* Return an RTX indicating where the return address to the
2726
   calling function can be found.  */
2727
rtx
2728
microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
2729
{
2730
  if (count != 0)
2731
    return NULL_RTX;
2732
 
2733
  return gen_rtx_PLUS (Pmode,
2734
                       get_hard_reg_initial_val (Pmode,
2735
                                                 MB_ABI_SUB_RETURN_ADDR_REGNUM),
2736
                       GEN_INT (8));
2737
}
2738
 
2739
/* Put string into .sdata2 if below threashold.  */
2740
void
2741
microblaze_asm_output_ident (FILE *file ATTRIBUTE_UNUSED, const char *string)
2742
{
2743
  int size = strlen (string) + 1;
2744
  if (size <= microblaze_section_threshold)
2745
    switch_to_section (sdata2_section);
2746
  else
2747
    switch_to_section (readonly_data_section);
2748
  assemble_string (string, size);
2749
}
2750
 
2751
static void
2752
microblaze_elf_asm_init_sections (void)
2753
{
2754
  sdata2_section
2755
    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
2756
                           SDATA2_SECTION_ASM_OP);
2757
}
2758
 
2759
/*  Generate assembler code for constant parts of a trampoline.  */
2760
 
2761
static void
2762
microblaze_asm_trampoline_template (FILE *f)
2763
{
2764
  fprintf (f, "\t.word\t0x03e00821\t\t# move   $1,$31\n");
2765
  fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n");
2766
  fprintf (f, "\t.word\t0x00000000\t\t# nop\n");
2767
  fprintf (f, "\t.word\t0x8fe30014\t\t# lw     $3,20($31)\n");
2768
  fprintf (f, "\t.word\t0x8fe20018\t\t# lw     $2,24($31)\n");
2769
  fprintf (f, "\t.word\t0x0060c821\t\t# move   $25,$3 (abicalls)\n");
2770
  fprintf (f, "\t.word\t0x00600008\t\t# jr     $3\n");
2771
  fprintf (f, "\t.word\t0x0020f821\t\t# move   $31,$1\n");
2772
  /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n");  */
2773
  /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n");  */
2774
}
2775
 
2776
/* Implement TARGET_TRAMPOLINE_INIT.  */
2777
 
2778
static void
2779
microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
2780
{
2781
  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2782
  rtx mem;
2783
 
2784
  emit_block_move (m_tramp, assemble_trampoline_template (),
2785
                   GEN_INT (8*UNITS_PER_WORD), BLOCK_OP_NORMAL);
2786
 
2787
  mem = adjust_address (m_tramp, SImode, 8);
2788
  emit_move_insn (mem, chain_value);
2789
  mem = adjust_address (m_tramp, SImode, 12);
2790
  emit_move_insn (mem, fnaddr);
2791
}
2792
 
2793
/* Emit instruction to perform compare.
2794
   cmp is (compare_op op0 op1).  */
2795
static rtx
2796
microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code)
2797
{
2798
  rtx cmp_op0 = XEXP (cmp, 0);
2799
  rtx cmp_op1 = XEXP (cmp, 1);
2800
  rtx comp_reg = gen_reg_rtx (SImode);
2801
  enum rtx_code code = *cmp_code;
2802
 
2803
  gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
2804
 
2805
  /* If comparing against zero, just test source reg.  */
2806
  if (cmp_op1 == const0_rtx)
2807
    return cmp_op0;
2808
 
2809
  if (code == EQ || code == NE)
2810
    {
2811
      if (TARGET_PATTERN_COMPARE && GET_CODE(cmp_op1) == REG)
2812
        {
2813
          if (code == EQ)
2814
            {
2815
              emit_insn (gen_seq_internal_pat (comp_reg, cmp_op0, cmp_op1));
2816
              *cmp_code = NE;
2817
            }
2818
          else
2819
            {
2820
              emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0, cmp_op1));
2821
            }
2822
        }
2823
      else
2824
        /* Use xor for equal/not-equal comparison.  */
2825
        emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
2826
    }
2827
  else if (code == GT || code == GTU || code == LE || code == LEU)
2828
    {
2829
      /* MicroBlaze compare is not symmetrical.  */
2830
      /* Swap argument order.  */
2831
      cmp_op1 = force_reg (mode, cmp_op1);
2832
      if (code == GT || code == LE)
2833
        emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1));
2834
      else
2835
        emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1));
2836
      /* Translate test condition.  */
2837
      *cmp_code = swap_condition (code);
2838
    }
2839
  else /* if (code == GE || code == GEU || code == LT || code == LTU) */
2840
    {
2841
      cmp_op1 = force_reg (mode, cmp_op1);
2842
      if (code == GE || code == LT)
2843
        emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0));
2844
      else
2845
        emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0));
2846
    }
2847
 
2848
  return comp_reg;
2849
}
2850
 
2851
/* Generate conditional branch -- first, generate test condition,
2852
   second, generate correct branch instruction.  */
2853
 
2854
void
2855
microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[])
2856
{
2857
  enum rtx_code code = GET_CODE (operands[0]);
2858
  rtx comp;
2859
  rtx condition;
2860
 
2861
  comp = microblaze_emit_compare (mode, operands[0], &code);
2862
  condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx);
2863
  emit_jump_insn (gen_condjump (condition, operands[3]));
2864
}
2865
 
2866
void
2867
microblaze_expand_conditional_branch_sf (rtx operands[])
2868
{
2869
  rtx condition;
2870
  rtx cmp_op0 = XEXP (operands[0], 0);
2871
  rtx cmp_op1 = XEXP (operands[0], 1);
2872
  rtx comp_reg = gen_reg_rtx (SImode);
2873
 
2874
  emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
2875
  condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
2876
  emit_jump_insn (gen_condjump (condition, operands[3]));
2877
}
2878
 
2879
/* Implement TARGET_FRAME_POINTER_REQUIRED.  */
2880
 
2881
static bool
2882
microblaze_frame_pointer_required (void)
2883
{
2884
  /* If the function contains dynamic stack allocations, we need to
2885
     use the frame pointer to access the static parts of the frame.  */
2886
  if (cfun->calls_alloca)
2887
    return true;
2888
  return false;
2889
}
2890
 
2891
void
2892
microblaze_expand_divide (rtx operands[])
2893
{
2894
  /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15).  */
2895
 
2896
  rtx regt1 = gen_reg_rtx (SImode);
2897
  rtx reg18 = gen_rtx_REG (SImode, R_TMP);
2898
  rtx regqi = gen_reg_rtx (QImode);
2899
  rtx div_label = gen_label_rtx ();
2900
  rtx div_end_label = gen_label_rtx ();
2901
  rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
2902
  rtx mem_rtx;
2903
  rtx ret;
2904
  rtx jump, cjump, insn;
2905
 
2906
  insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
2907
  cjump = emit_jump_insn_after (gen_cbranchsi4 (
2908
                                        gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
2909
                                        regt1, GEN_INT (15), div_label), insn);
2910
  LABEL_NUSES (div_label) = 1;
2911
  JUMP_LABEL (cjump) = div_label;
2912
  emit_insn (gen_rtx_CLOBBER (SImode, reg18));
2913
 
2914
  emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
2915
  emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
2916
  mem_rtx = gen_rtx_MEM (QImode,
2917
                            gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
2918
 
2919
  insn = emit_insn (gen_movqi (regqi, mem_rtx));
2920
  insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
2921
  jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
2922
  JUMP_LABEL (jump) = div_end_label;
2923
  LABEL_NUSES (div_end_label) = 1;
2924
  emit_barrier ();
2925
 
2926
  emit_label (div_label);
2927
  ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
2928
                                       operands[0], LCT_NORMAL,
2929
                                       GET_MODE (operands[0]), 2, operands[1],
2930
                                       GET_MODE (operands[1]), operands[2],
2931
                                       GET_MODE (operands[2]));
2932
  if (ret != operands[0])
2933
                emit_move_insn (operands[0], ret);
2934
 
2935
  emit_label (div_end_label);
2936
  emit_insn (gen_blockage ());
2937
}
2938
 
2939
/* Implement TARGET_FUNCTION_VALUE.  */
2940
static rtx
2941
microblaze_function_value (const_tree valtype,
2942
                           const_tree func ATTRIBUTE_UNUSED,
2943
                           bool outgoing ATTRIBUTE_UNUSED)
2944
{
2945
  return LIBCALL_VALUE (TYPE_MODE (valtype));
2946
}
2947
 
2948
/* Implement TARGET_SCHED_ADJUST_COST.  */
2949
static int
2950
microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link,
2951
                        rtx dep ATTRIBUTE_UNUSED, int cost)
2952
{
2953
  if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
2954
    return cost;
2955
  if (REG_NOTE_KIND (link) != 0)
2956
    return 0;
2957
  return cost;
2958
}
2959
 
2960
/* Implement TARGET_LEGITIMATE_CONSTANT_P.
2961
 
2962
   At present, GAS doesn't understand li.[sd], so don't allow it
2963
   to be generated at present.  */
2964
static bool
2965
microblaze_legitimate_constant_p (enum machine_mode mode, rtx x)
2966
{
2967
  return GET_CODE (x) != CONST_DOUBLE || microblaze_const_double_ok (x, mode);
2968
}
2969
 
2970
#undef TARGET_ENCODE_SECTION_INFO
2971
#define TARGET_ENCODE_SECTION_INFO      microblaze_encode_section_info
2972
 
2973
#undef TARGET_ASM_GLOBALIZE_LABEL
2974
#define TARGET_ASM_GLOBALIZE_LABEL      microblaze_globalize_label
2975
 
2976
#undef TARGET_ASM_FUNCTION_PROLOGUE
2977
#define TARGET_ASM_FUNCTION_PROLOGUE    microblaze_function_prologue
2978
 
2979
#undef TARGET_ASM_FUNCTION_EPILOGUE
2980
#define TARGET_ASM_FUNCTION_EPILOGUE    microblaze_function_epilogue
2981
 
2982
#undef TARGET_RTX_COSTS
2983
#define TARGET_RTX_COSTS                microblaze_rtx_costs
2984
 
2985
#undef TARGET_ADDRESS_COST
2986
#define TARGET_ADDRESS_COST             microblaze_address_cost
2987
 
2988
#undef TARGET_ATTRIBUTE_TABLE
2989
#define TARGET_ATTRIBUTE_TABLE          microblaze_attribute_table
2990
 
2991
#undef TARGET_IN_SMALL_DATA_P
2992
#define TARGET_IN_SMALL_DATA_P          microblaze_elf_in_small_data_p
2993
 
2994
#undef TARGET_ASM_SELECT_SECTION
2995
#define TARGET_ASM_SELECT_SECTION       microblaze_select_section
2996
 
2997
#undef TARGET_HAVE_SRODATA_SECTION
2998
#define TARGET_HAVE_SRODATA_SECTION     true
2999
 
3000
#undef TARGET_ASM_FUNCTION_END_PROLOGUE
3001
#define TARGET_ASM_FUNCTION_END_PROLOGUE \
3002
                                        microblaze_function_end_prologue
3003
 
3004
#undef TARGET_ARG_PARTIAL_BYTES
3005
#define TARGET_ARG_PARTIAL_BYTES        function_arg_partial_bytes
3006
 
3007
#undef TARGET_FUNCTION_ARG
3008
#define TARGET_FUNCTION_ARG             microblaze_function_arg
3009
 
3010
#undef TARGET_FUNCTION_ARG_ADVANCE
3011
#define TARGET_FUNCTION_ARG_ADVANCE     microblaze_function_arg_advance
3012
 
3013
#undef TARGET_CAN_ELIMINATE
3014
#define TARGET_CAN_ELIMINATE            microblaze_can_eliminate
3015
 
3016
#undef TARGET_LEGITIMIZE_ADDRESS
3017
#define TARGET_LEGITIMIZE_ADDRESS       microblaze_legitimize_address
3018
 
3019
#undef TARGET_LEGITIMATE_ADDRESS_P
3020
#define TARGET_LEGITIMATE_ADDRESS_P     microblaze_legitimate_address_p 
3021
 
3022
#undef TARGET_FRAME_POINTER_REQUIRED
3023
#define TARGET_FRAME_POINTER_REQUIRED   microblaze_frame_pointer_required
3024
 
3025
#undef  TARGET_ASM_TRAMPOLINE_TEMPLATE
3026
#define TARGET_ASM_TRAMPOLINE_TEMPLATE  microblaze_asm_trampoline_template
3027
 
3028
#undef  TARGET_TRAMPOLINE_INIT
3029
#define TARGET_TRAMPOLINE_INIT          microblaze_trampoline_init
3030
 
3031
#undef  TARGET_PROMOTE_FUNCTION_MODE
3032
#define TARGET_PROMOTE_FUNCTION_MODE    default_promote_function_mode_always_promote
3033
 
3034
#undef TARGET_FUNCTION_VALUE
3035
#define TARGET_FUNCTION_VALUE           microblaze_function_value 
3036
 
3037
#undef TARGET_SECONDARY_RELOAD
3038
#define TARGET_SECONDARY_RELOAD         microblaze_secondary_reload
3039
 
3040
#undef TARGET_SCHED_ADJUST_COST
3041
#define TARGET_SCHED_ADJUST_COST        microblaze_adjust_cost
3042
 
3043
#undef TARGET_ASM_INIT_SECTIONS
3044
#define TARGET_ASM_INIT_SECTIONS        microblaze_elf_asm_init_sections
3045
 
3046
#undef  TARGET_OPTION_OVERRIDE
3047
#define TARGET_OPTION_OVERRIDE          microblaze_option_override 
3048
 
3049
#undef TARGET_LEGITIMATE_CONSTANT_P
3050
#define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3051
 
3052
struct gcc_target targetm = TARGET_INITIALIZER;
3053
 
3054
#include "gt-microblaze.h"

powered by: WebSVN 2.1.0

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