1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright (C) 2019 Collabora, Ltd.
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*61046927SAndroid Build Coastguard Worker * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*61046927SAndroid Build Coastguard Worker * SOFTWARE.
22*61046927SAndroid Build Coastguard Worker *
23*61046927SAndroid Build Coastguard Worker * Authors (Collabora):
24*61046927SAndroid Build Coastguard Worker * Alyssa Rosenzweig <[email protected]>
25*61046927SAndroid Build Coastguard Worker */
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker #include "lcra.h"
28*61046927SAndroid Build Coastguard Worker #include <assert.h>
29*61046927SAndroid Build Coastguard Worker #include <limits.h>
30*61046927SAndroid Build Coastguard Worker #include <stdio.h>
31*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
32*61046927SAndroid Build Coastguard Worker #include <string.h>
33*61046927SAndroid Build Coastguard Worker #include "util/macros.h"
34*61046927SAndroid Build Coastguard Worker #include "util/u_math.h"
35*61046927SAndroid Build Coastguard Worker
36*61046927SAndroid Build Coastguard Worker /* This module is the reference implementation of "Linearly Constrained
37*61046927SAndroid Build Coastguard Worker * Register Allocation". The paper is available in PDF form
38*61046927SAndroid Build Coastguard Worker * (https://people.collabora.com/~alyssa/LCRA.pdf) as well as Markdown+LaTeX
39*61046927SAndroid Build Coastguard Worker * (https://gitlab.freedesktop.org/alyssa/lcra/blob/master/LCRA.md)
40*61046927SAndroid Build Coastguard Worker */
41*61046927SAndroid Build Coastguard Worker
42*61046927SAndroid Build Coastguard Worker struct lcra_state *
lcra_alloc_equations(unsigned node_count,unsigned class_count)43*61046927SAndroid Build Coastguard Worker lcra_alloc_equations(unsigned node_count, unsigned class_count)
44*61046927SAndroid Build Coastguard Worker {
45*61046927SAndroid Build Coastguard Worker struct lcra_state *l = calloc(1, sizeof(*l));
46*61046927SAndroid Build Coastguard Worker
47*61046927SAndroid Build Coastguard Worker l->node_count = node_count;
48*61046927SAndroid Build Coastguard Worker l->class_count = class_count;
49*61046927SAndroid Build Coastguard Worker
50*61046927SAndroid Build Coastguard Worker l->alignment = calloc(sizeof(l->alignment[0]), node_count);
51*61046927SAndroid Build Coastguard Worker l->linear = calloc(sizeof(l->linear[0]), node_count * node_count);
52*61046927SAndroid Build Coastguard Worker l->modulus = calloc(sizeof(l->modulus[0]), node_count);
53*61046927SAndroid Build Coastguard Worker l->class = calloc(sizeof(l->class[0]), node_count);
54*61046927SAndroid Build Coastguard Worker l->class_start = calloc(sizeof(l->class_start[0]), class_count);
55*61046927SAndroid Build Coastguard Worker l->class_disjoint =
56*61046927SAndroid Build Coastguard Worker calloc(sizeof(l->class_disjoint[0]), class_count * class_count);
57*61046927SAndroid Build Coastguard Worker l->class_size = calloc(sizeof(l->class_size[0]), class_count);
58*61046927SAndroid Build Coastguard Worker l->spill_cost = calloc(sizeof(l->spill_cost[0]), node_count);
59*61046927SAndroid Build Coastguard Worker l->solutions = calloc(sizeof(l->solutions[0]), node_count);
60*61046927SAndroid Build Coastguard Worker
61*61046927SAndroid Build Coastguard Worker memset(l->solutions, ~0, sizeof(l->solutions[0]) * node_count);
62*61046927SAndroid Build Coastguard Worker
63*61046927SAndroid Build Coastguard Worker return l;
64*61046927SAndroid Build Coastguard Worker }
65*61046927SAndroid Build Coastguard Worker
66*61046927SAndroid Build Coastguard Worker void
lcra_free(struct lcra_state * l)67*61046927SAndroid Build Coastguard Worker lcra_free(struct lcra_state *l)
68*61046927SAndroid Build Coastguard Worker {
69*61046927SAndroid Build Coastguard Worker if (!l)
70*61046927SAndroid Build Coastguard Worker return;
71*61046927SAndroid Build Coastguard Worker
72*61046927SAndroid Build Coastguard Worker free(l->alignment);
73*61046927SAndroid Build Coastguard Worker free(l->linear);
74*61046927SAndroid Build Coastguard Worker free(l->modulus);
75*61046927SAndroid Build Coastguard Worker free(l->class);
76*61046927SAndroid Build Coastguard Worker free(l->class_start);
77*61046927SAndroid Build Coastguard Worker free(l->class_disjoint);
78*61046927SAndroid Build Coastguard Worker free(l->class_size);
79*61046927SAndroid Build Coastguard Worker free(l->spill_cost);
80*61046927SAndroid Build Coastguard Worker free(l->solutions);
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Worker free(l);
83*61046927SAndroid Build Coastguard Worker }
84*61046927SAndroid Build Coastguard Worker
85*61046927SAndroid Build Coastguard Worker void
lcra_set_alignment(struct lcra_state * l,unsigned node,unsigned align_log2,unsigned bound)86*61046927SAndroid Build Coastguard Worker lcra_set_alignment(struct lcra_state *l, unsigned node, unsigned align_log2,
87*61046927SAndroid Build Coastguard Worker unsigned bound)
88*61046927SAndroid Build Coastguard Worker {
89*61046927SAndroid Build Coastguard Worker l->alignment[node] = (align_log2 + 1) | (bound << 16);
90*61046927SAndroid Build Coastguard Worker }
91*61046927SAndroid Build Coastguard Worker
92*61046927SAndroid Build Coastguard Worker void
lcra_set_disjoint_class(struct lcra_state * l,unsigned c1,unsigned c2)93*61046927SAndroid Build Coastguard Worker lcra_set_disjoint_class(struct lcra_state *l, unsigned c1, unsigned c2)
94*61046927SAndroid Build Coastguard Worker {
95*61046927SAndroid Build Coastguard Worker l->class_disjoint[(c1 * l->class_count) + c2] = true;
96*61046927SAndroid Build Coastguard Worker l->class_disjoint[(c2 * l->class_count) + c1] = true;
97*61046927SAndroid Build Coastguard Worker }
98*61046927SAndroid Build Coastguard Worker
99*61046927SAndroid Build Coastguard Worker void
lcra_restrict_range(struct lcra_state * l,unsigned node,unsigned len)100*61046927SAndroid Build Coastguard Worker lcra_restrict_range(struct lcra_state *l, unsigned node, unsigned len)
101*61046927SAndroid Build Coastguard Worker {
102*61046927SAndroid Build Coastguard Worker if (node < l->node_count && l->alignment[node]) {
103*61046927SAndroid Build Coastguard Worker unsigned BA = l->alignment[node];
104*61046927SAndroid Build Coastguard Worker unsigned alignment = (BA & 0xffff) - 1;
105*61046927SAndroid Build Coastguard Worker unsigned bound = BA >> 16;
106*61046927SAndroid Build Coastguard Worker l->modulus[node] = DIV_ROUND_UP(bound - len + 1, 1 << alignment);
107*61046927SAndroid Build Coastguard Worker }
108*61046927SAndroid Build Coastguard Worker }
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker void
lcra_add_node_interference(struct lcra_state * l,unsigned i,unsigned cmask_i,unsigned j,unsigned cmask_j)111*61046927SAndroid Build Coastguard Worker lcra_add_node_interference(struct lcra_state *l, unsigned i, unsigned cmask_i,
112*61046927SAndroid Build Coastguard Worker unsigned j, unsigned cmask_j)
113*61046927SAndroid Build Coastguard Worker {
114*61046927SAndroid Build Coastguard Worker if (i == j)
115*61046927SAndroid Build Coastguard Worker return;
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker if (l->class_disjoint[(l->class[i] * l -> class_count) + l->class[j]])
118*61046927SAndroid Build Coastguard Worker return;
119*61046927SAndroid Build Coastguard Worker
120*61046927SAndroid Build Coastguard Worker uint32_t constraint_fw = 0;
121*61046927SAndroid Build Coastguard Worker uint32_t constraint_bw = 0;
122*61046927SAndroid Build Coastguard Worker
123*61046927SAndroid Build Coastguard Worker for (unsigned D = 0; D < 16; ++D) {
124*61046927SAndroid Build Coastguard Worker if (cmask_i & (cmask_j << D)) {
125*61046927SAndroid Build Coastguard Worker constraint_bw |= (1 << (15 + D));
126*61046927SAndroid Build Coastguard Worker constraint_fw |= (1 << (15 - D));
127*61046927SAndroid Build Coastguard Worker }
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker if (cmask_i & (cmask_j >> D)) {
130*61046927SAndroid Build Coastguard Worker constraint_fw |= (1 << (15 + D));
131*61046927SAndroid Build Coastguard Worker constraint_bw |= (1 << (15 - D));
132*61046927SAndroid Build Coastguard Worker }
133*61046927SAndroid Build Coastguard Worker }
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker l->linear[j * l->node_count + i] |= constraint_fw;
136*61046927SAndroid Build Coastguard Worker l->linear[i * l->node_count + j] |= constraint_bw;
137*61046927SAndroid Build Coastguard Worker }
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker static bool
lcra_test_linear(struct lcra_state * l,unsigned * solutions,unsigned i)140*61046927SAndroid Build Coastguard Worker lcra_test_linear(struct lcra_state *l, unsigned *solutions, unsigned i)
141*61046927SAndroid Build Coastguard Worker {
142*61046927SAndroid Build Coastguard Worker unsigned *row = &l->linear[i * l->node_count];
143*61046927SAndroid Build Coastguard Worker signed constant = solutions[i];
144*61046927SAndroid Build Coastguard Worker
145*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < l->node_count; ++j) {
146*61046927SAndroid Build Coastguard Worker if (solutions[j] == ~0)
147*61046927SAndroid Build Coastguard Worker continue;
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker signed lhs = solutions[j] - constant;
150*61046927SAndroid Build Coastguard Worker
151*61046927SAndroid Build Coastguard Worker if (lhs < -15 || lhs > 15)
152*61046927SAndroid Build Coastguard Worker continue;
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker if (row[j] & (1 << (lhs + 15)))
155*61046927SAndroid Build Coastguard Worker return false;
156*61046927SAndroid Build Coastguard Worker }
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker return true;
159*61046927SAndroid Build Coastguard Worker }
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker bool
lcra_solve(struct lcra_state * l)162*61046927SAndroid Build Coastguard Worker lcra_solve(struct lcra_state *l)
163*61046927SAndroid Build Coastguard Worker {
164*61046927SAndroid Build Coastguard Worker for (unsigned step = 0; step < l->node_count; ++step) {
165*61046927SAndroid Build Coastguard Worker if (l->solutions[step] != ~0)
166*61046927SAndroid Build Coastguard Worker continue;
167*61046927SAndroid Build Coastguard Worker if (l->alignment[step] == 0)
168*61046927SAndroid Build Coastguard Worker continue;
169*61046927SAndroid Build Coastguard Worker
170*61046927SAndroid Build Coastguard Worker unsigned _class = l->class[step];
171*61046927SAndroid Build Coastguard Worker unsigned class_start = l->class_start[_class];
172*61046927SAndroid Build Coastguard Worker
173*61046927SAndroid Build Coastguard Worker unsigned BA = l->alignment[step];
174*61046927SAndroid Build Coastguard Worker unsigned shift = (BA & 0xffff) - 1;
175*61046927SAndroid Build Coastguard Worker unsigned bound = BA >> 16;
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker unsigned P = bound >> shift;
178*61046927SAndroid Build Coastguard Worker unsigned Q = l->modulus[step];
179*61046927SAndroid Build Coastguard Worker unsigned r_max = l->class_size[_class];
180*61046927SAndroid Build Coastguard Worker unsigned k_max = r_max >> shift;
181*61046927SAndroid Build Coastguard Worker unsigned m_max = k_max / P;
182*61046927SAndroid Build Coastguard Worker bool succ = false;
183*61046927SAndroid Build Coastguard Worker
184*61046927SAndroid Build Coastguard Worker for (unsigned m = 0; m < m_max; ++m) {
185*61046927SAndroid Build Coastguard Worker for (unsigned n = 0; n < Q; ++n) {
186*61046927SAndroid Build Coastguard Worker l->solutions[step] = ((m * P + n) << shift) + class_start;
187*61046927SAndroid Build Coastguard Worker succ = lcra_test_linear(l, l->solutions, step);
188*61046927SAndroid Build Coastguard Worker
189*61046927SAndroid Build Coastguard Worker if (succ)
190*61046927SAndroid Build Coastguard Worker break;
191*61046927SAndroid Build Coastguard Worker }
192*61046927SAndroid Build Coastguard Worker
193*61046927SAndroid Build Coastguard Worker if (succ)
194*61046927SAndroid Build Coastguard Worker break;
195*61046927SAndroid Build Coastguard Worker }
196*61046927SAndroid Build Coastguard Worker
197*61046927SAndroid Build Coastguard Worker /* Out of registers - prepare to spill */
198*61046927SAndroid Build Coastguard Worker if (!succ) {
199*61046927SAndroid Build Coastguard Worker l->spill_class = l->class[step];
200*61046927SAndroid Build Coastguard Worker return false;
201*61046927SAndroid Build Coastguard Worker }
202*61046927SAndroid Build Coastguard Worker }
203*61046927SAndroid Build Coastguard Worker
204*61046927SAndroid Build Coastguard Worker return true;
205*61046927SAndroid Build Coastguard Worker }
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker /* Register spilling is implemented with a cost-benefit system. Costs are set
208*61046927SAndroid Build Coastguard Worker * by the user. Benefits are calculated from the constraints. */
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker void
lcra_set_node_spill_cost(struct lcra_state * l,unsigned node,signed cost)211*61046927SAndroid Build Coastguard Worker lcra_set_node_spill_cost(struct lcra_state *l, unsigned node, signed cost)
212*61046927SAndroid Build Coastguard Worker {
213*61046927SAndroid Build Coastguard Worker if (node < l->node_count)
214*61046927SAndroid Build Coastguard Worker l->spill_cost[node] = cost;
215*61046927SAndroid Build Coastguard Worker }
216*61046927SAndroid Build Coastguard Worker
217*61046927SAndroid Build Coastguard Worker static unsigned
lcra_count_constraints(struct lcra_state * l,unsigned i)218*61046927SAndroid Build Coastguard Worker lcra_count_constraints(struct lcra_state *l, unsigned i)
219*61046927SAndroid Build Coastguard Worker {
220*61046927SAndroid Build Coastguard Worker unsigned count = 0;
221*61046927SAndroid Build Coastguard Worker unsigned *constraints = &l->linear[i * l->node_count];
222*61046927SAndroid Build Coastguard Worker
223*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < l->node_count; ++j)
224*61046927SAndroid Build Coastguard Worker count += util_bitcount(constraints[j]);
225*61046927SAndroid Build Coastguard Worker
226*61046927SAndroid Build Coastguard Worker return count;
227*61046927SAndroid Build Coastguard Worker }
228*61046927SAndroid Build Coastguard Worker
229*61046927SAndroid Build Coastguard Worker signed
lcra_get_best_spill_node(struct lcra_state * l)230*61046927SAndroid Build Coastguard Worker lcra_get_best_spill_node(struct lcra_state *l)
231*61046927SAndroid Build Coastguard Worker {
232*61046927SAndroid Build Coastguard Worker /* If there are no constraints on a node, do not pick it to spill under
233*61046927SAndroid Build Coastguard Worker * any circumstance, or else we would hang rather than fail RA */
234*61046927SAndroid Build Coastguard Worker float best_benefit = 0.0;
235*61046927SAndroid Build Coastguard Worker signed best_node = -1;
236*61046927SAndroid Build Coastguard Worker
237*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < l->node_count; ++i) {
238*61046927SAndroid Build Coastguard Worker /* Find spillable nodes */
239*61046927SAndroid Build Coastguard Worker if (l->class[i] != l->spill_class)
240*61046927SAndroid Build Coastguard Worker continue;
241*61046927SAndroid Build Coastguard Worker if (l->spill_cost[i] < 0)
242*61046927SAndroid Build Coastguard Worker continue;
243*61046927SAndroid Build Coastguard Worker
244*61046927SAndroid Build Coastguard Worker /* Adapted from Chaitin's heuristic */
245*61046927SAndroid Build Coastguard Worker float constraints = lcra_count_constraints(l, i);
246*61046927SAndroid Build Coastguard Worker float cost = (l->spill_cost[i] + 1);
247*61046927SAndroid Build Coastguard Worker float benefit = constraints / cost;
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker if (benefit > best_benefit) {
250*61046927SAndroid Build Coastguard Worker best_benefit = benefit;
251*61046927SAndroid Build Coastguard Worker best_node = i;
252*61046927SAndroid Build Coastguard Worker }
253*61046927SAndroid Build Coastguard Worker }
254*61046927SAndroid Build Coastguard Worker
255*61046927SAndroid Build Coastguard Worker return best_node;
256*61046927SAndroid Build Coastguard Worker }
257