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 
29 class ra_test : public ::testing::Test {
30 public:
31    void *mem_ctx;
32 
33 protected:
34    ra_test();
35    ~ra_test();
36 };
37 
ra_test()38 ra_test::ra_test()
39 {
40    mem_ctx = ralloc_context(NULL);
41 }
42 
~ra_test()43 ra_test::~ra_test()
44 {
45    ralloc_free(mem_ctx);
46 }
47 
48 void
thumb_checks(struct ra_regs * regs,unsigned reg32_base,unsigned reg64_base)49 thumb_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 
TEST_F(ra_test,thumb)86 TEST_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 
TEST_F(ra_test,thumb_contigregs)126 TEST_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 
TEST_F(ra_test,nonintersect_contigregs)150 TEST_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 
TEST_F(ra_test,aligned_contigregs)170 TEST_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