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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [tree-ssa-address.c] - Blame information for rev 826

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 280 jeremybenn
/* Memory address lowering and addressing mode selection.
2
   Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GCC.
6
 
7
GCC is free software; you can redistribute it and/or modify it
8
under the terms of the GNU General Public License as published by the
9
Free Software Foundation; either version 3, or (at your option) any
10
later version.
11
 
12
GCC is distributed in the hope that it will be useful, but WITHOUT
13
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GCC; see the file COPYING3.  If not see
19
<http://www.gnu.org/licenses/>.  */
20
 
21
/* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
22
   that directly map to addressing modes of the target.  */
23
 
24
#include "config.h"
25
#include "system.h"
26
#include "coretypes.h"
27
#include "tm.h"
28
#include "tree.h"
29
#include "rtl.h"
30
#include "tm_p.h"
31
#include "hard-reg-set.h"
32
#include "basic-block.h"
33
#include "output.h"
34
#include "diagnostic.h"
35
#include "tree-flow.h"
36
#include "tree-dump.h"
37
#include "tree-pass.h"
38
#include "timevar.h"
39
#include "flags.h"
40
#include "tree-inline.h"
41
#include "insn-config.h"
42
#include "recog.h"
43
#include "expr.h"
44
#include "ggc.h"
45
#include "tree-affine.h"
46
#include "target.h"
47
 
48
/* TODO -- handling of symbols (according to Richard Hendersons
49
   comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
50
 
51
   There are at least 5 different kinds of symbols that we can run up against:
52
 
53
     (1) binds_local_p, small data area.
54
     (2) binds_local_p, eg local statics
55
     (3) !binds_local_p, eg global variables
56
     (4) thread local, local_exec
57
     (5) thread local, !local_exec
58
 
59
   Now, (1) won't appear often in an array context, but it certainly can.
60
   All you have to do is set -GN high enough, or explicitly mark any
61
   random object __attribute__((section (".sdata"))).
62
 
63
   All of these affect whether or not a symbol is in fact a valid address.
64
   The only one tested here is (3).  And that result may very well
65
   be incorrect for (4) or (5).
66
 
67
   An incorrect result here does not cause incorrect results out the
68
   back end, because the expander in expr.c validizes the address.  However
69
   it would be nice to improve the handling here in order to produce more
70
   precise results.  */
71
 
72
/* A "template" for memory address, used to determine whether the address is
73
   valid for mode.  */
74
 
75
typedef struct GTY (()) mem_addr_template {
76
  rtx ref;                      /* The template.  */
77
  rtx * GTY ((skip)) step_p;    /* The point in template where the step should be
78
                                   filled in.  */
79
  rtx * GTY ((skip)) off_p;     /* The point in template where the offset should
80
                                   be filled in.  */
81
} mem_addr_template;
82
 
83
DEF_VEC_O (mem_addr_template);
84
DEF_VEC_ALLOC_O (mem_addr_template, gc);
85
 
86
/* The templates.  Each of the low five bits of the index corresponds to one
87
   component of TARGET_MEM_REF being present, while the high bits identify
88
   the address space.  See TEMPL_IDX.  */
89
 
90
static GTY(()) VEC (mem_addr_template, gc) *mem_addr_template_list;
91
 
92
#define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \
93
  (((int) (AS) << 5) \
94
   | ((SYMBOL != 0) << 4) \
95
   | ((BASE != 0) << 3) \
96
   | ((INDEX != 0) << 2) \
97
   | ((STEP != 0) << 1) \
98
   | (OFFSET != 0))
99
 
100
/* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
101
   STEP and OFFSET to *ADDR using address mode ADDRESS_MODE.  Stores pointers
102
   to where step is placed to *STEP_P and offset to *OFFSET_P.  */
103
 
104
static void
105
gen_addr_rtx (enum machine_mode address_mode,
106
              rtx symbol, rtx base, rtx index, rtx step, rtx offset,
107
              rtx *addr, rtx **step_p, rtx **offset_p)
108
{
109
  rtx act_elem;
110
 
111
  *addr = NULL_RTX;
112
  if (step_p)
113
    *step_p = NULL;
114
  if (offset_p)
115
    *offset_p = NULL;
116
 
117
  if (index)
118
    {
119
      act_elem = index;
120
      if (step)
121
        {
122
          act_elem = gen_rtx_MULT (address_mode, act_elem, step);
123
 
124
          if (step_p)
125
            *step_p = &XEXP (act_elem, 1);
126
        }
127
 
128
      *addr = act_elem;
129
    }
130
 
131
  if (base)
132
    {
133
      if (*addr)
134
        *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
135
      else
136
        *addr = base;
137
    }
138
 
139
  if (symbol)
140
    {
141
      act_elem = symbol;
142
      if (offset)
143
        {
144
          act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
145
 
146
          if (offset_p)
147
            *offset_p = &XEXP (act_elem, 1);
148
 
149
          if (GET_CODE (symbol) == SYMBOL_REF
150
              || GET_CODE (symbol) == LABEL_REF
151
              || GET_CODE (symbol) == CONST)
152
            act_elem = gen_rtx_CONST (address_mode, act_elem);
153
        }
154
 
155
      if (*addr)
156
        *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
157
      else
158
        *addr = act_elem;
159
    }
160
  else if (offset)
161
    {
162
      if (*addr)
163
        {
164
          *addr = gen_rtx_PLUS (address_mode, *addr, offset);
165
          if (offset_p)
166
            *offset_p = &XEXP (*addr, 1);
167
        }
168
      else
169
        {
170
          *addr = offset;
171
          if (offset_p)
172
            *offset_p = addr;
173
        }
174
    }
175
 
176
  if (!*addr)
177
    *addr = const0_rtx;
178
}
179
 
180
/* Returns address for TARGET_MEM_REF with parameters given by ADDR
181
   in address space AS.
182
   If REALLY_EXPAND is false, just make fake registers instead
183
   of really expanding the operands, and perform the expansion in-place
184
   by using one of the "templates".  */
185
 
186
rtx
187
addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
188
                  bool really_expand)
189
{
190
  enum machine_mode address_mode = targetm.addr_space.address_mode (as);
191
  rtx address, sym, bse, idx, st, off;
192
  struct mem_addr_template *templ;
193
 
194
  if (addr->step && !integer_onep (addr->step))
195
    st = immed_double_const (TREE_INT_CST_LOW (addr->step),
196
                             TREE_INT_CST_HIGH (addr->step), address_mode);
197
  else
198
    st = NULL_RTX;
199
 
200
  if (addr->offset && !integer_zerop (addr->offset))
201
    off = immed_double_const (TREE_INT_CST_LOW (addr->offset),
202
                              TREE_INT_CST_HIGH (addr->offset), address_mode);
203
  else
204
    off = NULL_RTX;
205
 
206
  if (!really_expand)
207
    {
208
      unsigned int templ_index
209
        = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
210
 
211
      if (templ_index
212
          >= VEC_length (mem_addr_template, mem_addr_template_list))
213
        VEC_safe_grow_cleared (mem_addr_template, gc, mem_addr_template_list,
214
                               templ_index + 1);
215
 
216
      /* Reuse the templates for addresses, so that we do not waste memory.  */
217
      templ = VEC_index (mem_addr_template, mem_addr_template_list, templ_index);
218
      if (!templ->ref)
219
        {
220
          sym = (addr->symbol ?
221
                 gen_rtx_SYMBOL_REF (address_mode, ggc_strdup ("test_symbol"))
222
                 : NULL_RTX);
223
          bse = (addr->base ?
224
                 gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1)
225
                 : NULL_RTX);
226
          idx = (addr->index ?
227
                 gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2)
228
                 : NULL_RTX);
229
 
230
          gen_addr_rtx (address_mode, sym, bse, idx,
231
                        st? const0_rtx : NULL_RTX,
232
                        off? const0_rtx : NULL_RTX,
233
                        &templ->ref,
234
                        &templ->step_p,
235
                        &templ->off_p);
236
        }
237
 
238
      if (st)
239
        *templ->step_p = st;
240
      if (off)
241
        *templ->off_p = off;
242
 
243
      return templ->ref;
244
    }
245
 
246
  /* Otherwise really expand the expressions.  */
247
  sym = (addr->symbol
248
         ? expand_expr (build_addr (addr->symbol, current_function_decl),
249
                        NULL_RTX, address_mode, EXPAND_NORMAL)
250
         : NULL_RTX);
251
  bse = (addr->base
252
         ? expand_expr (addr->base, NULL_RTX, address_mode, EXPAND_NORMAL)
253
         : NULL_RTX);
254
  idx = (addr->index
255
         ? expand_expr (addr->index, NULL_RTX, address_mode, EXPAND_NORMAL)
256
         : NULL_RTX);
257
 
258
  gen_addr_rtx (address_mode, sym, bse, idx, st, off, &address, NULL, NULL);
259
  return address;
260
}
261
 
262
/* Returns address of MEM_REF in TYPE.  */
263
 
264
tree
265
tree_mem_ref_addr (tree type, tree mem_ref)
266
{
267
  tree addr;
268
  tree act_elem;
269
  tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
270
  tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
271
  tree addr_base = NULL_TREE, addr_off = NULL_TREE;
272
 
273
  if (sym)
274
    addr_base = fold_convert (type, build_addr (sym, current_function_decl));
275
  else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
276
    {
277
      addr_base = fold_convert (type, base);
278
      base = NULL_TREE;
279
    }
280
 
281
  act_elem = TMR_INDEX (mem_ref);
282
  if (act_elem)
283
    {
284
      if (step)
285
        act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
286
      addr_off = act_elem;
287
    }
288
 
289
  act_elem = base;
290
  if (act_elem)
291
    {
292
      if (addr_off)
293
        addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
294
      else
295
        addr_off = act_elem;
296
    }
297
 
298
  if (offset && !integer_zerop (offset))
299
    {
300
      if (addr_off)
301
        addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
302
      else
303
        addr_off = offset;
304
    }
305
 
306
  if (addr_off)
307
    {
308
      if (addr_base)
309
        addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off);
310
      else
311
        addr = fold_convert (type, addr_off);
312
    }
313
  else if (addr_base)
314
    addr = addr_base;
315
  else
316
    addr = build_int_cst (type, 0);
317
 
318
  return addr;
319
}
320
 
321
/* Returns true if a memory reference in MODE and with parameters given by
322
   ADDR is valid on the current target.  */
323
 
324
static bool
325
valid_mem_ref_p (enum machine_mode mode, addr_space_t as,
326
                 struct mem_address *addr)
327
{
328
  rtx address;
329
 
330
  address = addr_for_mem_ref (addr, as, false);
331
  if (!address)
332
    return false;
333
 
334
  return memory_address_addr_space_p (mode, address, as);
335
}
336
 
337
/* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
338
   is valid on the current target and if so, creates and returns the
339
   TARGET_MEM_REF.  */
340
 
341
static tree
342
create_mem_ref_raw (tree type, struct mem_address *addr)
343
{
344
  if (!valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
345
    return NULL_TREE;
346
 
347
  if (addr->step && integer_onep (addr->step))
348
    addr->step = NULL_TREE;
349
 
350
  if (addr->offset && integer_zerop (addr->offset))
351
    addr->offset = NULL_TREE;
352
 
353
  return build6 (TARGET_MEM_REF, type,
354
                 addr->symbol, addr->base, addr->index,
355
                 addr->step, addr->offset, NULL);
356
}
357
 
358
/* Returns true if OBJ is an object whose address is a link time constant.  */
359
 
360
static bool
361
fixed_address_object_p (tree obj)
362
{
363
  return (TREE_CODE (obj) == VAR_DECL
364
          && (TREE_STATIC (obj)
365
              || DECL_EXTERNAL (obj))
366
          && ! DECL_DLLIMPORT_P (obj));
367
}
368
 
369
/* If ADDR contains an address of object that is a link time constant,
370
   move it to PARTS->symbol.  */
371
 
372
static void
373
move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
374
{
375
  unsigned i;
376
  tree val = NULL_TREE;
377
 
378
  for (i = 0; i < addr->n; i++)
379
    {
380
      if (!double_int_one_p (addr->elts[i].coef))
381
        continue;
382
 
383
      val = addr->elts[i].val;
384
      if (TREE_CODE (val) == ADDR_EXPR
385
          && fixed_address_object_p (TREE_OPERAND (val, 0)))
386
        break;
387
    }
388
 
389
  if (i == addr->n)
390
    return;
391
 
392
  parts->symbol = TREE_OPERAND (val, 0);
393
  aff_combination_remove_elt (addr, i);
394
}
395
 
396
/* If ADDR contains an instance of BASE_HINT, move it to PARTS->base.  */
397
 
398
static void
399
move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
400
                   aff_tree *addr)
401
{
402
  unsigned i;
403
  tree val = NULL_TREE;
404
  int qual;
405
 
406
  for (i = 0; i < addr->n; i++)
407
    {
408
      if (!double_int_one_p (addr->elts[i].coef))
409
        continue;
410
 
411
      val = addr->elts[i].val;
412
      if (operand_equal_p (val, base_hint, 0))
413
        break;
414
    }
415
 
416
  if (i == addr->n)
417
    return;
418
 
419
  /* Cast value to appropriate pointer type.  We cannot use a pointer
420
     to TYPE directly, as the back-end will assume registers of pointer
421
     type are aligned, and just the base itself may not actually be.
422
     We use void pointer to the type's address space instead.  */
423
  qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
424
  type = build_qualified_type (void_type_node, qual);
425
  parts->base = fold_convert (build_pointer_type (type), val);
426
  aff_combination_remove_elt (addr, i);
427
}
428
 
429
/* If ADDR contains an address of a dereferenced pointer, move it to
430
   PARTS->base.  */
431
 
432
static void
433
move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
434
{
435
  unsigned i;
436
  tree val = NULL_TREE;
437
 
438
  for (i = 0; i < addr->n; i++)
439
    {
440
      if (!double_int_one_p (addr->elts[i].coef))
441
        continue;
442
 
443
      val = addr->elts[i].val;
444
      if (POINTER_TYPE_P (TREE_TYPE (val)))
445
        break;
446
    }
447
 
448
  if (i == addr->n)
449
    return;
450
 
451
  parts->base = val;
452
  aff_combination_remove_elt (addr, i);
453
}
454
 
455
/* Adds ELT to PARTS.  */
456
 
457
static void
458
add_to_parts (struct mem_address *parts, tree elt)
459
{
460
  tree type;
461
 
462
  if (!parts->index)
463
    {
464
      parts->index = fold_convert (sizetype, elt);
465
      return;
466
    }
467
 
468
  if (!parts->base)
469
    {
470
      parts->base = elt;
471
      return;
472
    }
473
 
474
  /* Add ELT to base.  */
475
  type = TREE_TYPE (parts->base);
476
  if (POINTER_TYPE_P (type))
477
    parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
478
                               parts->base,
479
                               fold_convert (sizetype, elt));
480
  else
481
    parts->base = fold_build2 (PLUS_EXPR, type,
482
                               parts->base, elt);
483
}
484
 
485
/* Finds the most expensive multiplication in ADDR that can be
486
   expressed in an addressing mode and move the corresponding
487
   element(s) to PARTS.  */
488
 
489
static void
490
most_expensive_mult_to_index (tree type, struct mem_address *parts,
491
                              aff_tree *addr, bool speed)
492
{
493
  addr_space_t as = TYPE_ADDR_SPACE (type);
494
  enum machine_mode address_mode = targetm.addr_space.address_mode (as);
495
  HOST_WIDE_INT coef;
496
  double_int best_mult, amult, amult_neg;
497
  unsigned best_mult_cost = 0, acost;
498
  tree mult_elt = NULL_TREE, elt;
499
  unsigned i, j;
500
  enum tree_code op_code;
501
 
502
  best_mult = double_int_zero;
503
  for (i = 0; i < addr->n; i++)
504
    {
505
      if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
506
        continue;
507
 
508
      coef = double_int_to_shwi (addr->elts[i].coef);
509
      if (coef == 1
510
          || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
511
        continue;
512
 
513
      acost = multiply_by_cost (coef, address_mode, speed);
514
 
515
      if (acost > best_mult_cost)
516
        {
517
          best_mult_cost = acost;
518
          best_mult = addr->elts[i].coef;
519
        }
520
    }
521
 
522
  if (!best_mult_cost)
523
    return;
524
 
525
  /* Collect elements multiplied by best_mult.  */
526
  for (i = j = 0; i < addr->n; i++)
527
    {
528
      amult = addr->elts[i].coef;
529
      amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
530
 
531
      if (double_int_equal_p (amult, best_mult))
532
        op_code = PLUS_EXPR;
533
      else if (double_int_equal_p (amult_neg, best_mult))
534
        op_code = MINUS_EXPR;
535
      else
536
        {
537
          addr->elts[j] = addr->elts[i];
538
          j++;
539
          continue;
540
        }
541
 
542
      elt = fold_convert (sizetype, addr->elts[i].val);
543
      if (mult_elt)
544
        mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
545
      else if (op_code == PLUS_EXPR)
546
        mult_elt = elt;
547
      else
548
        mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
549
    }
550
  addr->n = j;
551
 
552
  parts->index = mult_elt;
553
  parts->step = double_int_to_tree (sizetype, best_mult);
554
}
555
 
556
/* Splits address ADDR for a memory access of type TYPE into PARTS.
557
   If BASE_HINT is non-NULL, it specifies an SSA name to be used
558
   preferentially as base of the reference.
559
 
560
   TODO -- be more clever about the distribution of the elements of ADDR
561
   to PARTS.  Some architectures do not support anything but single
562
   register in address, possibly with a small integer offset; while
563
   create_mem_ref will simplify the address to an acceptable shape
564
   later, it would be more efficient to know that asking for complicated
565
   addressing modes is useless.  */
566
 
567
static void
568
addr_to_parts (tree type, aff_tree *addr, tree base_hint,
569
               struct mem_address *parts, bool speed)
570
{
571
  tree part;
572
  unsigned i;
573
 
574
  parts->symbol = NULL_TREE;
575
  parts->base = NULL_TREE;
576
  parts->index = NULL_TREE;
577
  parts->step = NULL_TREE;
578
 
579
  if (!double_int_zero_p (addr->offset))
580
    parts->offset = double_int_to_tree (sizetype, addr->offset);
581
  else
582
    parts->offset = NULL_TREE;
583
 
584
  /* Try to find a symbol.  */
585
  move_fixed_address_to_symbol (parts, addr);
586
 
587
  /* First move the most expensive feasible multiplication
588
     to index.  */
589
  most_expensive_mult_to_index (type, parts, addr, speed);
590
 
591
  /* Try to find a base of the reference.  Since at the moment
592
     there is no reliable way how to distinguish between pointer and its
593
     offset, this is just a guess.  */
594
  if (!parts->symbol && base_hint)
595
    move_hint_to_base (type, parts, base_hint, addr);
596
  if (!parts->symbol && !parts->base)
597
    move_pointer_to_base (parts, addr);
598
 
599
  /* Then try to process the remaining elements.  */
600
  for (i = 0; i < addr->n; i++)
601
    {
602
      part = fold_convert (sizetype, addr->elts[i].val);
603
      if (!double_int_one_p (addr->elts[i].coef))
604
        part = fold_build2 (MULT_EXPR, sizetype, part,
605
                            double_int_to_tree (sizetype, addr->elts[i].coef));
606
      add_to_parts (parts, part);
607
    }
608
  if (addr->rest)
609
    add_to_parts (parts, fold_convert (sizetype, addr->rest));
610
}
611
 
612
/* Force the PARTS to register.  */
613
 
614
static void
615
gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
616
{
617
  if (parts->base)
618
    parts->base = force_gimple_operand_gsi (gsi, parts->base,
619
                                            true, NULL_TREE,
620
                                            true, GSI_SAME_STMT);
621
  if (parts->index)
622
    parts->index = force_gimple_operand_gsi (gsi, parts->index,
623
                                             true, NULL_TREE,
624
                                             true, GSI_SAME_STMT);
625
}
626
 
627
/* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
628
   computations are emitted in front of GSI.  TYPE is the mode
629
   of created memory reference.  */
630
 
631
tree
632
create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
633
                tree base_hint, bool speed)
634
{
635
  tree mem_ref, tmp;
636
  tree atype;
637
  struct mem_address parts;
638
 
639
  addr_to_parts (type, addr, base_hint, &parts, speed);
640
  gimplify_mem_ref_parts (gsi, &parts);
641
  mem_ref = create_mem_ref_raw (type, &parts);
642
  if (mem_ref)
643
    return mem_ref;
644
 
645
  /* The expression is too complicated.  Try making it simpler.  */
646
 
647
  if (parts.step && !integer_onep (parts.step))
648
    {
649
      /* Move the multiplication to index.  */
650
      gcc_assert (parts.index);
651
      parts.index = force_gimple_operand_gsi (gsi,
652
                                fold_build2 (MULT_EXPR, sizetype,
653
                                             parts.index, parts.step),
654
                                true, NULL_TREE, true, GSI_SAME_STMT);
655
      parts.step = NULL_TREE;
656
 
657
      mem_ref = create_mem_ref_raw (type, &parts);
658
      if (mem_ref)
659
        return mem_ref;
660
    }
661
 
662
  if (parts.symbol)
663
    {
664
      tmp = build_addr (parts.symbol, current_function_decl);
665
      gcc_assert (is_gimple_val (tmp));
666
 
667
      /* Add the symbol to base, eventually forcing it to register.  */
668
      if (parts.base)
669
        {
670
          gcc_assert (useless_type_conversion_p
671
                                (sizetype, TREE_TYPE (parts.base)));
672
 
673
          if (parts.index)
674
            {
675
              atype = TREE_TYPE (tmp);
676
              parts.base = force_gimple_operand_gsi (gsi,
677
                        fold_build2 (POINTER_PLUS_EXPR, atype,
678
                                     tmp,
679
                                     fold_convert (sizetype, parts.base)),
680
                        true, NULL_TREE, true, GSI_SAME_STMT);
681
            }
682
          else
683
            {
684
              parts.index = parts.base;
685
              parts.base = tmp;
686
            }
687
        }
688
      else
689
        parts.base = tmp;
690
      parts.symbol = NULL_TREE;
691
 
692
      mem_ref = create_mem_ref_raw (type, &parts);
693
      if (mem_ref)
694
        return mem_ref;
695
    }
696
 
697
  if (parts.index)
698
    {
699
      /* Add index to base.  */
700
      if (parts.base)
701
        {
702
          atype = TREE_TYPE (parts.base);
703
          parts.base = force_gimple_operand_gsi (gsi,
704
                        fold_build2 (POINTER_PLUS_EXPR, atype,
705
                                     parts.base,
706
                                     parts.index),
707
                        true, NULL_TREE, true, GSI_SAME_STMT);
708
        }
709
      else
710
        parts.base = parts.index;
711
      parts.index = NULL_TREE;
712
 
713
      mem_ref = create_mem_ref_raw (type, &parts);
714
      if (mem_ref)
715
        return mem_ref;
716
    }
717
 
718
  if (parts.offset && !integer_zerop (parts.offset))
719
    {
720
      /* Try adding offset to base.  */
721
      if (parts.base)
722
        {
723
          atype = TREE_TYPE (parts.base);
724
          parts.base = force_gimple_operand_gsi (gsi,
725
                        fold_build2 (POINTER_PLUS_EXPR, atype,
726
                                     parts.base,
727
                                     fold_convert (sizetype, parts.offset)),
728
                        true, NULL_TREE, true, GSI_SAME_STMT);
729
        }
730
      else
731
        parts.base = parts.offset;
732
 
733
      parts.offset = NULL_TREE;
734
 
735
      mem_ref = create_mem_ref_raw (type, &parts);
736
      if (mem_ref)
737
        return mem_ref;
738
    }
739
 
740
  /* Verify that the address is in the simplest possible shape
741
     (only a register).  If we cannot create such a memory reference,
742
     something is really wrong.  */
743
  gcc_assert (parts.symbol == NULL_TREE);
744
  gcc_assert (parts.index == NULL_TREE);
745
  gcc_assert (!parts.step || integer_onep (parts.step));
746
  gcc_assert (!parts.offset || integer_zerop (parts.offset));
747
  gcc_unreachable ();
748
}
749
 
750
/* Copies components of the address from OP to ADDR.  */
751
 
752
void
753
get_address_description (tree op, struct mem_address *addr)
754
{
755
  addr->symbol = TMR_SYMBOL (op);
756
  addr->base = TMR_BASE (op);
757
  addr->index = TMR_INDEX (op);
758
  addr->step = TMR_STEP (op);
759
  addr->offset = TMR_OFFSET (op);
760
}
761
 
762
/* Copies the additional information attached to target_mem_ref FROM to TO.  */
763
 
764
void
765
copy_mem_ref_info (tree to, tree from)
766
{
767
  /* And the info about the original reference.  */
768
  TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
769
  TREE_SIDE_EFFECTS (to) = TREE_SIDE_EFFECTS (from);
770
  TREE_THIS_VOLATILE (to) = TREE_THIS_VOLATILE (from);
771
}
772
 
773
/* Move constants in target_mem_ref REF to offset.  Returns the new target
774
   mem ref if anything changes, NULL_TREE otherwise.  */
775
 
776
tree
777
maybe_fold_tmr (tree ref)
778
{
779
  struct mem_address addr;
780
  bool changed = false;
781
  tree ret, off;
782
 
783
  get_address_description (ref, &addr);
784
 
785
  if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
786
    {
787
      if (addr.offset)
788
        addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
789
                        addr.offset,
790
                        fold_convert (sizetype, addr.base));
791
      else
792
        addr.offset = addr.base;
793
 
794
      addr.base = NULL_TREE;
795
      changed = true;
796
    }
797
 
798
  if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
799
    {
800
      off = addr.index;
801
      if (addr.step)
802
        {
803
          off = fold_binary_to_constant (MULT_EXPR, sizetype,
804
                                         off, addr.step);
805
          addr.step = NULL_TREE;
806
        }
807
 
808
      if (addr.offset)
809
        {
810
          addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
811
                                                 addr.offset, off);
812
        }
813
      else
814
        addr.offset = off;
815
 
816
      addr.index = NULL_TREE;
817
      changed = true;
818
    }
819
 
820
  if (!changed)
821
    return NULL_TREE;
822
 
823
  ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
824
  if (!ret)
825
    return NULL_TREE;
826
 
827
  copy_mem_ref_info (ret, ref);
828
  return ret;
829
}
830
 
831
/* Dump PARTS to FILE.  */
832
 
833
extern void dump_mem_address (FILE *, struct mem_address *);
834
void
835
dump_mem_address (FILE *file, struct mem_address *parts)
836
{
837
  if (parts->symbol)
838
    {
839
      fprintf (file, "symbol: ");
840
      print_generic_expr (file, parts->symbol, TDF_SLIM);
841
      fprintf (file, "\n");
842
    }
843
  if (parts->base)
844
    {
845
      fprintf (file, "base: ");
846
      print_generic_expr (file, parts->base, TDF_SLIM);
847
      fprintf (file, "\n");
848
    }
849
  if (parts->index)
850
    {
851
      fprintf (file, "index: ");
852
      print_generic_expr (file, parts->index, TDF_SLIM);
853
      fprintf (file, "\n");
854
    }
855
  if (parts->step)
856
    {
857
      fprintf (file, "step: ");
858
      print_generic_expr (file, parts->step, TDF_SLIM);
859
      fprintf (file, "\n");
860
    }
861
  if (parts->offset)
862
    {
863
      fprintf (file, "offset: ");
864
      print_generic_expr (file, parts->offset, TDF_SLIM);
865
      fprintf (file, "\n");
866
    }
867
}
868
 
869
#include "gt-tree-ssa-address.h"

powered by: WebSVN 2.1.0

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