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