annotate gcc/config/aarch64/falkor-tag-collision-avoidance.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
131
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
1 /* Tag Collision Avoidance pass for Falkor.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
2 Copyright (C) 2018 Free Software Foundation, Inc.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
3
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
4 This file is part of GCC.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
5
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
6 GCC is free software; you can redistribute it and/or modify it
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
7 under the terms of the GNU General Public License as published by
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
8 the Free Software Foundation; either version 3, or (at your option)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
9 any later version.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
10
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
11 GCC is distributed in the hope that it will be useful, but
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
12 WITHOUT ANY WARRANTY; without even the implied warranty of
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
14 General Public License for more details.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
15
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
17 along with GCC; see the file COPYING3. If not see
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
18 <http://www.gnu.org/licenses/>. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
19
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
20 #define IN_TARGET_CODE 1
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
21
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
22 #include "config.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
23 #define INCLUDE_LIST
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
24 #include "system.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
25 #include "coretypes.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
26 #include "backend.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
27 #include "target.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
28 #include "rtl.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
29 #include "tree.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
30 #include "tree-pass.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
31 #include "aarch64-protos.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
32 #include "hash-map.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
33 #include "cfgloop.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
34 #include "cfgrtl.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
35 #include "rtl-iter.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
36 #include "df.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
37 #include "memmodel.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
38 #include "optabs.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
39 #include "regs.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
40 #include "recog.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
41 #include "regrename.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
42 #include "print-rtl.h"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
43
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
44 /* The Falkor hardware prefetching system uses the encoding of the registers
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
45 and offsets of loads to decide which of the multiple hardware prefetchers to
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
46 assign the load to. This has the positive effect of accelerating prefetches
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
47 when all related loads with uniform strides are assigned to the same
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
48 prefetcher unit. The down side is that because of the way the assignment
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
49 works, multiple unrelated loads may end up on the same prefetch unit, thus
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
50 causing the unit to bounce between different sets of addresses and never
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
51 train correctly. The point of this pass is to avoid such collisions so that
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
52 unrelated loads are spread out to different prefetchers. It also makes a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
53 rudimentary attempt to ensure that related loads with the same tags don't
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
54 get moved out unnecessarily.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
55
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
56 Perhaps a future enhancement would be to make a more concerted attempt to
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
57 get related loads under the same tag. See the memcpy/memset implementation
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
58 for falkor in glibc to understand the kind of impact this can have on
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
59 falkor.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
60
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
61 The assignment of loads is based on a tag that is computed from the encoding
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
62 of the first destination register (the only destination in case of LDR), the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
63 base register and the offset (either the register or the immediate value, as
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
64 encoded in the instruction). This is what the 14 bit tag looks like:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
65
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
66 |<- 6 bits ->|<- 4b ->|<- 4b ->|
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
67 --------------------------------
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
68 | OFFSET | SRC | DST |
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
69 --------------------------------
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
70
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
71 For all cases, the SRC and DST are the 4 LSB of the encoding of the register
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
72 in the instruction. Offset computation is more involved and is as follows:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
73
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
74 - For register offset addressing: 4 LSB of the offset register with the MSB
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
75 of the 6 bits set to 1.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
76
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
77 - For immediate offset: 4 LSB of the encoded immediate offset. The encoding
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
78 depends on the width of the load and is expressed as multiples of the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
79 width.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
80
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
81 - For loads with update: 4 LSB of the offset. The encoding here is the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
82 exact number by which the base is offset and incremented.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
83
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
84 Based on the above it is clear that registers 0 and 16 will result in
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
85 collisions, 1 and 17 and so on. This pass detects such collisions within a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
86 def/use chain of the source register in a loop and tries to resolve the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
87 collision by renaming one of the destination registers. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
88
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
89 /* Get the destination part of the tag. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
90 #define TAG_GET_DEST(__tag) ((__tag) & 0xf)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
91
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
92 /* Get the tag with the destination part updated. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
93 #define TAG_UPDATE_DEST(__tag, __dest) (((__tag) & ~0xf) | (__dest & 0xf))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
94
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
95 #define MAX_PREFETCH_STRIDE 2048
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
96
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
97 /* The instruction information structure. This is used to cache information
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
98 about the INSN that we derive when traversing through all of the insns in
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
99 loops. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
100 class tag_insn_info
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
101 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
102 public:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
103 rtx_insn *insn;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
104 rtx dest;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
105 rtx base;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
106 rtx offset;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
107 bool writeback;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
108 bool ldp;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
109
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
110 tag_insn_info (rtx_insn *i, rtx d, rtx b, rtx o, bool w, bool p)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
111 : insn (i), dest (d), base (b), offset (o), writeback (w), ldp (p)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
112 {}
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
113
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
114 /* Compute the tag based on BASE, DEST and OFFSET of the load. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
115 unsigned tag ()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
116 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
117 unsigned int_offset = 0;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
118 rtx offset = this->offset;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
119 unsigned dest = REGNO (this->dest);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
120 unsigned base = REGNO (this->base);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
121 machine_mode dest_mode = GET_MODE (this->dest);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
122
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
123 /* Falkor does not support SVE; GET_LOAD_INFO ensures that the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
124 destination mode is constant here. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
125 unsigned dest_mode_size = GET_MODE_SIZE (dest_mode).to_constant ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
126
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
127 /* For loads of larger than 16 bytes, the DEST part of the tag is 0. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
128 if ((dest_mode_size << this->ldp) > 16)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
129 dest = 0;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
130
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
131 if (offset && REG_P (offset))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
132 int_offset = (1 << 5) | REGNO (offset);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
133 else if (offset && CONST_INT_P (offset))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
134 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
135 int_offset = INTVAL (offset);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
136 int_offset /= dest_mode_size;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
137 if (!this->writeback)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
138 int_offset >>= 2;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
139 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
140 return ((dest & 0xf)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
141 | ((base & 0xf) << 4)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
142 | ((int_offset & 0x3f) << 8));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
143 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
144 };
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
145
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
146 /* Hash map to traverse and process instructions with colliding tags. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
147 typedef hash_map <rtx, auto_vec <tag_insn_info *> > tag_map_t;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
148
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
149 /* Vector of instructions with colliding tags. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
150 typedef auto_vec <tag_insn_info *> insn_info_list_t;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
151
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
152 /* Pair of instruction information and unavailable register set to pass to
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
153 CHECK_COLLIDING_TAGS. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
154 typedef std::pair <tag_insn_info *, HARD_REG_SET *> arg_pair_t;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
155
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
156
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
157 /* Callback to free all tag_insn_info objects. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
158 bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
159 free_insn_info (const rtx &t ATTRIBUTE_UNUSED, insn_info_list_t *v,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
160 void *arg ATTRIBUTE_UNUSED)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
161 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
162 while (v->length () > 0)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
163 delete v->pop ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
164
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
165 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
166 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
167
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
168
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
169 /* Add all aliases of the register to the unavailable register set. REG is the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
170 smallest register number that can then be used to reference its aliases.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
171 UNAVAILABLE is the hard register set to add the ignored register numbers to
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
172 and MODE is the mode in which the registers would have been used. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
173 static void
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
174 ignore_all_aliases (HARD_REG_SET *unavailable, machine_mode mode, unsigned reg)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
175 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
176 add_to_hard_reg_set (unavailable, mode, reg);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
177 add_to_hard_reg_set (unavailable, mode, reg + 16);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
178 add_to_hard_reg_set (unavailable, mode, reg + 32);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
179 add_to_hard_reg_set (unavailable, mode, reg + 48);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
180 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
181
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
182
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
183 /* Callback to check which destination registers are unavailable to us for
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
184 renaming because of the base and offset colliding. This is a callback that
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
185 gets called for every name value pair (T, V) in the TAG_MAP. The ARG is an
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
186 std::pair of the tag_insn_info of the original insn and the hard register
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
187 set UNAVAILABLE that is used to record hard register numbers that cannot be
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
188 used for the renaming. This always returns true since we want to traverse
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
189 through the entire TAG_MAP. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
190 bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
191 check_colliding_tags (const rtx &t, const insn_info_list_t &v, arg_pair_t *arg)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
192 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
193 HARD_REG_SET *unavailable = arg->second;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
194 unsigned orig_tag = arg->first->tag ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
195 unsigned tag = INTVAL (t);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
196 machine_mode mode = GET_MODE (arg->first->dest);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
197
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
198 /* Can't collide with emptiness. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
199 if (v.length () == 0)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
200 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
201
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
202 /* Drop all aliased destination registers that result in the same
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
203 tag. It is not necessary to drop all of them but we do anyway
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
204 because it is quicker than checking ranges. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
205 if (TAG_UPDATE_DEST (tag, 0) == TAG_UPDATE_DEST (orig_tag, 0))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
206 ignore_all_aliases (unavailable, mode, TAG_GET_DEST (tag));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
207
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
208 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
209 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
210
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
211
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
212 /* Initialize and build a set of hard register numbers UNAVAILABLE to avoid for
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
213 renaming. INSN_INFO is the original insn, TAG_MAP is the map of the list of
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
214 insns indexed by their tags, HEAD is the def/use chain head of the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
215 destination register of the original insn. The routine returns the super
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
216 class of register classes that may be used during the renaming. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
217 static enum reg_class
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
218 init_unavailable (tag_insn_info *insn_info, tag_map_t &tag_map, du_head_p head,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
219 HARD_REG_SET *unavailable)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
220 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
221 unsigned dest = head->regno;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
222 enum reg_class super_class = NO_REGS;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
223 machine_mode mode = GET_MODE (insn_info->dest);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
224
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
225 CLEAR_HARD_REG_SET (*unavailable);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
226
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
227 for (struct du_chain *tmp = head->first; tmp; tmp = tmp->next_use)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
228 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
229 if (DEBUG_INSN_P (tmp->insn))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
230 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
231
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
232 IOR_COMPL_HARD_REG_SET (*unavailable, reg_class_contents[tmp->cl]);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
233 super_class = reg_class_superunion[(int) super_class][(int) tmp->cl];
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
234 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
235
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
236 for (unsigned i = 0; i < FIRST_PSEUDO_REGISTER; i++)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
237 if (fixed_regs[i] || global_regs[i])
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
238 add_to_hard_reg_set (unavailable, mode, i);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
239
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
240 arg_pair_t arg = arg_pair_t (insn_info, unavailable);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
241
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
242 /* Exclude all registers that would lead to collisions with other loads. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
243 tag_map.traverse <arg_pair_t *, check_colliding_tags> (&arg);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
244
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
245 /* Finally, also ignore all aliases of the current reg. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
246 ignore_all_aliases (unavailable, mode, dest & 0xf);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
247
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
248 return super_class;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
249 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
250
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
251
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
252 /* Find a suitable and available register and rename the chain of occurrences
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
253 of the register defined in the def/use chain headed by HEAD in which INSN
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
254 exists. CUR_TAG, TAGS and TAG_MAP are used to determine which registers are
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
255 unavailable due to a potential collision due to the rename. The routine
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
256 returns the register number in case of a successful rename or -1 to indicate
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
257 failure. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
258 static int
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
259 rename_chain (tag_insn_info *insn_info, tag_map_t &tag_map, du_head_p head)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
260 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
261 unsigned dest_regno = head->regno;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
262
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
263 if (head->cannot_rename || head->renamed)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
264 return -1;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
265
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
266 HARD_REG_SET unavailable;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
267
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
268 enum reg_class super_class = init_unavailable (insn_info, tag_map, head,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
269 &unavailable);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
270
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
271 unsigned new_regno = find_rename_reg (head, super_class, &unavailable,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
272 dest_regno, false);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
273
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
274 /* Attempt to rename as long as regrename doesn't just throw the same
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
275 register at us. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
276 if (new_regno != dest_regno && regrename_do_replace (head, new_regno))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
277 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
278 if (dump_file && (dump_flags & TDF_DETAILS))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
279 fprintf (dump_file, "\tInsn %d: Renamed %d to %d\n",
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
280 INSN_UID (insn_info->insn), dest_regno, new_regno);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
281
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
282 return new_regno;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
283 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
284
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
285 return -1;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
286 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
287
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
288
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
289 /* Return true if REGNO is not safe to rename. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
290 static bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
291 unsafe_rename_p (unsigned regno)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
292 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
293 /* Avoid renaming registers used for argument passing and return value. In
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
294 future we could be a little less conservative and walk through the basic
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
295 blocks to see if there are any call or syscall sites. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
296 if (regno <= R8_REGNUM
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
297 || (regno >= V0_REGNUM && regno < V8_REGNUM))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
298 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
299
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
300 /* Don't attempt to rename registers that may have specific meanings. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
301 switch (regno)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
302 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
303 case LR_REGNUM:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
304 case HARD_FRAME_POINTER_REGNUM:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
305 case FRAME_POINTER_REGNUM:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
306 case STACK_POINTER_REGNUM:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
307 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
308 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
309
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
310 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
311 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
312
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
313
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
314 /* Go through the def/use chains for the register and find the chain for this
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
315 insn to rename. The function returns the hard register number in case of a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
316 successful rename and -1 otherwise. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
317 static int
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
318 rename_dest (tag_insn_info *insn_info, tag_map_t &tag_map)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
319 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
320 struct du_chain *chain = NULL;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
321 du_head_p head = NULL;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
322 int i;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
323
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
324 unsigned dest_regno = REGNO (insn_info->dest);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
325
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
326 if (unsafe_rename_p (dest_regno))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
327 return -1;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
328
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
329 /* Search the chain where this instruction is (one of) the root. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
330 rtx_insn *insn = insn_info->insn;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
331 operand_rr_info *dest_op_info = insn_rr[INSN_UID (insn)].op_info;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
332
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
333 for (i = 0; i < dest_op_info->n_chains; i++)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
334 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
335 /* The register tracked by this chain does not match the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
336 destination register of insn. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
337 if (dest_op_info->heads[i]->regno != dest_regno)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
338 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
339
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
340 head = dest_op_info->heads[i];
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
341 /* The chain was merged in another, find the new head. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
342 if (!head->first)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
343 head = regrename_chain_from_id (head->id);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
344
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
345 for (chain = head->first; chain; chain = chain->next_use)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
346 /* Found the insn in the chain, so try renaming the register in this
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
347 chain. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
348 if (chain->insn == insn)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
349 return rename_chain (insn_info, tag_map, head);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
350 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
351
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
352 return -1;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
353 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
354
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
355
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
356 /* Flag to track if the map has changed. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
357 static bool map_changed = false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
358
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
359 /* The actual reallocation logic. For each vector of collisions V, try to
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
360 resolve the collision by attempting to rename the destination register of
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
361 all but one of the loads. This is a callback that is invoked for each
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
362 name-value pair (T, V) in TAG_MAP. The function returns true whenever it
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
363 returns unchanged and false otherwise to halt traversal. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
364 bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
365 avoid_collisions_1 (const rtx &t, insn_info_list_t *v, tag_map_t *tag_map)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
366 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
367 /* We need at least two loads to cause a tag collision, return unchanged. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
368 if (v->length () < 2)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
369 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
370
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
371 tag_insn_info *vec_start = v->pop ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
372 tag_insn_info *insn_info = vec_start;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
373
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
374 /* Try to rename at least one register to reduce the collision. If we
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
375 iterate all the way through, we end up dropping one of the loads from the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
376 list. This is fine because we want at most one element to ensure that a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
377 subsequent rename attempt does not end up worsening the collision. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
378 do
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
379 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
380 int new_regno;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
381
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
382 if ((new_regno = rename_dest (insn_info, *tag_map)) != -1)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
383 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
384 rtx new_tag = GEN_INT (TAG_UPDATE_DEST (INTVAL (t), new_regno));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
385
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
386 tag_map->get_or_insert (new_tag).safe_push (insn_info);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
387 df_set_regs_ever_live (new_regno, true);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
388 map_changed = true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
389 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
390 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
391
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
392 v->safe_insert (0, insn_info);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
393 insn_info = v->pop ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
394 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
395 while (insn_info != vec_start);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
396
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
397 if (dump_file)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
398 fprintf (dump_file, "\t>> Failed to rename destination in insn %d\n\t>>",
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
399 INSN_UID (insn_info->insn));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
400
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
401 /* Drop the last element and move on to the next tag. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
402 delete insn_info;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
403 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
404 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
405
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
406
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
407 /* For each set of collisions, attempt to rename the registers or insert a move
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
408 to avoid the collision. We repeatedly traverse through TAG_MAP using
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
409 AVOID_COLLISIONS_1 trying to rename registers to avoid collisions until a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
410 full traversal results in no change in the map. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
411 static void
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
412 avoid_collisions (tag_map_t &tag_map)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
413 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
414 do
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
415 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
416 map_changed = false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
417 tag_map.traverse <tag_map_t *, avoid_collisions_1> (&tag_map);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
418 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
419 while (map_changed);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
420 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
421
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
422
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
423
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
424 /* Find the use def chain in which INSN exists and then see if there is a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
425 definition inside the loop and outside it. We use this as a simple
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
426 approximation to determine whether the base register is an IV. The basic
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
427 idea is to find INSN in the use-def chains for its base register and find
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
428 all definitions that reach it. Of all these definitions, there should be at
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
429 least one definition that is a simple addition of a constant value, either
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
430 as a binary operation or a pre or post update.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
431
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
432 The function returns true if the base register is estimated to be an IV. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
433 static bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
434 iv_p (rtx_insn *insn, rtx reg, struct loop *loop)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
435 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
436 df_ref ause;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
437 unsigned regno = REGNO (reg);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
438
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
439 /* Ignore loads from the stack. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
440 if (regno == SP_REGNUM)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
441 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
442
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
443 for (ause = DF_REG_USE_CHAIN (regno); ause; ause = DF_REF_NEXT_REG (ause))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
444 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
445 if (!DF_REF_INSN_INFO (ause)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
446 || !NONDEBUG_INSN_P (DF_REF_INSN (ause)))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
447 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
448
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
449 if (insn != DF_REF_INSN (ause))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
450 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
451
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
452 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
453 df_ref def_rec;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
454
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
455 FOR_EACH_INSN_INFO_DEF (def_rec, insn_info)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
456 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
457 rtx_insn *insn = DF_REF_INSN (def_rec);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
458 basic_block bb = BLOCK_FOR_INSN (insn);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
459
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
460 if (dominated_by_p (CDI_DOMINATORS, bb, loop->header)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
461 && bb->loop_father == loop)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
462 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
463 if (recog_memoized (insn) < 0)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
464 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
465
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
466 rtx pat = PATTERN (insn);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
467
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
468 /* Prefetch or clobber; unlikely to be a constant stride. The
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
469 falkor software prefetcher tuning is pretty conservative, so
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
470 its presence indicates that the access pattern is probably
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
471 strided but most likely with an unknown stride size or a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
472 stride size that is quite large. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
473 if (GET_CODE (pat) != SET)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
474 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
475
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
476 rtx x = SET_SRC (pat);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
477 if (GET_CODE (x) == ZERO_EXTRACT
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
478 || GET_CODE (x) == ZERO_EXTEND
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
479 || GET_CODE (x) == SIGN_EXTEND)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
480 x = XEXP (x, 0);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
481
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
482 /* Loading the value from memory; unlikely to be a constant
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
483 stride. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
484 if (MEM_P (x))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
485 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
486
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
487 /* An increment or decrement by a constant MODE_SIZE amount or
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
488 the result of a binary expression is likely to be an IV. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
489 if (GET_CODE (x) == POST_INC
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
490 || GET_CODE (x) == POST_DEC
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
491 || GET_CODE (x) == PRE_INC
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
492 || GET_CODE (x) == PRE_DEC)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
493 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
494 else if (BINARY_P (x)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
495 && (CONST_INT_P (XEXP (x, 0))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
496 || CONST_INT_P (XEXP (x, 1))))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
497 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
498 rtx stride = (CONST_INT_P (XEXP (x, 0))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
499 ? XEXP (x, 0) : XEXP (x, 1));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
500
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
501 /* Don't bother with very long strides because the prefetcher
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
502 is unable to train on them anyway. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
503 if (INTVAL (stride) < MAX_PREFETCH_STRIDE)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
504 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
505 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
506 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
507 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
508 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
509 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
510 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
511 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
512
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
513
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
514 /* Return true if SRC is a strided load in the LOOP, false otherwise.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
515 If it is a strided load, set the BASE and OFFSET. Also, if this is
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
516 a pre/post increment load, set PRE_POST to true. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
517 static bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
518 valid_src_p (rtx src, rtx_insn *insn, struct loop *loop, bool *pre_post,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
519 rtx *base, rtx *offset, bool load_pair)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
520 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
521 subrtx_var_iterator::array_type array;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
522 rtx x = NULL_RTX;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
523
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
524 FOR_EACH_SUBRTX_VAR (iter, array, src, NONCONST)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
525 if (MEM_P (*iter))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
526 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
527 x = *iter;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
528 break;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
529 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
530
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
531 if (!x)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
532 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
533
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
534 struct aarch64_address_info addr;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
535 machine_mode mode = GET_MODE (x);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
536
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
537 if (!aarch64_classify_address (&addr, XEXP (x, 0), mode, true))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
538 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
539
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
540 unsigned regno = REGNO (addr.base);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
541 if (global_regs[regno] || fixed_regs[regno])
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
542 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
543
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
544 if (addr.type == ADDRESS_REG_WB)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
545 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
546 unsigned code = GET_CODE (XEXP (x, 0));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
547
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
548 *pre_post = true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
549 *base = addr.base;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
550
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
551 if (code == PRE_MODIFY || code == POST_MODIFY)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
552 *offset = addr.offset;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
553 else
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
554 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
555 /*Writeback is only supported for fixed-width modes. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
556 unsigned int_offset = GET_MODE_SIZE (mode).to_constant ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
557
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
558 /* For post-incremented load pairs we would increment the base twice
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
559 over, so make that adjustment. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
560 if (load_pair && (code == POST_INC || code == POST_DEC))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
561 int_offset *= 2;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
562
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
563 *offset = GEN_INT (int_offset);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
564 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
565 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
566 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
567 else if (addr.type == ADDRESS_REG_IMM || addr.type == ADDRESS_REG_REG)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
568 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
569 /* Check if the load is strided. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
570 if (!iv_p (insn, addr.base, loop))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
571 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
572
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
573 *base = addr.base;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
574 *offset = addr.offset;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
575 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
576 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
577
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
578 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
579 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
580
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
581
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
582 /* Return true if INSN is a strided load in LOOP. If it is a strided load, set
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
583 the DEST, BASE and OFFSET. Also, if this is a pre/post increment load, set
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
584 PRE_POST to true.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
585
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
586 The routine does checks on the destination of the insn and depends on
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
587 STRIDED_LOAD_P to check the source and fill in the BASE and OFFSET. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
588 static bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
589 get_load_info (rtx_insn *insn, struct loop *loop, rtx *dest, rtx *base,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
590 rtx *offset, bool *pre_post, bool *ldp)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
591 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
592 if (!INSN_P (insn) || recog_memoized (insn) < 0)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
593 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
594
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
595 rtx pat = PATTERN (insn);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
596 unsigned code = GET_CODE (pat);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
597 bool load_pair = (code == PARALLEL);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
598
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
599 /* For a load pair we need only the first base and destination
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
600 registers. We however need to ensure that our pre/post increment
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
601 offset is doubled; we do that in STRIDED_LOAD_P. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
602 if (load_pair)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
603 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
604 pat = XVECEXP (pat, 0, 0);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
605 code = GET_CODE (pat);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
606 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
607
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
608 if (code != SET)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
609 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
610
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
611 rtx dest_rtx = SET_DEST (pat);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
612
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
613 if (!REG_P (dest_rtx))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
614 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
615
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
616 unsigned regno = REGNO (dest_rtx);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
617 machine_mode mode = GET_MODE (dest_rtx);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
618 machine_mode inner_mode = GET_MODE_INNER (mode);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
619
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
620 /* Falkor does not support SVE vectors. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
621 if (!GET_MODE_SIZE (mode).is_constant ())
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
622 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
623
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
624 /* Ignore vector struct or lane loads. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
625 if (GET_MODE_SIZE (mode).to_constant ()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
626 != GET_MODE_SIZE (inner_mode).to_constant ())
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
627 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
628
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
629 /* The largest width we want to bother with is a load of a pair of
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
630 quad-words. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
631 if ((GET_MODE_SIZE (mode).to_constant () << load_pair)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
632 > GET_MODE_SIZE (OImode))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
633 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
634
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
635 /* Ignore loads into the stack pointer because it is unlikely to be a
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
636 stream. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
637 if (regno == SP_REGNUM)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
638 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
639
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
640 if (valid_src_p (SET_SRC (pat), insn, loop, pre_post, base, offset,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
641 load_pair))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
642 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
643 *dest = dest_rtx;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
644 *ldp = load_pair;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
645
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
646 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
647 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
648
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
649 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
650 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
651
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
652
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
653 /* Return whether INSN and CAND are in the same def/use chain. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
654 static bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
655 in_same_chain (rtx_insn *insn, rtx_insn *cand, unsigned regno)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
656 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
657 struct du_chain *chain = NULL;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
658 du_head_p head = NULL;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
659 int i;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
660
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
661 /* Search the chain where this instruction is (one of) the root. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
662 operand_rr_info *op_info = insn_rr[INSN_UID (insn)].op_info;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
663
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
664 for (i = 0; i < op_info->n_chains; i++)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
665 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
666 /* The register tracked by this chain does not match the
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
667 dest register of insn. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
668 if (op_info->heads[i]->regno != regno)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
669 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
670
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
671 head = op_info->heads[i];
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
672 /* The chain was merged in another, find the new head. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
673 if (!head->first)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
674 head = regrename_chain_from_id (head->id);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
675
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
676 bool found_insn = false, found_cand = false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
677
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
678 for (chain = head->first; chain; chain = chain->next_use)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
679 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
680 rtx *loc = &SET_DEST (PATTERN (chain->insn));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
681
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
682 if (chain->loc != loc)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
683 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
684
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
685 if (chain->insn == insn)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
686 found_insn = true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
687
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
688 if (chain->insn == cand)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
689 found_cand = true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
690
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
691 if (found_insn && found_cand)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
692 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
693 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
694 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
695
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
696 return false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
697 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
698
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
699
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
700 /* Callback function to traverse the tag map and drop loads that have the same
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
701 destination and and in the same chain of occurrence. Routine always returns
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
702 true to allow traversal through all of TAG_MAP. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
703 bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
704 single_dest_per_chain (const rtx &t ATTRIBUTE_UNUSED, insn_info_list_t *v,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
705 void *arg ATTRIBUTE_UNUSED)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
706 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
707 for (int i = v->length () - 1; i>= 1; i--)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
708 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
709 tag_insn_info *insn_info = (*v)[i];
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
710
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
711 for (int j = v->length () - 2; j >= 0; j--)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
712 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
713 /* Filter out destinations in the same chain. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
714 if (in_same_chain (insn_info->insn, (*v)[j]->insn,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
715 REGNO (insn_info->dest)))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
716 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
717 v->ordered_remove (j);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
718 i = v->length ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
719 break;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
720 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
721 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
722 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
723
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
724 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
725 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
726
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
727
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
728 /* Callback invoked for each name-value pair (T, INSN_INFO) to dump the insn
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
729 list INSN_INFO for tag T. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
730 bool
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
731 dump_insn_list (const rtx &t, const insn_info_list_t &insn_info,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
732 void *unused ATTRIBUTE_UNUSED)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
733 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
734 gcc_assert (dump_file);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
735 fprintf (dump_file, "Tag 0x%lx ::\n", INTVAL (t));
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
736
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
737 for (unsigned i = 0; i < insn_info.length (); i++)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
738 dump_insn_slim (dump_file, insn_info[i]->insn);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
739
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
740 fprintf (dump_file, "\n");
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
741
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
742 return true;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
743 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
744
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
745
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
746 /* Record all loads in LOOP into TAG_MAP indexed by the falkor hardware
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
747 prefetcher memory tags. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
748 static void
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
749 record_loads (tag_map_t &tag_map, struct loop *loop)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
750 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
751 rtx_insn *insn;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
752 basic_block *body, bb;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
753
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
754 body = get_loop_body (loop);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
755
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
756 for (unsigned i = 0; i < loop->num_nodes; i++)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
757 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
758 bb = body[i];
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
759 FOR_BB_INSNS (bb, insn)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
760 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
761 rtx base = NULL_RTX;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
762 rtx dest = NULL_RTX;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
763 rtx offset = NULL_RTX;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
764 bool writeback = false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
765 bool ldp = false;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
766
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
767 if (!INSN_P (insn) || DEBUG_INSN_P (insn))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
768 continue;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
769
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
770 if (get_load_info (insn, loop, &dest, &base, &offset, &writeback,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
771 &ldp))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
772 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
773 tag_insn_info *i = new tag_insn_info (insn, dest, base, offset,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
774 writeback, ldp);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
775 rtx tag = GEN_INT (i->tag ());
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
776 tag_map.get_or_insert (tag).safe_push (i);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
777 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
778 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
779 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
780
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
781 if (dump_file)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
782 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
783 fprintf (dump_file, "Loop %d: Tag map generated.\n", loop->num);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
784 tag_map.traverse <void *, dump_insn_list> (NULL);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
785 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
786
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
787 /* Try to reduce the dataset before launching into the rename attempt. Drop
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
788 destinations in the same collision chain that appear in the same def/use
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
789 chain, all as defs. These chains will move together in a rename so
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
790 there's no point in keeping both in there. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
791 tag_map.traverse <void *, single_dest_per_chain> (NULL);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
792 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
793
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
794
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
795 /* Tag collision avoidance pass for Falkor. The pass runs in two phases for
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
796 each loop; the first phase collects all loads that we consider as
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
797 interesting for renaming into a tag-indexed map of lists. The second phase
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
798 renames the destination register of the loads in an attempt to spread out
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
799 the loads into different tags. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
800 void
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
801 execute_tag_collision_avoidance ()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
802 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
803 struct loop *loop;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
804
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
805 df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
806 df_chain_add_problem (DF_UD_CHAIN);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
807 df_compute_regs_ever_live (true);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
808 df_analyze ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
809 df_set_flags (DF_DEFER_INSN_RESCAN);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
810
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
811 regrename_init (true);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
812 regrename_analyze (NULL);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
813
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
814 compute_bb_for_insn ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
815 calculate_dominance_info (CDI_DOMINATORS);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
816 loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
817
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
818 FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
819 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
820 tag_map_t tag_map (512);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
821
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
822 record_loads (tag_map, loop);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
823 avoid_collisions (tag_map);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
824 if (dump_file)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
825 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
826 fprintf (dump_file, "Loop %d: Completed rename.\n", loop->num);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
827 tag_map.traverse <void *, dump_insn_list> (NULL);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
828 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
829 tag_map.traverse <void *, free_insn_info> (NULL);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
830 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
831
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
832 loop_optimizer_finalize ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
833 free_dominance_info (CDI_DOMINATORS);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
834 regrename_finish ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
835 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
836
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
837
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
838 const pass_data pass_data_tag_collision_avoidance =
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
839 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
840 RTL_PASS, /* type */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
841 "tag_collision_avoidance", /* name */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
842 OPTGROUP_NONE, /* optinfo_flags */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
843 TV_NONE, /* tv_id */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
844 0, /* properties_required */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
845 0, /* properties_provided */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
846 0, /* properties_destroyed */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
847 0, /* todo_flags_start */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
848 TODO_df_finish, /* todo_flags_finish */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
849 };
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
850
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
851
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
852 class pass_tag_collision_avoidance : public rtl_opt_pass
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
853 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
854 public:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
855 pass_tag_collision_avoidance (gcc::context *ctxt)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
856 : rtl_opt_pass (pass_data_tag_collision_avoidance, ctxt)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
857 {}
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
858
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
859 /* opt_pass methods: */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
860 virtual bool gate (function *)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
861 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
862 return ((aarch64_tune_params.extra_tuning_flags
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
863 & AARCH64_EXTRA_TUNE_RENAME_LOAD_REGS)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
864 && optimize >= 2);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
865 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
866
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
867 virtual unsigned int execute (function *)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
868 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
869 execute_tag_collision_avoidance ();
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
870 return 0;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
871 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
872
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
873 }; // class pass_tag_collision_avoidance
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
874
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
875
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
876 /* Create a new pass instance. */
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
877 rtl_opt_pass *
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
878 make_pass_tag_collision_avoidance (gcc::context *ctxt)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
879 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
880 return new pass_tag_collision_avoidance (ctxt);
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
881 }