WasmBCRegMgmt-inl.h (11907B)
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 * Copyright 2016 Mozilla Foundation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 // This is an INTERNAL header for Wasm baseline compiler: inline methods in the 20 // compiler for register management. 21 22 #ifndef wasm_wasm_baseline_reg_mgmt_inl_h 23 #define wasm_wasm_baseline_reg_mgmt_inl_h 24 25 namespace js { 26 namespace wasm { 27 28 bool BaseCompiler::isAvailableI32(RegI32 r) { return ra.isAvailableI32(r); } 29 bool BaseCompiler::isAvailableI64(RegI64 r) { return ra.isAvailableI64(r); } 30 bool BaseCompiler::isAvailableRef(RegRef r) { return ra.isAvailableRef(r); } 31 bool BaseCompiler::isAvailablePtr(RegPtr r) { return ra.isAvailablePtr(r); } 32 bool BaseCompiler::isAvailableF32(RegF32 r) { return ra.isAvailableF32(r); } 33 bool BaseCompiler::isAvailableF64(RegF64 r) { return ra.isAvailableF64(r); } 34 #ifdef ENABLE_WASM_SIMD 35 bool BaseCompiler::isAvailableV128(RegV128 r) { return ra.isAvailableV128(r); } 36 #endif 37 38 [[nodiscard]] RegI32 BaseCompiler::needI32() { return ra.needI32(); } 39 [[nodiscard]] RegI64 BaseCompiler::needI64() { return ra.needI64(); } 40 [[nodiscard]] RegRef BaseCompiler::needRef() { return ra.needRef(); } 41 [[nodiscard]] RegPtr BaseCompiler::needPtr() { return ra.needPtr(); } 42 [[nodiscard]] RegF32 BaseCompiler::needF32() { return ra.needF32(); } 43 [[nodiscard]] RegF64 BaseCompiler::needF64() { return ra.needF64(); } 44 #ifdef ENABLE_WASM_SIMD 45 [[nodiscard]] RegV128 BaseCompiler::needV128() { return ra.needV128(); } 46 #endif 47 48 void BaseCompiler::needI32(RegI32 specific) { ra.needI32(specific); } 49 void BaseCompiler::needI64(RegI64 specific) { ra.needI64(specific); } 50 void BaseCompiler::needRef(RegRef specific) { ra.needRef(specific); } 51 void BaseCompiler::needPtr(RegPtr specific) { ra.needPtr(specific); } 52 void BaseCompiler::needF32(RegF32 specific) { ra.needF32(specific); } 53 void BaseCompiler::needF64(RegF64 specific) { ra.needF64(specific); } 54 #ifdef ENABLE_WASM_SIMD 55 void BaseCompiler::needV128(RegV128 specific) { ra.needV128(specific); } 56 #endif 57 58 #if defined(JS_CODEGEN_ARM) 59 [[nodiscard]] RegI64 BaseCompiler::needI64Pair() { return ra.needI64Pair(); } 60 #endif 61 62 void BaseCompiler::freeI32(RegI32 r) { ra.freeI32(r); } 63 void BaseCompiler::freeI64(RegI64 r) { ra.freeI64(r); } 64 void BaseCompiler::freeRef(RegRef r) { ra.freeRef(r); } 65 void BaseCompiler::freePtr(RegPtr r) { ra.freePtr(r); } 66 void BaseCompiler::freeF32(RegF32 r) { ra.freeF32(r); } 67 void BaseCompiler::freeF64(RegF64 r) { ra.freeF64(r); } 68 #ifdef ENABLE_WASM_SIMD 69 void BaseCompiler::freeV128(RegV128 r) { ra.freeV128(r); } 70 #endif 71 72 void BaseCompiler::freeAny(AnyReg r) { 73 switch (r.tag) { 74 case AnyReg::I32: 75 freeI32(r.i32()); 76 break; 77 case AnyReg::I64: 78 freeI64(r.i64()); 79 break; 80 case AnyReg::REF: 81 freeRef(r.ref()); 82 break; 83 case AnyReg::F32: 84 freeF32(r.f32()); 85 break; 86 case AnyReg::F64: 87 freeF64(r.f64()); 88 break; 89 #ifdef ENABLE_WASM_SIMD 90 case AnyReg::V128: 91 freeV128(r.v128()); 92 break; 93 #endif 94 default: 95 MOZ_CRASH(); 96 } 97 } 98 99 template <> 100 inline void BaseCompiler::free<RegI32>(RegI32 r) { 101 freeI32(r); 102 } 103 104 template <> 105 inline void BaseCompiler::free<RegI64>(RegI64 r) { 106 freeI64(r); 107 } 108 109 template <> 110 inline void BaseCompiler::free<RegRef>(RegRef r) { 111 freeRef(r); 112 } 113 114 template <> 115 inline void BaseCompiler::free<RegPtr>(RegPtr r) { 116 freePtr(r); 117 } 118 119 template <> 120 inline void BaseCompiler::free<RegF32>(RegF32 r) { 121 freeF32(r); 122 } 123 124 template <> 125 inline void BaseCompiler::free<RegF64>(RegF64 r) { 126 freeF64(r); 127 } 128 129 #ifdef ENABLE_WASM_SIMD 130 template <> 131 inline void BaseCompiler::free<RegV128>(RegV128 r) { 132 freeV128(r); 133 } 134 #endif 135 136 template <> 137 inline void BaseCompiler::free<AnyReg>(AnyReg r) { 138 freeAny(r); 139 } 140 141 void BaseCompiler::freeI64Except(RegI64 r, RegI32 except) { 142 #ifdef JS_PUNBOX64 143 MOZ_ASSERT(r.reg == except); 144 #else 145 MOZ_ASSERT(r.high == except || r.low == except); 146 freeI64(r); 147 needI32(except); 148 #endif 149 } 150 151 void BaseCompiler::maybeFree(RegI32 r) { 152 if (r.isValid()) { 153 freeI32(r); 154 } 155 } 156 157 void BaseCompiler::maybeFree(RegI64 r) { 158 if (r.isValid()) { 159 freeI64(r); 160 } 161 } 162 163 void BaseCompiler::maybeFree(RegF32 r) { 164 if (r.isValid()) { 165 freeF32(r); 166 } 167 } 168 169 void BaseCompiler::maybeFree(RegF64 r) { 170 if (r.isValid()) { 171 freeF64(r); 172 } 173 } 174 175 void BaseCompiler::maybeFree(RegRef r) { 176 if (r.isValid()) { 177 freeRef(r); 178 } 179 } 180 181 void BaseCompiler::maybeFree(RegPtr r) { 182 if (r.isValid()) { 183 freePtr(r); 184 } 185 } 186 187 #ifdef ENABLE_WASM_SIMD128 188 void BaseCompiler::maybeFree(RegV128 r) { 189 if (r.isValid()) { 190 freeV128(r); 191 } 192 } 193 #endif 194 195 void BaseCompiler::needI32NoSync(RegI32 r) { 196 MOZ_ASSERT(isAvailableI32(r)); 197 needI32(r); 198 } 199 200 // TODO / OPTIMIZE: need2xI32() can be optimized along with needI32() 201 // to avoid sync(). (Bug 1316802) 202 203 void BaseCompiler::need2xI32(RegI32 r0, RegI32 r1) { 204 needI32(r0); 205 needI32(r1); 206 } 207 208 void BaseCompiler::need2xI64(RegI64 r0, RegI64 r1) { 209 needI64(r0); 210 needI64(r1); 211 } 212 213 RegI32 BaseCompiler::fromI64(RegI64 r) { return RegI32(lowPart(r)); } 214 215 RegI32 BaseCompiler::maybeFromI64(RegI64 r) { 216 if (!r.isValid()) { 217 return RegI32::Invalid(); 218 } 219 return fromI64(r); 220 } 221 222 #ifdef JS_PUNBOX64 223 RegI64 BaseCompiler::fromI32(RegI32 r) { return RegI64(Register64(r)); } 224 #endif 225 226 RegI64 BaseCompiler::widenI32(RegI32 r) { 227 MOZ_ASSERT(!isAvailableI32(r)); 228 #ifdef JS_PUNBOX64 229 return fromI32(r); 230 #else 231 RegI32 high = needI32(); 232 return RegI64(Register64(high, r)); 233 #endif 234 } 235 236 RegI32 BaseCompiler::narrowI64(RegI64 r) { 237 #ifdef JS_PUNBOX64 238 return RegI32(r.reg); 239 #else 240 freeI32(RegI32(r.high)); 241 return RegI32(r.low); 242 #endif 243 } 244 245 RegI32 BaseCompiler::narrowRef(RegRef r) { return RegI32(r); } 246 247 RegI32 BaseCompiler::lowPart(RegI64 r) { 248 #ifdef JS_PUNBOX64 249 return RegI32(r.reg); 250 #else 251 return RegI32(r.low); 252 #endif 253 } 254 255 RegI32 BaseCompiler::maybeHighPart(RegI64 r) { 256 #ifdef JS_PUNBOX64 257 return RegI32::Invalid(); 258 #else 259 return RegI32(r.high); 260 #endif 261 } 262 263 // TODO: We want these to be inlined for sure; do we need an `inline` somewhere? 264 265 template <> 266 inline RegI32 BaseCompiler::need<RegI32>() { 267 return needI32(); 268 } 269 template <> 270 inline RegI64 BaseCompiler::need<RegI64>() { 271 return needI64(); 272 } 273 template <> 274 inline RegF32 BaseCompiler::need<RegF32>() { 275 return needF32(); 276 } 277 template <> 278 inline RegF64 BaseCompiler::need<RegF64>() { 279 return needF64(); 280 } 281 282 template <> 283 inline RegI32 BaseCompiler::pop<RegI32>() { 284 return popI32(); 285 } 286 template <> 287 inline RegI64 BaseCompiler::pop<RegI64>() { 288 return popI64(); 289 } 290 template <> 291 inline RegF32 BaseCompiler::pop<RegF32>() { 292 return popF32(); 293 } 294 template <> 295 inline RegF64 BaseCompiler::pop<RegF64>() { 296 return popF64(); 297 } 298 299 #ifdef ENABLE_WASM_SIMD 300 template <> 301 inline RegV128 BaseCompiler::need<RegV128>() { 302 return needV128(); 303 } 304 template <> 305 inline RegV128 BaseCompiler::pop<RegV128>() { 306 return popV128(); 307 } 308 #endif 309 310 // RegPtr values can't be pushed, hence can't be popped. 311 template <> 312 inline RegPtr BaseCompiler::need<RegPtr>() { 313 return needPtr(); 314 } 315 316 void BaseCompiler::needResultRegisters(ResultType type, ResultRegKind which) { 317 if (type.empty()) { 318 return; 319 } 320 321 for (ABIResultIter iter(type); !iter.done(); iter.next()) { 322 ABIResult result = iter.cur(); 323 // Register results are visited first; when we see a stack result we're 324 // done. 325 if (!result.inRegister()) { 326 return; 327 } 328 switch (result.type().kind()) { 329 case ValType::I32: 330 needI32(RegI32(result.gpr())); 331 break; 332 case ValType::I64: 333 needI64(RegI64(result.gpr64())); 334 break; 335 case ValType::V128: 336 #ifdef ENABLE_WASM_SIMD 337 if (which == ResultRegKind::All) { 338 needV128(RegV128(result.fpr())); 339 } 340 break; 341 #else 342 MOZ_CRASH("No SIMD support"); 343 #endif 344 case ValType::F32: 345 if (which == ResultRegKind::All) { 346 needF32(RegF32(result.fpr())); 347 } 348 break; 349 case ValType::F64: 350 if (which == ResultRegKind::All) { 351 needF64(RegF64(result.fpr())); 352 } 353 break; 354 case ValType::Ref: 355 needRef(RegRef(result.gpr())); 356 break; 357 } 358 } 359 } 360 361 #ifdef JS_64BIT 362 void BaseCompiler::widenInt32ResultRegisters(ResultType type) { 363 if (type.empty()) { 364 return; 365 } 366 367 for (ABIResultIter iter(type); !iter.done(); iter.next()) { 368 ABIResult result = iter.cur(); 369 if (result.inRegister() && result.type().kind() == ValType::I32) { 370 masm.widenInt32(result.gpr()); 371 } 372 } 373 } 374 #endif 375 376 void BaseCompiler::freeResultRegisters(ResultType type, ResultRegKind which) { 377 if (type.empty()) { 378 return; 379 } 380 381 for (ABIResultIter iter(type); !iter.done(); iter.next()) { 382 ABIResult result = iter.cur(); 383 // Register results are visited first; when we see a stack result we're 384 // done. 385 if (!result.inRegister()) { 386 return; 387 } 388 switch (result.type().kind()) { 389 case ValType::I32: 390 freeI32(RegI32(result.gpr())); 391 break; 392 case ValType::I64: 393 freeI64(RegI64(result.gpr64())); 394 break; 395 case ValType::V128: 396 #ifdef ENABLE_WASM_SIMD 397 if (which == ResultRegKind::All) { 398 freeV128(RegV128(result.fpr())); 399 } 400 break; 401 #else 402 MOZ_CRASH("No SIMD support"); 403 #endif 404 case ValType::F32: 405 if (which == ResultRegKind::All) { 406 freeF32(RegF32(result.fpr())); 407 } 408 break; 409 case ValType::F64: 410 if (which == ResultRegKind::All) { 411 freeF64(RegF64(result.fpr())); 412 } 413 break; 414 case ValType::Ref: 415 freeRef(RegRef(result.gpr())); 416 break; 417 } 418 } 419 } 420 421 void BaseCompiler::needIntegerResultRegisters(ResultType type) { 422 needResultRegisters(type, ResultRegKind::OnlyGPRs); 423 } 424 425 void BaseCompiler::freeIntegerResultRegisters(ResultType type) { 426 freeResultRegisters(type, ResultRegKind::OnlyGPRs); 427 } 428 429 void BaseCompiler::needResultRegisters(ResultType type) { 430 needResultRegisters(type, ResultRegKind::All); 431 } 432 433 void BaseCompiler::freeResultRegisters(ResultType type) { 434 freeResultRegisters(type, ResultRegKind::All); 435 } 436 437 void BaseCompiler::captureResultRegisters(ResultType type) { 438 assertResultRegistersAvailable(type); 439 needResultRegisters(type); 440 } 441 442 void BaseCompiler::captureCallResultRegisters(ResultType type) { 443 captureResultRegisters(type); 444 #ifdef JS_64BIT 445 widenInt32ResultRegisters(type); 446 #endif 447 } 448 449 ////////////////////////////////////////////////////////////////////////////// 450 // 451 // Control stack. Some of these are very hot. 452 453 void BaseCompiler::initControl(Control& item, ResultType params) { 454 // Make sure the constructor was run properly 455 MOZ_ASSERT(!item.stackHeight.isValid() && item.stackSize == UINT32_MAX); 456 457 uint32_t paramCount = deadCode_ ? 0 : params.length(); 458 uint32_t stackParamSize = stackConsumed(paramCount); 459 item.stackHeight = fr.stackResultsBase(stackParamSize); 460 item.stackSize = stk_.length() - paramCount; 461 item.deadOnArrival = deadCode_; 462 item.bceSafeOnEntry = bceSafe_; 463 } 464 465 Control& BaseCompiler::controlItem() { return iter_.controlItem(); } 466 467 Control& BaseCompiler::controlItem(uint32_t relativeDepth) { 468 return iter_.controlItem(relativeDepth); 469 } 470 471 Control& BaseCompiler::controlOutermost() { return iter_.controlOutermost(); } 472 473 LabelKind BaseCompiler::controlKind(uint32_t relativeDepth) { 474 return iter_.controlKind(relativeDepth); 475 } 476 477 } // namespace wasm 478 } // namespace js 479 480 #endif // wasm_wasm_baseline_reg_mgmt_inl_h