1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2021 Google LLC
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <gtest/gtest.h>
25bf215546Sopenharmony_ci#include "ralloc.h"
26bf215546Sopenharmony_ci#include "register_allocate.h"
27bf215546Sopenharmony_ci#include "register_allocate_internal.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "util/blob.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ciclass ra_test : public ::testing::Test {
32bf215546Sopenharmony_cipublic:
33bf215546Sopenharmony_ci   void *mem_ctx;
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ciprotected:
36bf215546Sopenharmony_ci   ra_test();
37bf215546Sopenharmony_ci   ~ra_test();
38bf215546Sopenharmony_ci};
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_cira_test::ra_test()
41bf215546Sopenharmony_ci{
42bf215546Sopenharmony_ci   mem_ctx = ralloc_context(NULL);
43bf215546Sopenharmony_ci}
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_cira_test::~ra_test()
46bf215546Sopenharmony_ci{
47bf215546Sopenharmony_ci   ralloc_free(mem_ctx);
48bf215546Sopenharmony_ci}
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_civoid
51bf215546Sopenharmony_cithumb_checks(struct ra_regs *regs, unsigned reg32_base, unsigned reg64_base)
52bf215546Sopenharmony_ci{
53bf215546Sopenharmony_ci   struct ra_class *reg32low = ra_get_class_from_index(regs, 0);
54bf215546Sopenharmony_ci   struct ra_class *reg64low = ra_get_class_from_index(regs, 1);
55bf215546Sopenharmony_ci   struct ra_class *reg96 = ra_get_class_from_index(regs, 2);
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   /* Table 4.1 */
58bf215546Sopenharmony_ci   ASSERT_EQ(reg32low->p, 8);
59bf215546Sopenharmony_ci   ASSERT_EQ(reg32low->q[reg32low->index], 1);
60bf215546Sopenharmony_ci   ASSERT_EQ(reg32low->q[reg64low->index], 2);
61bf215546Sopenharmony_ci   ASSERT_EQ(reg32low->q[reg96->index], 3);
62bf215546Sopenharmony_ci   ASSERT_EQ(reg64low->p, 8);
63bf215546Sopenharmony_ci   ASSERT_EQ(reg64low->q[reg32low->index], 2);
64bf215546Sopenharmony_ci   ASSERT_EQ(reg64low->q[reg64low->index], 3);
65bf215546Sopenharmony_ci   ASSERT_EQ(reg64low->q[reg96->index], 4);
66bf215546Sopenharmony_ci   ASSERT_EQ(reg96->p, 2);
67bf215546Sopenharmony_ci   ASSERT_EQ(reg96->q[reg96->index], 2);
68bf215546Sopenharmony_ci   ASSERT_EQ(reg96->q[reg64low->index], 2);
69bf215546Sopenharmony_ci   ASSERT_EQ(reg96->q[reg96->index], 2);
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   /* These individual regs should conflict with themselves, but nothing else from their class */
72bf215546Sopenharmony_ci   for (int i = 0; i < 7; i++) {
73bf215546Sopenharmony_ci      ASSERT_FALSE(ra_class_allocations_conflict(reg32low, reg32_base + i, reg32low, reg32_base + i + 1));
74bf215546Sopenharmony_ci      ASSERT_TRUE(ra_class_allocations_conflict(reg32low, reg32_base + i, reg32low, reg32_base + i));
75bf215546Sopenharmony_ci   }
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci   /* Check that reg64low conflicts with the pairs of reg32low but not neighbors */
78bf215546Sopenharmony_ci   ASSERT_TRUE(ra_class_allocations_conflict(reg64low, reg64_base + 0, reg32low, reg32_base + 0));
79bf215546Sopenharmony_ci   ASSERT_TRUE(ra_class_allocations_conflict(reg64low, reg64_base + 0, reg32low, reg32_base + 1));
80bf215546Sopenharmony_ci   ASSERT_FALSE(ra_class_allocations_conflict(reg64low, reg64_base + 0, reg32low, reg32_base + 2));
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   ASSERT_FALSE(ra_class_allocations_conflict(reg64low, reg64_base + 1, reg32low, reg32_base + 0));
83bf215546Sopenharmony_ci   ASSERT_TRUE(ra_class_allocations_conflict(reg64low, reg64_base + 1, reg32low, reg32_base + 1));
84bf215546Sopenharmony_ci   ASSERT_TRUE(ra_class_allocations_conflict(reg64low, reg64_base + 1, reg32low, reg32_base + 2));
85bf215546Sopenharmony_ci   ASSERT_FALSE(ra_class_allocations_conflict(reg64low, reg64_base + 1, reg32low, reg32_base + 3));
86bf215546Sopenharmony_ci}
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ciTEST_F(ra_test, thumb)
89bf215546Sopenharmony_ci{
90bf215546Sopenharmony_ci   struct ra_regs *regs = ra_alloc_reg_set(mem_ctx, 100, true);
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   /* r0..15 are the real HW registers. */
93bf215546Sopenharmony_ci   int next_vreg = 16;
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci   /* reg32low is any of the low 8 registers. */
96bf215546Sopenharmony_ci   unsigned int reg32_base = next_vreg;
97bf215546Sopenharmony_ci   struct ra_class *reg32low = ra_alloc_reg_class(regs);
98bf215546Sopenharmony_ci   for (int i = 0; i < 8; i++) {
99bf215546Sopenharmony_ci      int vreg = next_vreg++;
100bf215546Sopenharmony_ci      ra_class_add_reg(reg32low, vreg);
101bf215546Sopenharmony_ci      ra_add_transitive_reg_conflict(regs, i, vreg);
102bf215546Sopenharmony_ci   }
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   /* reg64low is pairs of the low 8 registers (with wraparound!) */
105bf215546Sopenharmony_ci   unsigned int reg64_base = next_vreg;
106bf215546Sopenharmony_ci   struct ra_class *reg64low = ra_alloc_reg_class(regs);
107bf215546Sopenharmony_ci   for (int i = 0; i < 8; i++) {
108bf215546Sopenharmony_ci      int vreg = next_vreg++;
109bf215546Sopenharmony_ci      ra_class_add_reg(reg64low, vreg);
110bf215546Sopenharmony_ci      ra_add_transitive_reg_conflict(regs, i, vreg);
111bf215546Sopenharmony_ci      ra_add_transitive_reg_conflict(regs, (i + 1) % 8, vreg);
112bf215546Sopenharmony_ci   }
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   /* reg96 is one of either r[0..2] or r[1..3] */
115bf215546Sopenharmony_ci   struct ra_class *reg96 = ra_alloc_reg_class(regs);
116bf215546Sopenharmony_ci   for (int i = 0; i < 2; i++) {
117bf215546Sopenharmony_ci      int vreg = next_vreg++;
118bf215546Sopenharmony_ci      ra_class_add_reg(reg96, vreg);
119bf215546Sopenharmony_ci      for (int j = 0; j < 3; j++)
120bf215546Sopenharmony_ci         ra_add_transitive_reg_conflict(regs, i + j, vreg);
121bf215546Sopenharmony_ci   }
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci   ra_set_finalize(regs, NULL);
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   thumb_checks(regs, reg32_base, reg64_base);
126bf215546Sopenharmony_ci}
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ciTEST_F(ra_test, thumb_contigregs)
129bf215546Sopenharmony_ci{
130bf215546Sopenharmony_ci   struct ra_regs *regs = ra_alloc_reg_set(mem_ctx, 16, true);
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   /* reg32low is any of the low 8 registers. */
133bf215546Sopenharmony_ci   struct ra_class *reg32low = ra_alloc_contig_reg_class(regs, 1);
134bf215546Sopenharmony_ci   for (int i = 0; i < 8; i++)
135bf215546Sopenharmony_ci      ra_class_add_reg(reg32low, i);
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   /* reg64low is pairs of the low 8 registers (we're ignoring the wraparound thing here) */
138bf215546Sopenharmony_ci   struct ra_class *reg64low = ra_alloc_contig_reg_class(regs, 2);
139bf215546Sopenharmony_ci   for (int i = 0; i < 8; i++)
140bf215546Sopenharmony_ci      ra_class_add_reg(reg64low, i);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   /* reg96 is one of either r[0..2] or r[1..3] */
143bf215546Sopenharmony_ci   struct ra_class *reg96 = ra_alloc_contig_reg_class(regs, 3);
144bf215546Sopenharmony_ci   for (int i = 0; i < 2; i++)
145bf215546Sopenharmony_ci      ra_class_add_reg(reg96, i);
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   ra_set_finalize(regs, NULL);
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   thumb_checks(regs, 0, 0);
150bf215546Sopenharmony_ci}
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ciTEST_F(ra_test, nonintersect_contigregs)
153bf215546Sopenharmony_ci{
154bf215546Sopenharmony_ci   struct ra_regs *regs = ra_alloc_reg_set(mem_ctx, 16, true);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   struct ra_class *low = ra_alloc_contig_reg_class(regs, 1);
157bf215546Sopenharmony_ci   for (int i = 0; i < 8; i++)
158bf215546Sopenharmony_ci      ra_class_add_reg(low, i);
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   struct ra_class *high = ra_alloc_contig_reg_class(regs, 1);
161bf215546Sopenharmony_ci   for (int i = 8; i < 16; i++)
162bf215546Sopenharmony_ci      ra_class_add_reg(high, i);
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   ra_set_finalize(regs, NULL);
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   ASSERT_EQ(low->q[low->index], 1);
167bf215546Sopenharmony_ci   ASSERT_EQ(low->q[high->index], 0);
168bf215546Sopenharmony_ci   ASSERT_EQ(high->q[low->index], 0);
169bf215546Sopenharmony_ci   ASSERT_EQ(high->q[high->index], 1);
170bf215546Sopenharmony_ci}
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ciTEST_F(ra_test, aligned_contigregs)
173bf215546Sopenharmony_ci{
174bf215546Sopenharmony_ci   int base_regs = 32;
175bf215546Sopenharmony_ci   struct ra_regs *regs = ra_alloc_reg_set(mem_ctx, base_regs, true);
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   struct ra_class *c1 = ra_alloc_contig_reg_class(regs, 1);
178bf215546Sopenharmony_ci   for (int i = 0; i < base_regs; i++)
179bf215546Sopenharmony_ci      ra_class_add_reg(c1, i);
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci   struct ra_class *c2 = ra_alloc_contig_reg_class(regs, 2);
182bf215546Sopenharmony_ci   for (int i = 8; i < base_regs; i += 2)
183bf215546Sopenharmony_ci      ra_class_add_reg(c2, i);
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   struct ra_class *c4 = ra_alloc_contig_reg_class(regs, 4);
186bf215546Sopenharmony_ci   for (int i = 8; i < base_regs; i += 4)
187bf215546Sopenharmony_ci      ra_class_add_reg(c4, i);
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   ra_set_finalize(regs, NULL);
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   ASSERT_EQ(c1->q[c1->index], 1);
192bf215546Sopenharmony_ci   ASSERT_EQ(c1->q[c2->index], 2);
193bf215546Sopenharmony_ci   ASSERT_EQ(c1->q[c4->index], 4);
194bf215546Sopenharmony_ci   ASSERT_EQ(c2->q[c1->index], 1);
195bf215546Sopenharmony_ci   ASSERT_EQ(c2->q[c2->index], 1);
196bf215546Sopenharmony_ci   ASSERT_EQ(c2->q[c4->index], 2);
197bf215546Sopenharmony_ci   ASSERT_EQ(c4->q[c1->index], 1);
198bf215546Sopenharmony_ci   ASSERT_EQ(c4->q[c2->index], 1);
199bf215546Sopenharmony_ci   ASSERT_EQ(c4->q[c4->index], 1);
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   /* Check conflicts for a c4 allocation at i against other classes. */
202bf215546Sopenharmony_ci   for (int i = 0; i < base_regs / 4; i += 4) {
203bf215546Sopenharmony_ci      for (int j = 0; j < base_regs; j++) {
204bf215546Sopenharmony_ci         ASSERT_EQ(ra_class_allocations_conflict(c4, i, c1, j),
205bf215546Sopenharmony_ci                   j >= i && j < i + 4);
206bf215546Sopenharmony_ci      }
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci      for (int j = 0; j < base_regs; j += 2) {
209bf215546Sopenharmony_ci         ASSERT_EQ(ra_class_allocations_conflict(c4, i, c2, j),
210bf215546Sopenharmony_ci                   j >= i && j < i + 4);
211bf215546Sopenharmony_ci      }
212bf215546Sopenharmony_ci   }
213bf215546Sopenharmony_ci}
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ciTEST_F(ra_test, serialization_roundtrip)
216bf215546Sopenharmony_ci{
217bf215546Sopenharmony_ci   struct blob blob;
218bf215546Sopenharmony_ci   blob_init(&blob);
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   for (int i = 0; i < 2; i++) {
221bf215546Sopenharmony_ci      void *mem_ctx = ralloc_context(this->mem_ctx);
222bf215546Sopenharmony_ci      struct ra_regs *regs;
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci      if (i == 0) {
225bf215546Sopenharmony_ci         /* Build a register set and serialize it. */
226bf215546Sopenharmony_ci         regs = ra_alloc_reg_set(mem_ctx, 4 + 4 + 4, true);
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci         struct ra_class *reg8_low = ra_alloc_reg_class(regs);
229bf215546Sopenharmony_ci         struct ra_class *reg8_high = ra_alloc_reg_class(regs);
230bf215546Sopenharmony_ci         struct ra_class *reg16 = ra_alloc_reg_class(regs);
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci         for (int i = 0; i < 4; i++) {
233bf215546Sopenharmony_ci            const unsigned low = 2 * i;
234bf215546Sopenharmony_ci            const unsigned high = low + 1;
235bf215546Sopenharmony_ci            ra_class_add_reg(reg8_low, low);
236bf215546Sopenharmony_ci            ra_class_add_reg(reg8_high, high);
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci            const unsigned both = 8 + i;
239bf215546Sopenharmony_ci            ra_class_add_reg(reg16, 8 + i);
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci            ra_add_reg_conflict(regs, low, both);
242bf215546Sopenharmony_ci            ra_add_reg_conflict(regs, high, both);
243bf215546Sopenharmony_ci         }
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci         ra_set_finalize(regs, NULL);
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci         assert(blob.size == 0);
248bf215546Sopenharmony_ci         ra_set_serialize(regs, &blob);
249bf215546Sopenharmony_ci      } else {
250bf215546Sopenharmony_ci         /* Deserialize the register set. */
251bf215546Sopenharmony_ci         assert(blob.size > 0);
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci         struct blob_reader reader;
254bf215546Sopenharmony_ci         blob_reader_init(&reader, blob.data, blob.size);
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci         regs = ra_set_deserialize(mem_ctx, &reader);
257bf215546Sopenharmony_ci      }
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci      /* Verify the register set for each case. */
260bf215546Sopenharmony_ci      {
261bf215546Sopenharmony_ci         struct ra_class *reg8_low = ra_get_class_from_index(regs, 0);
262bf215546Sopenharmony_ci         ASSERT_EQ(ra_class_index(reg8_low), 0);
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci         struct ra_class *reg8_high = ra_get_class_from_index(regs, 1);
265bf215546Sopenharmony_ci         ASSERT_EQ(ra_class_index(reg8_high), 1);
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci         struct ra_class *reg16 = ra_get_class_from_index(regs, 2);
268bf215546Sopenharmony_ci         ASSERT_EQ(ra_class_index(reg16), 2);
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci         for (int i = 0; i < 4; i++) {
271bf215546Sopenharmony_ci            EXPECT_TRUE(ra_class_allocations_conflict(reg8_low, 2 * i, reg16, 8 + i));
272bf215546Sopenharmony_ci            EXPECT_TRUE(ra_class_allocations_conflict(reg8_high, (2 * i) + 1, reg16, 8 + i));
273bf215546Sopenharmony_ci         }
274bf215546Sopenharmony_ci      }
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci      ralloc_free(mem_ctx);
277bf215546Sopenharmony_ci   }
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   blob_finish(&blob);
280bf215546Sopenharmony_ci}
281bf215546Sopenharmony_ci
282