testJitRegisterSet.cpp (6095B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 */ 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 #include "jit/RegisterSets.h" 9 10 #include "jsapi-tests/tests.h" 11 12 using namespace js; 13 using namespace js::jit; 14 15 static bool CoPrime(size_t a, size_t b) { 16 if (b <= 1) { 17 return a == 1 || b == 1; 18 } 19 return CoPrime(b, a % b); 20 } 21 22 // This macros are use to iterave over all registers in a large number of 23 // non-looping sequences, which does not rely on the getFirst / getLast 24 // functions. 25 #define BEGIN_INDEX_WALK(RegTotal) \ 26 static const size_t Total = RegTotal; \ 27 for (size_t walk = 1; walk < RegTotal; walk += 2) { \ 28 if (!CoPrime(RegTotal, walk)) continue; \ 29 for (size_t start = 0; start < RegTotal; start++) { \ 30 size_t index = start; 31 32 #define END_INDEX_WALK \ 33 } \ 34 } 35 36 #define BEGIN_All_WALK(RegTotal) \ 37 static const size_t Total = RegTotal; \ 38 size_t walk = 1; \ 39 size_t start = 0; \ 40 size_t index = start; 41 42 #define FOR_ALL_REGISTERS(Register, reg) \ 43 do { \ 44 Register reg = Register::FromCode(index); 45 46 #define END_FOR_ALL_REGISTERS \ 47 index = (index + walk) % Total; \ 48 } \ 49 while (index != start) 50 51 BEGIN_TEST(testJitRegisterSet_GPR) { 52 BEGIN_INDEX_WALK(Registers::Total) 53 54 LiveGeneralRegisterSet liveRegs; 55 AllocatableGeneralRegisterSet pool(GeneralRegisterSet::All()); 56 CHECK(liveRegs.empty()); 57 CHECK(pool.set() == GeneralRegisterSet::All()); 58 59 FOR_ALL_REGISTERS(Register, reg) { 60 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 61 if (pool.has(reg)) { 62 CHECK(!liveRegs.has(reg)); 63 pool.take(reg); 64 liveRegs.add(reg); 65 CHECK(liveRegs.has(reg)); 66 CHECK(!pool.has(reg)); 67 } 68 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 69 } 70 END_FOR_ALL_REGISTERS; 71 72 CHECK(pool.empty()); 73 74 FOR_ALL_REGISTERS(Register, reg) { 75 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 76 if (liveRegs.has(reg)) { 77 CHECK(!pool.has(reg)); 78 liveRegs.take(reg); 79 pool.add(reg); 80 CHECK(pool.has(reg)); 81 CHECK(!liveRegs.has(reg)); 82 } 83 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 84 } 85 END_FOR_ALL_REGISTERS; 86 87 CHECK(liveRegs.empty()); 88 CHECK(pool.set() == GeneralRegisterSet::All()); 89 90 END_INDEX_WALK 91 return true; 92 } 93 END_TEST(testJitRegisterSet_GPR) 94 95 BEGIN_TEST(testJitRegisterSet_FPU) { 96 BEGIN_INDEX_WALK(FloatRegisters::Total) 97 98 LiveFloatRegisterSet liveRegs; 99 AllocatableFloatRegisterSet pool(FloatRegisterSet::All()); 100 CHECK(liveRegs.empty()); 101 CHECK(pool.set() == FloatRegisterSet::All()); 102 103 FOR_ALL_REGISTERS(FloatRegister, reg) { 104 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 105 if (pool.has(reg)) { 106 CHECK(!liveRegs.has(reg)); 107 pool.take(reg); 108 liveRegs.add(reg); 109 CHECK(liveRegs.has(reg)); 110 CHECK(!pool.has(reg)); 111 } 112 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 113 } 114 END_FOR_ALL_REGISTERS; 115 116 CHECK(pool.empty()); 117 118 FOR_ALL_REGISTERS(FloatRegister, reg) { 119 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 120 if (liveRegs.has(reg)) { 121 CHECK(!pool.has(reg)); 122 liveRegs.take(reg); 123 pool.add(reg); 124 CHECK(pool.has(reg)); 125 CHECK(!liveRegs.has(reg)); 126 } 127 CHECK(!pool.has(reg) || !liveRegs.has(reg)); 128 } 129 END_FOR_ALL_REGISTERS; 130 131 CHECK(liveRegs.empty()); 132 CHECK(pool.set() == FloatRegisterSet::All()); 133 134 END_INDEX_WALK 135 return true; 136 } 137 END_TEST(testJitRegisterSet_FPU) 138 139 void pullAllFpus(AllocatableFloatRegisterSet& set, uint32_t& max_bits, 140 uint32_t bits) { 141 FloatRegisterSet allocSet(set.bits()); 142 FloatRegisterSet available_f32( 143 allocSet.allAllocatable<RegTypeName::Float32>()); 144 FloatRegisterSet available_f64( 145 allocSet.allAllocatable<RegTypeName::Float64>()); 146 FloatRegisterSet available_v128( 147 allocSet.allAllocatable<RegTypeName::Vector128>()); 148 for (FloatRegisterIterator it(available_f32); it.more(); ++it) { 149 FloatRegister tmp = *it; 150 set.take(tmp); 151 pullAllFpus(set, max_bits, bits + 32); 152 set.add(tmp); 153 } 154 for (FloatRegisterIterator it(available_f64); it.more(); ++it) { 155 FloatRegister tmp = *it; 156 set.take(tmp); 157 pullAllFpus(set, max_bits, bits + 64); 158 set.add(tmp); 159 } 160 for (FloatRegisterIterator it(available_v128); it.more(); ++it) { 161 FloatRegister tmp = *it; 162 set.take(tmp); 163 pullAllFpus(set, max_bits, bits + 128); 164 set.add(tmp); 165 } 166 if (bits >= max_bits) { 167 max_bits = bits; 168 } 169 } 170 171 // TODO: MIPS64 only allows calling |alignedAliased| for Double FP registers. 172 // Disable this test for MIPS64 until it's clear that that restriction is 173 // actually correct. (bug 1993738) 174 #ifndef JS_CODEGEN_MIPS64 175 BEGIN_TEST(testJitRegisterSet_FPU_Aliases) { 176 BEGIN_All_WALK(FloatRegisters::Total); 177 FOR_ALL_REGISTERS(FloatRegister, reg) { 178 AllocatableFloatRegisterSet pool; 179 pool.add(reg); 180 181 uint32_t alias_bits = 0; 182 for (uint32_t i = 0; i < reg.numAlignedAliased(); i++) { 183 FloatRegister alias = reg.alignedAliased(i); 184 185 if (alias.isSingle()) { 186 if (alias_bits <= 32) { 187 alias_bits = 32; 188 } 189 } else if (alias.isDouble()) { 190 if (alias_bits <= 64) { 191 alias_bits = 64; 192 } 193 } else if (alias.isSimd128()) { 194 if (alias_bits <= 128) { 195 alias_bits = 128; 196 } 197 } 198 } 199 200 uint32_t max_bits = 0; 201 pullAllFpus(pool, max_bits, 0); 202 203 // By adding one register, we expect that we should not be able to pull 204 // more than any of its aligned aliases. This rule should hold for both 205 // x64 and ARM. 206 CHECK(max_bits <= alias_bits); 207 208 // We added one register, we expect to be able to pull it back. 209 CHECK(max_bits > 0); 210 } 211 END_FOR_ALL_REGISTERS; 212 213 return true; 214 } 215 END_TEST(testJitRegisterSet_FPU_Aliases) 216 #endif