WasmBCCodegen-inl.h (15400B)
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 basic code generation. 21 22 #ifndef wasm_wasm_baseline_codegen_inl_h 23 #define wasm_wasm_baseline_codegen_inl_h 24 25 // The templates for register management must be defined by the time we use the 26 // templated emitters, below. 27 #include "wasm/WasmBCRegMgmt-inl.h" 28 29 namespace js { 30 namespace wasm { 31 32 ////////////////////////////////////////////////////////////////////////////// 33 // 34 // Register-to-register moves. 35 36 void BaseCompiler::moveI32(RegI32 src, RegI32 dest) { 37 if (src != dest) { 38 masm.move32(src, dest); 39 } 40 } 41 42 void BaseCompiler::moveI64(RegI64 src, RegI64 dest) { 43 if (src != dest) { 44 masm.move64(src, dest); 45 } 46 } 47 48 void BaseCompiler::moveRef(RegRef src, RegRef dest) { 49 if (src != dest) { 50 masm.movePtr(src, dest); 51 } 52 } 53 54 void BaseCompiler::movePtr(RegPtr src, RegPtr dest) { 55 if (src != dest) { 56 masm.movePtr(src, dest); 57 } 58 } 59 60 void BaseCompiler::moveF64(RegF64 src, RegF64 dest) { 61 if (src != dest) { 62 masm.moveDouble(src, dest); 63 } 64 } 65 66 void BaseCompiler::moveF32(RegF32 src, RegF32 dest) { 67 if (src != dest) { 68 masm.moveFloat32(src, dest); 69 } 70 } 71 72 #ifdef ENABLE_WASM_SIMD 73 void BaseCompiler::moveV128(RegV128 src, RegV128 dest) { 74 if (src != dest) { 75 masm.moveSimd128(src, dest); 76 } 77 } 78 #endif 79 80 template <> 81 inline void BaseCompiler::move<RegI32>(RegI32 src, RegI32 dest) { 82 moveI32(src, dest); 83 } 84 85 template <> 86 inline void BaseCompiler::move<RegI64>(RegI64 src, RegI64 dest) { 87 moveI64(src, dest); 88 } 89 90 template <> 91 inline void BaseCompiler::move<RegF32>(RegF32 src, RegF32 dest) { 92 moveF32(src, dest); 93 } 94 95 template <> 96 inline void BaseCompiler::move<RegF64>(RegF64 src, RegF64 dest) { 97 moveF64(src, dest); 98 } 99 100 template <> 101 inline void BaseCompiler::move<RegRef>(RegRef src, RegRef dest) { 102 moveRef(src, dest); 103 } 104 105 template <> 106 inline void BaseCompiler::move<RegPtr>(RegPtr src, RegPtr dest) { 107 movePtr(src, dest); 108 } 109 110 #ifdef ENABLE_WASM_SIMD 111 template <> 112 inline void BaseCompiler::move<RegV128>(RegV128 src, RegV128 dest) { 113 moveV128(src, dest); 114 } 115 #endif 116 117 ////////////////////////////////////////////////////////////////////////////// 118 // 119 // Constant loads. 120 121 void BaseCompiler::moveImm32(int32_t v, RegI32 dest) { 122 masm.move32(Imm32(v), dest); 123 } 124 125 void BaseCompiler::moveImm64(int64_t v, RegI64 dest) { 126 masm.move64(Imm64(v), dest); 127 } 128 129 void BaseCompiler::moveImmRef(intptr_t v, RegRef dest) { 130 masm.movePtr(ImmWord(v), dest); 131 } 132 133 ////////////////////////////////////////////////////////////////////////////// 134 // 135 // Calls. 136 137 RegI32 BaseCompiler::captureReturnedI32() { 138 RegI32 r = RegI32(ReturnReg); 139 MOZ_ASSERT(isAvailableI32(r)); 140 needI32(r); 141 #if defined(JS_64BIT) 142 masm.widenInt32(r); 143 #endif 144 return r; 145 } 146 147 RegI64 BaseCompiler::captureReturnedI64() { 148 RegI64 r = RegI64(ReturnReg64); 149 MOZ_ASSERT(isAvailableI64(r)); 150 needI64(r); 151 return r; 152 } 153 154 RegF32 BaseCompiler::captureReturnedF32(const FunctionCall& call) { 155 RegF32 r = RegF32(ReturnFloat32Reg); 156 MOZ_ASSERT(isAvailableF32(r)); 157 needF32(r); 158 #if defined(JS_CODEGEN_ARM) 159 if ((call.abiKind == ABIKind::System) && !call.hardFP) { 160 masm.ma_vxfer(ReturnReg, r); 161 } 162 #elif defined(JS_CODEGEN_X86) 163 if (call.abiKind == ABIKind::System) { 164 masm.reserveStack(sizeof(float)); 165 Operand op(esp, 0); 166 masm.fstp32(op); 167 masm.loadFloat32(op, ReturnFloat32Reg); 168 masm.freeStack(sizeof(float)); 169 } 170 #endif 171 return r; 172 } 173 174 RegF64 BaseCompiler::captureReturnedF64(const FunctionCall& call) { 175 RegF64 r = RegF64(ReturnDoubleReg); 176 MOZ_ASSERT(isAvailableF64(r)); 177 needF64(r); 178 #if defined(JS_CODEGEN_ARM) 179 if ((call.abiKind == ABIKind::System) && !call.hardFP) { 180 masm.ma_vxfer(ReturnReg64.low, ReturnReg64.high, r); 181 } 182 #elif defined(JS_CODEGEN_X86) 183 if (call.abiKind == ABIKind::System) { 184 masm.reserveStack(sizeof(double)); 185 Operand op(esp, 0); 186 masm.fstp(op); 187 masm.loadDouble(op, ReturnDoubleReg); 188 masm.freeStack(sizeof(double)); 189 } 190 #endif 191 return r; 192 } 193 194 #ifdef ENABLE_WASM_SIMD 195 RegV128 BaseCompiler::captureReturnedV128(const FunctionCall& call) { 196 RegV128 r = RegV128(ReturnSimd128Reg); 197 MOZ_ASSERT(isAvailableV128(r)); 198 needV128(r); 199 return r; 200 } 201 #endif 202 203 RegRef BaseCompiler::captureReturnedRef() { 204 RegRef r = RegRef(ReturnReg); 205 MOZ_ASSERT(isAvailableRef(r)); 206 needRef(r); 207 return r; 208 } 209 210 ////////////////////////////////////////////////////////////////////////////// 211 // 212 // Miscellaneous. 213 214 void BaseCompiler::trap(Trap t) const { masm.wasmTrap(t, trapSiteDesc()); } 215 216 void BaseCompiler::cmp64Set(Assembler::Condition cond, RegI64 lhs, RegI64 rhs, 217 RegI32 dest) { 218 #if defined(JS_PUNBOX64) 219 masm.cmpPtrSet(cond, lhs.reg, rhs.reg, dest); 220 #else 221 // TODO / OPTIMIZE (Bug 1316822): This is pretty branchy, we should be 222 // able to do better. 223 Label done, condTrue; 224 masm.branch64(cond, lhs, rhs, &condTrue); 225 moveImm32(0, dest); 226 masm.jump(&done); 227 masm.bind(&condTrue); 228 moveImm32(1, dest); 229 masm.bind(&done); 230 #endif 231 } 232 233 [[nodiscard]] bool BaseCompiler::supportsRoundInstruction(RoundingMode mode) { 234 return Assembler::HasRoundInstruction(mode); 235 } 236 237 void BaseCompiler::roundF32(RoundingMode roundingMode, RegF32 f0) { 238 masm.nearbyIntFloat32(roundingMode, f0, f0); 239 } 240 241 void BaseCompiler::roundF64(RoundingMode roundingMode, RegF64 f0) { 242 masm.nearbyIntDouble(roundingMode, f0, f0); 243 } 244 245 void BaseCompiler::branchTo(Assembler::DoubleCondition c, RegF64 lhs, 246 RegF64 rhs, Label* l) { 247 masm.branchDouble(c, lhs, rhs, l); 248 } 249 250 void BaseCompiler::branchTo(Assembler::DoubleCondition c, RegF32 lhs, 251 RegF32 rhs, Label* l) { 252 masm.branchFloat(c, lhs, rhs, l); 253 } 254 255 void BaseCompiler::branchTo(Assembler::Condition c, RegI32 lhs, RegI32 rhs, 256 Label* l) { 257 masm.branch32(c, lhs, rhs, l); 258 } 259 260 void BaseCompiler::branchTo(Assembler::Condition c, RegI32 lhs, Imm32 rhs, 261 Label* l) { 262 masm.branch32(c, lhs, rhs, l); 263 } 264 265 void BaseCompiler::branchTo(Assembler::Condition c, RegI64 lhs, RegI64 rhs, 266 Label* l) { 267 masm.branch64(c, lhs, rhs, l); 268 } 269 270 void BaseCompiler::branchTo(Assembler::Condition c, RegI64 lhs, Imm64 rhs, 271 Label* l) { 272 masm.branch64(c, lhs, rhs, l); 273 } 274 275 void BaseCompiler::branchTo(Assembler::Condition c, RegRef lhs, ImmWord rhs, 276 Label* l) { 277 masm.branchPtr(c, lhs, rhs, l); 278 } 279 280 ////////////////////////////////////////////////////////////////////////////// 281 // 282 // Templated emitters 283 284 template <> 285 inline BaseCompiler& BaseCompiler::selectCompiler<BaseCompiler>() { 286 return *this; 287 } 288 289 template <> 290 inline MacroAssembler& BaseCompiler::selectCompiler<MacroAssembler>() { 291 return masm; 292 } 293 294 template <typename SourceType, typename DestType> 295 void BaseCompiler::emitUnop(void (*op)(MacroAssembler& masm, SourceType rs, 296 DestType rd)) { 297 SourceType rs = pop<SourceType>(); 298 DestType rd = need<DestType>(); 299 op(masm, rs, rd); 300 free(rs); 301 push(rd); 302 } 303 304 // Specialize narrowing reuse. Consumers may assume that rs.reg==rd on 64-bit 305 // platforms, or rs.low==rd on 32-bit platforms. 306 template <> 307 inline void BaseCompiler::emitUnop(void (*op)(MacroAssembler& masm, RegI64 rs, 308 RegI32 rd)) { 309 RegI64 rs = pop<RegI64>(); 310 RegI32 rd = fromI64(rs); 311 op(masm, rs, rd); 312 freeI64Except(rs, rd); 313 push(rd); 314 } 315 316 template <typename CompilerType, typename RegType> 317 void BaseCompiler::emitUnop(void (*op)(CompilerType& compiler, RegType rsd)) { 318 RegType rsd = pop<RegType>(); 319 op(selectCompiler<CompilerType>(), rsd); 320 push(rsd); 321 } 322 323 template <typename RegType, typename TempType> 324 void BaseCompiler::emitUnop(void (*op)(BaseCompiler& bc, RegType rsd, 325 TempType rt), 326 TempType (*getSpecializedTemp)(BaseCompiler& bc)) { 327 RegType rsd = pop<RegType>(); 328 TempType temp = getSpecializedTemp(*this); 329 op(*this, rsd, temp); 330 maybeFree(temp); 331 push(rsd); 332 } 333 334 template <typename SourceType, typename DestType, typename TempType> 335 void BaseCompiler::emitUnop(void (*op)(MacroAssembler& masm, SourceType rs, 336 DestType rd, TempType temp)) { 337 SourceType rs = pop<SourceType>(); 338 DestType rd = need<DestType>(); 339 TempType temp = need<TempType>(); 340 op(masm, rs, rd, temp); 341 free(rs); 342 free(temp); 343 push(rd); 344 } 345 346 template <typename SourceType, typename DestType, typename ImmType> 347 void BaseCompiler::emitUnop(ImmType immediate, 348 void (*op)(MacroAssembler&, ImmType, SourceType, 349 DestType)) { 350 SourceType rs = pop<SourceType>(); 351 DestType rd = need<DestType>(); 352 op(masm, immediate, rs, rd); 353 free(rs); 354 push(rd); 355 } 356 357 template <typename CompilerType, typename RhsType, typename LhsDestType> 358 void BaseCompiler::emitBinop(void (*op)(CompilerType& masm, RhsType src, 359 LhsDestType srcDest)) { 360 RhsType rs = pop<RhsType>(); 361 LhsDestType rsd = pop<LhsDestType>(); 362 op(selectCompiler<CompilerType>(), rs, rsd); 363 free(rs); 364 push(rsd); 365 } 366 367 template <typename CompilerType, typename ValType> 368 void BaseCompiler::emitTernary(void (*op)(CompilerType&, ValType src0, 369 ValType src1, ValType srcDest)) { 370 ValType src2 = pop<ValType>(); 371 ValType src1 = pop<ValType>(); 372 ValType srcDest = pop<ValType>(); 373 op(selectCompiler<CompilerType>(), src1, src2, srcDest); 374 free(src2); 375 free(src1); 376 push(srcDest); 377 } 378 379 template <typename CompilerType, typename ValType> 380 void BaseCompiler::emitTernary(void (*op)(CompilerType&, ValType src0, 381 ValType src1, ValType srcDest, 382 ValType temp)) { 383 ValType src2 = pop<ValType>(); 384 ValType src1 = pop<ValType>(); 385 ValType srcDest = pop<ValType>(); 386 ValType temp = need<ValType>(); 387 op(selectCompiler<CompilerType>(), src1, src2, srcDest, temp); 388 free(temp); 389 free(src2); 390 free(src1); 391 push(srcDest); 392 } 393 394 template <typename CompilerType, typename ValType> 395 void BaseCompiler::emitTernaryResultLast(void (*op)(CompilerType&, ValType src0, 396 ValType src1, 397 ValType srcDest)) { 398 ValType srcDest = pop<ValType>(); 399 ValType src2 = pop<ValType>(); 400 ValType src1 = pop<ValType>(); 401 op(selectCompiler<CompilerType>(), src1, src2, srcDest); 402 free(src2); 403 free(src1); 404 push(srcDest); 405 } 406 407 template <typename RhsDestType, typename LhsType> 408 void BaseCompiler::emitBinop(void (*op)(MacroAssembler& masm, RhsDestType src, 409 LhsType srcDest, RhsDestOp)) { 410 RhsDestType rsd = pop<RhsDestType>(); 411 LhsType rs = pop<LhsType>(); 412 op(masm, rsd, rs, RhsDestOp::True); 413 free(rs); 414 push(rsd); 415 } 416 417 template <typename RhsType, typename LhsDestType, typename TempType> 418 void BaseCompiler::emitBinop(void (*op)(MacroAssembler& masm, RhsType rs, 419 LhsDestType rsd, TempType temp)) { 420 RhsType rs = pop<RhsType>(); 421 LhsDestType rsd = pop<LhsDestType>(); 422 TempType temp = need<TempType>(); 423 op(masm, rs, rsd, temp); 424 free(rs); 425 free(temp); 426 push(rsd); 427 } 428 429 template <typename RhsType, typename LhsDestType, typename TempType1, 430 typename TempType2> 431 void BaseCompiler::emitBinop(void (*op)(MacroAssembler& masm, RhsType rs, 432 LhsDestType rsd, TempType1 temp1, 433 TempType2 temp2)) { 434 RhsType rs = pop<RhsType>(); 435 LhsDestType rsd = pop<LhsDestType>(); 436 TempType1 temp1 = need<TempType1>(); 437 TempType2 temp2 = need<TempType2>(); 438 op(masm, rs, rsd, temp1, temp2); 439 free(rs); 440 free(temp1); 441 free(temp2); 442 push(rsd); 443 } 444 445 template <typename RhsType, typename LhsDestType, typename ImmType> 446 void BaseCompiler::emitBinop(ImmType immediate, 447 void (*op)(MacroAssembler&, ImmType, RhsType, 448 LhsDestType)) { 449 RhsType rs = pop<RhsType>(); 450 LhsDestType rsd = pop<LhsDestType>(); 451 op(masm, immediate, rs, rsd); 452 free(rs); 453 push(rsd); 454 } 455 456 template <typename RhsType, typename LhsDestType, typename ImmType, 457 typename TempType1, typename TempType2> 458 void BaseCompiler::emitBinop(ImmType immediate, 459 void (*op)(MacroAssembler&, ImmType, RhsType, 460 LhsDestType, TempType1 temp1, 461 TempType2 temp2)) { 462 RhsType rs = pop<RhsType>(); 463 LhsDestType rsd = pop<LhsDestType>(); 464 TempType1 temp1 = need<TempType1>(); 465 TempType2 temp2 = need<TempType2>(); 466 op(masm, immediate, rs, rsd, temp1, temp2); 467 free(rs); 468 free(temp1); 469 free(temp2); 470 push(rsd); 471 } 472 473 template <typename CompilerType1, typename CompilerType2, typename RegType, 474 typename ImmType> 475 void BaseCompiler::emitBinop(void (*op)(CompilerType1& compiler, RegType rs, 476 RegType rsd), 477 void (*opConst)(CompilerType2& compiler, ImmType c, 478 RegType rsd), 479 RegType (BaseCompiler::*rhsPopper)()) { 480 ImmType c; 481 if (popConst(&c)) { 482 RegType rsd = pop<RegType>(); 483 opConst(selectCompiler<CompilerType2>(), c, rsd); 484 push(rsd); 485 } else { 486 RegType rs = rhsPopper ? (this->*rhsPopper)() : pop<RegType>(); 487 RegType rsd = pop<RegType>(); 488 op(selectCompiler<CompilerType1>(), rs, rsd); 489 free(rs); 490 push(rsd); 491 } 492 } 493 494 template <typename R> 495 bool BaseCompiler::emitInstanceCallOp(const SymbolicAddressSignature& fn, 496 R reader) { 497 if (!reader()) { 498 return false; 499 } 500 if (deadCode_) { 501 return true; 502 } 503 return emitInstanceCall(fn); 504 } 505 506 template <typename A1, typename R> 507 bool BaseCompiler::emitInstanceCallOp(const SymbolicAddressSignature& fn, 508 R reader) { 509 A1 arg = 0; 510 if (!reader(&arg)) { 511 return false; 512 } 513 if (deadCode_) { 514 return true; 515 } 516 push(arg); 517 return emitInstanceCall(fn); 518 } 519 520 template <typename A1, typename A2, typename R> 521 bool BaseCompiler::emitInstanceCallOp(const SymbolicAddressSignature& fn, 522 R reader) { 523 A1 arg1 = 0; 524 A2 arg2 = 0; 525 if (!reader(&arg1, &arg2)) { 526 return false; 527 } 528 if (deadCode_) { 529 return true; 530 } 531 // Note order of arguments must be the same as for the reader. 532 push(arg1); 533 push(arg2); 534 return emitInstanceCall(fn); 535 } 536 537 } // namespace wasm 538 } // namespace js 539 540 #endif // wasm_wasm_baseline_codegen_inl_h