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