Bug 1695778 - (Core-Wasm-EH-Ion) part 4: Support reftypes in exceptions. r=rhunt
[gecko.git] / js / src / jit / Lowering.cpp
blob7a219053862dae1994b024bb80963ab185c4bf7d
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 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/Lowering.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/EndianUtils.h"
11 #include "mozilla/FloatingPoint.h"
12 #include "mozilla/MathAlgorithms.h"
14 #include <type_traits>
16 #include "jit/ABIArgGenerator.h"
17 #include "jit/IonOptimizationLevels.h"
18 #include "jit/JitSpewer.h"
19 #include "jit/LIR.h"
20 #include "jit/MIR.h"
21 #include "jit/MIRGraph.h"
22 #include "jit/SharedICRegisters.h"
23 #include "js/experimental/JitInfo.h" // JSJitInfo
24 #include "util/Memory.h"
25 #include "wasm/WasmCodegenTypes.h"
26 #include "wasm/WasmJS.h" // for wasm::ReportSimdAnalysis
27 #include "wasm/WasmTlsData.h"
29 #include "jit/shared/Lowering-shared-inl.h"
30 #include "vm/BytecodeUtil-inl.h"
32 using namespace js;
33 using namespace jit;
35 using JS::GenericNaN;
36 using mozilla::DebugOnly;
38 LBoxAllocation LIRGenerator::useBoxFixedAtStart(MDefinition* mir,
39 ValueOperand op) {
40 #if defined(JS_NUNBOX32)
41 return useBoxFixed(mir, op.typeReg(), op.payloadReg(), true);
42 #elif defined(JS_PUNBOX64)
43 return useBoxFixed(mir, op.valueReg(), op.scratchReg(), true);
44 #endif
47 LBoxAllocation LIRGenerator::useBoxAtStart(MDefinition* mir,
48 LUse::Policy policy) {
49 return useBox(mir, policy, /* useAtStart = */ true);
52 void LIRGenerator::visitParameter(MParameter* param) {
53 ptrdiff_t offset;
54 if (param->index() == MParameter::THIS_SLOT) {
55 offset = THIS_FRAME_ARGSLOT;
56 } else {
57 offset = 1 + param->index();
60 LParameter* ins = new (alloc()) LParameter;
61 defineBox(ins, param, LDefinition::FIXED);
63 offset *= sizeof(Value);
64 #if defined(JS_NUNBOX32)
65 # if MOZ_BIG_ENDIAN()
66 ins->getDef(0)->setOutput(LArgument(offset));
67 ins->getDef(1)->setOutput(LArgument(offset + 4));
68 # else
69 ins->getDef(0)->setOutput(LArgument(offset + 4));
70 ins->getDef(1)->setOutput(LArgument(offset));
71 # endif
72 #elif defined(JS_PUNBOX64)
73 ins->getDef(0)->setOutput(LArgument(offset));
74 #endif
77 void LIRGenerator::visitCallee(MCallee* ins) {
78 define(new (alloc()) LCallee(), ins);
81 void LIRGenerator::visitIsConstructing(MIsConstructing* ins) {
82 define(new (alloc()) LIsConstructing(), ins);
85 void LIRGenerator::visitGoto(MGoto* ins) {
86 add(new (alloc()) LGoto(ins->target()));
89 void LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch) {
90 MDefinition* opd = tableswitch->getOperand(0);
92 // There should be at least 1 successor. The default case!
93 MOZ_ASSERT(tableswitch->numSuccessors() > 0);
95 // If there are no cases, the default case is always taken.
96 if (tableswitch->numSuccessors() == 1) {
97 add(new (alloc()) LGoto(tableswitch->getDefault()));
98 return;
101 // If we don't know the type.
102 if (opd->type() == MIRType::Value) {
103 LTableSwitchV* lir = newLTableSwitchV(tableswitch);
104 add(lir);
105 return;
108 // Case indices are numeric, so other types will always go to the default
109 // case.
110 if (opd->type() != MIRType::Int32 && opd->type() != MIRType::Double) {
111 add(new (alloc()) LGoto(tableswitch->getDefault()));
112 return;
115 // Return an LTableSwitch, capable of handling either an integer or
116 // floating-point index.
117 LAllocation index;
118 LDefinition tempInt;
119 if (opd->type() == MIRType::Int32) {
120 index = useRegisterAtStart(opd);
121 tempInt = tempCopy(opd, 0);
122 } else {
123 index = useRegister(opd);
124 tempInt = temp(LDefinition::GENERAL);
126 add(newLTableSwitch(index, tempInt, tableswitch));
129 void LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed* ins) {
130 LCheckOverRecursed* lir = new (alloc()) LCheckOverRecursed();
131 add(lir, ins);
132 assignSafepoint(lir, ins);
135 void LIRGenerator::visitNewArray(MNewArray* ins) {
136 LNewArray* lir = new (alloc()) LNewArray(temp());
137 define(lir, ins);
138 assignSafepoint(lir, ins);
141 void LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength* ins) {
142 MDefinition* length = ins->length();
143 MOZ_ASSERT(length->type() == MIRType::Int32);
145 LNewArrayDynamicLength* lir =
146 new (alloc()) LNewArrayDynamicLength(useRegister(length), temp());
147 define(lir, ins);
148 assignSafepoint(lir, ins);
151 void LIRGenerator::visitNewIterator(MNewIterator* ins) {
152 LNewIterator* lir = new (alloc()) LNewIterator(temp());
153 define(lir, ins);
154 assignSafepoint(lir, ins);
157 void LIRGenerator::visitNewTypedArray(MNewTypedArray* ins) {
158 LNewTypedArray* lir = new (alloc()) LNewTypedArray(temp(), temp());
159 define(lir, ins);
160 assignSafepoint(lir, ins);
163 void LIRGenerator::visitNewTypedArrayDynamicLength(
164 MNewTypedArrayDynamicLength* ins) {
165 MDefinition* length = ins->length();
166 MOZ_ASSERT(length->type() == MIRType::Int32);
168 LNewTypedArrayDynamicLength* lir =
169 new (alloc()) LNewTypedArrayDynamicLength(useRegister(length), temp());
170 define(lir, ins);
171 assignSafepoint(lir, ins);
174 void LIRGenerator::visitNewTypedArrayFromArray(MNewTypedArrayFromArray* ins) {
175 MDefinition* array = ins->array();
176 MOZ_ASSERT(array->type() == MIRType::Object);
178 auto* lir = new (alloc()) LNewTypedArrayFromArray(useRegisterAtStart(array));
179 defineReturn(lir, ins);
180 assignSafepoint(lir, ins);
183 void LIRGenerator::visitNewTypedArrayFromArrayBuffer(
184 MNewTypedArrayFromArrayBuffer* ins) {
185 MDefinition* arrayBuffer = ins->arrayBuffer();
186 MDefinition* byteOffset = ins->byteOffset();
187 MDefinition* length = ins->length();
188 MOZ_ASSERT(arrayBuffer->type() == MIRType::Object);
189 MOZ_ASSERT(byteOffset->type() == MIRType::Value);
190 MOZ_ASSERT(length->type() == MIRType::Value);
192 auto* lir = new (alloc()) LNewTypedArrayFromArrayBuffer(
193 useRegisterAtStart(arrayBuffer), useBoxAtStart(byteOffset),
194 useBoxAtStart(length));
195 defineReturn(lir, ins);
196 assignSafepoint(lir, ins);
199 void LIRGenerator::visitNewObject(MNewObject* ins) {
200 LNewObject* lir = new (alloc()) LNewObject(temp());
201 define(lir, ins);
202 assignSafepoint(lir, ins);
205 void LIRGenerator::visitNewPlainObject(MNewPlainObject* ins) {
206 LNewPlainObject* lir = new (alloc()) LNewPlainObject(temp(), temp(), temp());
207 define(lir, ins);
208 assignSafepoint(lir, ins);
211 void LIRGenerator::visitNewArrayObject(MNewArrayObject* ins) {
212 LNewArrayObject* lir = new (alloc()) LNewArrayObject(temp(), temp());
213 define(lir, ins);
214 assignSafepoint(lir, ins);
217 void LIRGenerator::visitNewNamedLambdaObject(MNewNamedLambdaObject* ins) {
218 LNewNamedLambdaObject* lir = new (alloc()) LNewNamedLambdaObject(temp());
219 define(lir, ins);
220 assignSafepoint(lir, ins);
223 void LIRGenerator::visitNewCallObject(MNewCallObject* ins) {
224 LNewCallObject* lir = new (alloc()) LNewCallObject(temp());
225 define(lir, ins);
226 assignSafepoint(lir, ins);
229 void LIRGenerator::visitNewStringObject(MNewStringObject* ins) {
230 MOZ_ASSERT(ins->input()->type() == MIRType::String);
232 LNewStringObject* lir =
233 new (alloc()) LNewStringObject(useRegister(ins->input()), temp());
234 define(lir, ins);
235 assignSafepoint(lir, ins);
238 void LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter* ins) {
239 LInitElemGetterSetter* lir = new (alloc()) LInitElemGetterSetter(
240 useRegisterAtStart(ins->object()), useBoxAtStart(ins->id()),
241 useRegisterAtStart(ins->value()));
242 add(lir, ins);
243 assignSafepoint(lir, ins);
246 void LIRGenerator::visitMutateProto(MMutateProto* ins) {
247 LMutateProto* lir = new (alloc()) LMutateProto(
248 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
249 add(lir, ins);
250 assignSafepoint(lir, ins);
253 void LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter* ins) {
254 LInitPropGetterSetter* lir = new (alloc()) LInitPropGetterSetter(
255 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->value()));
256 add(lir, ins);
257 assignSafepoint(lir, ins);
260 void LIRGenerator::visitCreateThis(MCreateThis* ins) {
261 LCreateThis* lir =
262 new (alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->callee()),
263 useRegisterOrConstantAtStart(ins->newTarget()));
264 defineReturn(lir, ins);
265 assignSafepoint(lir, ins);
268 void LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject* ins) {
269 LAllocation callObj = useRegisterAtStart(ins->getCallObject());
270 LCreateArgumentsObject* lir = new (alloc())
271 LCreateArgumentsObject(callObj, tempFixed(CallTempReg0),
272 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
273 defineReturn(lir, ins);
274 assignSafepoint(lir, ins);
277 void LIRGenerator::visitCreateInlinedArgumentsObject(
278 MCreateInlinedArgumentsObject* ins) {
279 LAllocation callObj = useRegisterAtStart(ins->getCallObject());
280 LAllocation callee = useRegisterAtStart(ins->getCallee());
281 uint32_t numActuals = ins->numActuals();
282 uint32_t numOperands = numActuals * BOX_PIECES +
283 LCreateInlinedArgumentsObject::NumNonArgumentOperands;
285 auto* lir = allocateVariadic<LCreateInlinedArgumentsObject>(
286 numOperands, tempFixed(CallTempReg0));
287 if (!lir) {
288 abort(AbortReason::Alloc,
289 "OOM: LIRGenerator::visitCreateInlinedArgumentsObject");
290 return;
293 lir->setOperand(LCreateInlinedArgumentsObject::CallObj, callObj);
294 lir->setOperand(LCreateInlinedArgumentsObject::Callee, callee);
295 for (uint32_t i = 0; i < numActuals; i++) {
296 MDefinition* arg = ins->getArg(i);
297 uint32_t index = LCreateInlinedArgumentsObject::ArgIndex(i);
298 lir->setBoxOperand(index, useBoxOrTypedOrConstant(arg,
299 /*useConstant = */ true,
300 /*useAtStart = */ true));
303 defineReturn(lir, ins);
304 assignSafepoint(lir, ins);
307 void LIRGenerator::visitGetInlinedArgument(MGetInlinedArgument* ins) {
308 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_MIPS64)
309 // On some 64-bit architectures, we don't support boxing a typed
310 // register in-place without using a scratch register, so the result
311 // register can't be the same as any of the inputs. Fortunately,
312 // those architectures have registers to spare.
313 const bool useAtStart = false;
314 #else
315 const bool useAtStart = true;
316 #endif
318 LAllocation index =
319 useAtStart ? useRegisterAtStart(ins->index()) : useRegister(ins->index());
320 uint32_t numActuals = ins->numActuals();
321 uint32_t numOperands =
322 numActuals * BOX_PIECES + LGetInlinedArgument::NumNonArgumentOperands;
324 auto* lir = allocateVariadic<LGetInlinedArgument>(numOperands);
325 if (!lir) {
326 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgument");
327 return;
330 lir->setOperand(LGetInlinedArgument::Index, index);
331 for (uint32_t i = 0; i < numActuals; i++) {
332 MDefinition* arg = ins->getArg(i);
333 uint32_t index = LGetInlinedArgument::ArgIndex(i);
334 lir->setBoxOperand(
335 index, useBoxOrTypedOrConstant(arg,
336 /*useConstant = */ true, useAtStart));
338 defineBox(lir, ins);
341 void LIRGenerator::visitGetInlinedArgumentHole(MGetInlinedArgumentHole* ins) {
342 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_MIPS64)
343 // On some 64-bit architectures, we don't support boxing a typed
344 // register in-place without using a scratch register, so the result
345 // register can't be the same as any of the inputs. Fortunately,
346 // those architectures have registers to spare.
347 const bool useAtStart = false;
348 #else
349 const bool useAtStart = true;
350 #endif
352 LAllocation index =
353 useAtStart ? useRegisterAtStart(ins->index()) : useRegister(ins->index());
354 uint32_t numActuals = ins->numActuals();
355 uint32_t numOperands =
356 numActuals * BOX_PIECES + LGetInlinedArgumentHole::NumNonArgumentOperands;
358 auto* lir = allocateVariadic<LGetInlinedArgumentHole>(numOperands);
359 if (!lir) {
360 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgumentHole");
361 return;
364 lir->setOperand(LGetInlinedArgumentHole::Index, index);
365 for (uint32_t i = 0; i < numActuals; i++) {
366 MDefinition* arg = ins->getArg(i);
367 uint32_t index = LGetInlinedArgumentHole::ArgIndex(i);
368 lir->setBoxOperand(
369 index, useBoxOrTypedOrConstant(arg,
370 /*useConstant = */ true, useAtStart));
372 assignSnapshot(lir, ins->bailoutKind());
373 defineBox(lir, ins);
376 void LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins) {
377 LAllocation argsObj = useRegister(ins->argsObject());
378 LGetArgumentsObjectArg* lir =
379 new (alloc()) LGetArgumentsObjectArg(argsObj, temp());
380 defineBox(lir, ins);
383 void LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins) {
384 LAllocation argsObj = useRegister(ins->argsObject());
385 LSetArgumentsObjectArg* lir = new (alloc())
386 LSetArgumentsObjectArg(argsObj, useBox(ins->value()), temp());
387 add(lir, ins);
390 void LIRGenerator::visitLoadArgumentsObjectArg(MLoadArgumentsObjectArg* ins) {
391 MDefinition* argsObj = ins->argsObject();
392 MOZ_ASSERT(argsObj->type() == MIRType::Object);
394 MDefinition* index = ins->index();
395 MOZ_ASSERT(index->type() == MIRType::Int32);
397 auto* lir = new (alloc())
398 LLoadArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp());
399 assignSnapshot(lir, ins->bailoutKind());
400 defineBox(lir, ins);
403 void LIRGenerator::visitLoadArgumentsObjectArgHole(
404 MLoadArgumentsObjectArgHole* ins) {
405 MDefinition* argsObj = ins->argsObject();
406 MOZ_ASSERT(argsObj->type() == MIRType::Object);
408 MDefinition* index = ins->index();
409 MOZ_ASSERT(index->type() == MIRType::Int32);
411 auto* lir = new (alloc()) LLoadArgumentsObjectArgHole(
412 useRegister(argsObj), useRegister(index), temp());
413 assignSnapshot(lir, ins->bailoutKind());
414 defineBox(lir, ins);
417 void LIRGenerator::visitInArgumentsObjectArg(MInArgumentsObjectArg* ins) {
418 MDefinition* argsObj = ins->argsObject();
419 MOZ_ASSERT(argsObj->type() == MIRType::Object);
421 MDefinition* index = ins->index();
422 MOZ_ASSERT(index->type() == MIRType::Int32);
424 auto* lir = new (alloc())
425 LInArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp());
426 assignSnapshot(lir, ins->bailoutKind());
427 define(lir, ins);
430 void LIRGenerator::visitArgumentsObjectLength(MArgumentsObjectLength* ins) {
431 MDefinition* argsObj = ins->argsObject();
432 MOZ_ASSERT(argsObj->type() == MIRType::Object);
434 auto* lir = new (alloc()) LArgumentsObjectLength(useRegister(argsObj));
435 assignSnapshot(lir, ins->bailoutKind());
436 define(lir, ins);
439 void LIRGenerator::visitArrayFromArgumentsObject(
440 MArrayFromArgumentsObject* ins) {
441 MDefinition* argsObj = ins->argsObject();
442 MOZ_ASSERT(argsObj->type() == MIRType::Object);
444 auto* lir =
445 new (alloc()) LArrayFromArgumentsObject(useRegisterAtStart(argsObj));
446 defineReturn(lir, ins);
447 assignSafepoint(lir, ins);
450 void LIRGenerator::visitGuardArgumentsObjectFlags(
451 MGuardArgumentsObjectFlags* ins) {
452 MDefinition* argsObj = ins->argsObject();
453 MOZ_ASSERT(argsObj->type() == MIRType::Object);
455 auto* lir =
456 new (alloc()) LGuardArgumentsObjectFlags(useRegister(argsObj), temp());
457 assignSnapshot(lir, ins->bailoutKind());
458 add(lir, ins);
459 redefine(ins, argsObj);
462 void LIRGenerator::visitReturnFromCtor(MReturnFromCtor* ins) {
463 LReturnFromCtor* lir = new (alloc())
464 LReturnFromCtor(useBox(ins->value()), useRegister(ins->object()));
465 define(lir, ins);
468 void LIRGenerator::visitBoxNonStrictThis(MBoxNonStrictThis* ins) {
469 MOZ_ASSERT(ins->type() == MIRType::Object);
470 MOZ_ASSERT(ins->input()->type() == MIRType::Value);
472 auto* lir = new (alloc()) LBoxNonStrictThis(useBox(ins->input()));
473 define(lir, ins);
474 assignSafepoint(lir, ins);
477 void LIRGenerator::visitImplicitThis(MImplicitThis* ins) {
478 MDefinition* env = ins->envChain();
479 MOZ_ASSERT(env->type() == MIRType::Object);
481 LImplicitThis* lir = new (alloc()) LImplicitThis(useRegisterAtStart(env));
482 defineReturn(lir, ins);
483 assignSafepoint(lir, ins);
486 void LIRGenerator::visitArrowNewTarget(MArrowNewTarget* ins) {
487 MOZ_ASSERT(ins->type() == MIRType::Value);
488 MOZ_ASSERT(ins->callee()->type() == MIRType::Object);
490 LArrowNewTarget* lir =
491 new (alloc()) LArrowNewTarget(useRegister(ins->callee()));
492 defineBox(lir, ins);
495 bool LIRGenerator::lowerCallArguments(MCall* call) {
496 uint32_t argc = call->numStackArgs();
498 // Align the arguments of a call such that the callee would keep the same
499 // alignment as the caller.
500 uint32_t baseSlot = 0;
501 if (JitStackValueAlignment > 1) {
502 baseSlot = AlignBytes(argc, JitStackValueAlignment);
503 } else {
504 baseSlot = argc;
507 // Save the maximum number of argument, such that we can have one unique
508 // frame size.
509 if (baseSlot > maxargslots_) {
510 maxargslots_ = baseSlot;
513 for (size_t i = 0; i < argc; i++) {
514 MDefinition* arg = call->getArg(i);
515 uint32_t argslot = baseSlot - i;
517 // Values take a slow path.
518 if (arg->type() == MIRType::Value) {
519 LStackArgV* stack = new (alloc()) LStackArgV(useBox(arg), argslot);
520 add(stack);
521 } else {
522 // Known types can move constant types and/or payloads.
523 LStackArgT* stack = new (alloc())
524 LStackArgT(useRegisterOrConstant(arg), argslot, arg->type());
525 add(stack);
528 if (!alloc().ensureBallast()) {
529 return false;
532 return true;
535 void LIRGenerator::visitCall(MCall* call) {
536 MOZ_ASSERT(call->getCallee()->type() == MIRType::Object);
538 // In case of oom, skip the rest of the allocations.
539 if (!lowerCallArguments(call)) {
540 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCall");
541 return;
544 WrappedFunction* target = call->getSingleTarget();
546 LInstruction* lir;
548 if (call->isCallDOMNative()) {
549 // Call DOM functions.
550 MOZ_ASSERT(target && target->isNativeWithoutJitEntry());
551 Register cxReg, objReg, privReg, argsReg;
552 GetTempRegForIntArg(0, 0, &cxReg);
553 GetTempRegForIntArg(1, 0, &objReg);
554 GetTempRegForIntArg(2, 0, &privReg);
555 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &argsReg);
556 MOZ_ASSERT(ok, "How can we not have four temp registers?");
557 lir = new (alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg),
558 tempFixed(privReg), tempFixed(argsReg));
559 } else if (target) {
560 // Call known functions.
561 if (target->isNativeWithoutJitEntry()) {
562 Register cxReg, numReg, vpReg, tmpReg;
563 GetTempRegForIntArg(0, 0, &cxReg);
564 GetTempRegForIntArg(1, 0, &numReg);
565 GetTempRegForIntArg(2, 0, &vpReg);
567 // Even though this is just a temp reg, use the same API to avoid
568 // register collisions.
569 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
570 MOZ_ASSERT(ok, "How can we not have four temp registers?");
572 lir = new (alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
573 tempFixed(vpReg), tempFixed(tmpReg));
574 } else {
575 lir = new (alloc()) LCallKnown(useRegisterAtStart(call->getCallee()),
576 tempFixed(CallTempReg0));
578 } else {
579 // Call anything, using the most generic code.
580 lir = new (alloc())
581 LCallGeneric(useRegisterAtStart(call->getCallee()),
582 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
584 defineReturn(lir, call);
585 assignSafepoint(lir, call);
588 void LIRGenerator::visitApplyArgs(MApplyArgs* apply) {
589 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
591 // Assert if the return value is already erased.
592 static_assert(CallTempReg2 != JSReturnReg_Type);
593 static_assert(CallTempReg2 != JSReturnReg_Data);
595 LApplyArgsGeneric* lir = new (alloc()) LApplyArgsGeneric(
596 useFixedAtStart(apply->getFunction(), CallTempReg3),
597 useFixedAtStart(apply->getArgc(), CallTempReg0),
598 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
599 tempFixed(CallTempReg1), // object register
600 tempFixed(CallTempReg2)); // stack counter register
602 // Bailout is needed in the case of too many values in the arguments array.
603 assignSnapshot(lir, apply->bailoutKind());
605 defineReturn(lir, apply);
606 assignSafepoint(lir, apply);
609 void LIRGenerator::visitApplyArgsObj(MApplyArgsObj* apply) {
610 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
612 // Assert if the return value is already erased.
613 static_assert(CallTempReg2 != JSReturnReg_Type);
614 static_assert(CallTempReg2 != JSReturnReg_Data);
616 LApplyArgsObj* lir = new (alloc()) LApplyArgsObj(
617 useFixedAtStart(apply->getFunction(), CallTempReg3),
618 useFixedAtStart(apply->getArgsObj(), CallTempReg0),
619 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
620 tempFixed(CallTempReg1), // object register
621 tempFixed(CallTempReg2)); // stack counter register
623 // Bailout is needed in the case of too many values in the arguments array.
624 assignSnapshot(lir, apply->bailoutKind());
626 defineReturn(lir, apply);
627 assignSafepoint(lir, apply);
630 void LIRGenerator::visitApplyArray(MApplyArray* apply) {
631 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
633 // Assert if the return value is already erased.
634 static_assert(CallTempReg2 != JSReturnReg_Type);
635 static_assert(CallTempReg2 != JSReturnReg_Data);
637 LApplyArrayGeneric* lir = new (alloc()) LApplyArrayGeneric(
638 useFixedAtStart(apply->getFunction(), CallTempReg3),
639 useFixedAtStart(apply->getElements(), CallTempReg0),
640 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
641 tempFixed(CallTempReg1), // object register
642 tempFixed(CallTempReg2)); // stack counter register
644 // Bailout is needed in the case of too many values in the array, or empty
645 // space at the end of the array.
646 assignSnapshot(lir, apply->bailoutKind());
648 defineReturn(lir, apply);
649 assignSafepoint(lir, apply);
652 void LIRGenerator::visitConstructArgs(MConstructArgs* mir) {
653 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
654 MOZ_ASSERT(mir->getArgc()->type() == MIRType::Int32);
655 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
656 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
658 // Assert if the return value is already erased.
659 static_assert(CallTempReg2 != JSReturnReg_Type);
660 static_assert(CallTempReg2 != JSReturnReg_Data);
662 auto* lir = new (alloc()) LConstructArgsGeneric(
663 useFixedAtStart(mir->getFunction(), CallTempReg3),
664 useFixedAtStart(mir->getArgc(), CallTempReg0),
665 useFixedAtStart(mir->getNewTarget(), CallTempReg1),
666 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5),
667 tempFixed(CallTempReg2));
669 // Bailout is needed in the case of too many values in the arguments array.
670 assignSnapshot(lir, mir->bailoutKind());
672 defineReturn(lir, mir);
673 assignSafepoint(lir, mir);
676 void LIRGenerator::visitConstructArray(MConstructArray* mir) {
677 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
678 MOZ_ASSERT(mir->getElements()->type() == MIRType::Elements);
679 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
680 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
682 // Assert if the return value is already erased.
683 static_assert(CallTempReg2 != JSReturnReg_Type);
684 static_assert(CallTempReg2 != JSReturnReg_Data);
686 auto* lir = new (alloc()) LConstructArrayGeneric(
687 useFixedAtStart(mir->getFunction(), CallTempReg3),
688 useFixedAtStart(mir->getElements(), CallTempReg0),
689 useFixedAtStart(mir->getNewTarget(), CallTempReg1),
690 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5),
691 tempFixed(CallTempReg2));
693 // Bailout is needed in the case of too many values in the array, or empty
694 // space at the end of the array.
695 assignSnapshot(lir, mir->bailoutKind());
697 defineReturn(lir, mir);
698 assignSafepoint(lir, mir);
701 void LIRGenerator::visitBail(MBail* bail) {
702 LBail* lir = new (alloc()) LBail();
703 assignSnapshot(lir, bail->bailoutKind());
704 add(lir, bail);
707 void LIRGenerator::visitUnreachable(MUnreachable* unreachable) {
708 LUnreachable* lir = new (alloc()) LUnreachable();
709 add(lir, unreachable);
712 void LIRGenerator::visitEncodeSnapshot(MEncodeSnapshot* mir) {
713 LEncodeSnapshot* lir = new (alloc()) LEncodeSnapshot();
714 assignSnapshot(lir, mir->bailoutKind());
715 add(lir, mir);
718 void LIRGenerator::visitUnreachableResult(MUnreachableResult* mir) {
719 if (mir->type() == MIRType::Value) {
720 auto* lir = new (alloc()) LUnreachableResultV();
721 defineBox(lir, mir);
722 } else {
723 auto* lir = new (alloc()) LUnreachableResultT();
724 define(lir, mir);
728 void LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion) {
729 MIRType type = assertion->input()->type();
730 DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
732 if (type != MIRType::Value && !JitOptions.eagerIonCompilation()) {
733 MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32);
734 MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32);
738 void LIRGenerator::visitAssertRecoveredOnBailout(
739 MAssertRecoveredOnBailout* assertion) {
740 MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
743 [[nodiscard]] static JSOp ReorderComparison(JSOp op, MDefinition** lhsp,
744 MDefinition** rhsp) {
745 MDefinition* lhs = *lhsp;
746 MDefinition* rhs = *rhsp;
748 if (lhs->maybeConstantValue()) {
749 *rhsp = lhs;
750 *lhsp = rhs;
751 return ReverseCompareOp(op);
753 return op;
756 void LIRGenerator::visitTest(MTest* test) {
757 MDefinition* opd = test->getOperand(0);
758 MBasicBlock* ifTrue = test->ifTrue();
759 MBasicBlock* ifFalse = test->ifFalse();
761 // String is converted to length of string in the type analysis phase (see
762 // TestPolicy).
763 MOZ_ASSERT(opd->type() != MIRType::String);
765 // Testing a constant.
766 if (MConstant* constant = opd->maybeConstantValue()) {
767 bool b;
768 if (constant->valueToBoolean(&b)) {
769 add(new (alloc()) LGoto(b ? ifTrue : ifFalse));
770 return;
774 if (opd->type() == MIRType::Value) {
775 auto* lir = new (alloc()) LTestVAndBranch(ifTrue, ifFalse, useBox(opd),
776 tempDouble(), temp(), temp());
777 add(lir, test);
778 return;
781 // Objects are truthy, except if it might emulate undefined.
782 if (opd->type() == MIRType::Object) {
783 add(new (alloc())
784 LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()),
785 test);
786 return;
789 // These must be explicitly sniffed out since they are constants and have
790 // no payload.
791 if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) {
792 add(new (alloc()) LGoto(ifFalse));
793 return;
796 // All symbols are truthy.
797 if (opd->type() == MIRType::Symbol) {
798 add(new (alloc()) LGoto(ifTrue));
799 return;
802 // Try to match the pattern
803 // test=MTest(
804 // comp=MCompare(
805 // {EQ,NE} for {Int,UInt}{32,64},
806 // bitAnd={MBitAnd,MWasmBinaryBitwise(And{32,64})}(x, y),
807 // MConstant(0)
808 // )
809 // )
810 // and produce a single LBitAndAndBranch node. This requires both `comp`
811 // and `bitAnd` to be marked emit-at-uses. Since we can't use
812 // LBitAndAndBranch to represent a 64-bit AND on a 32-bit target, the 64-bit
813 // case is restricted to 64-bit targets.
814 if (opd->isCompare() && opd->isEmittedAtUses()) {
815 #ifdef JS_64BIT
816 constexpr bool targetIs64 = true;
817 #else
818 constexpr bool targetIs64 = false;
819 #endif
820 MCompare* comp = opd->toCompare();
821 Assembler::Condition compCond =
822 JSOpToCondition(comp->compareType(), comp->jsop());
823 MDefinition* compL = comp->getOperand(0);
824 MDefinition* compR = comp->getOperand(1);
825 if ((comp->compareType() == MCompare::Compare_Int32 ||
826 comp->compareType() == MCompare::Compare_UInt32 ||
827 (targetIs64 && comp->compareType() == MCompare::Compare_Int64) ||
828 (targetIs64 && comp->compareType() == MCompare::Compare_UInt64)) &&
829 (compCond == Assembler::Equal || compCond == Assembler::NotEqual) &&
830 compR->isConstant() &&
831 (compR->toConstant()->isInt32(0) ||
832 (targetIs64 && compR->toConstant()->isInt64(0))) &&
833 (compL->isBitAnd() || (compL->isWasmBinaryBitwise() &&
834 compL->toWasmBinaryBitwise()->subOpcode() ==
835 MWasmBinaryBitwise::SubOpcode::And))) {
836 // The MCompare is OK; now check its first operand (the and-ish node).
837 MDefinition* bitAnd = compL;
838 MDefinition* bitAndL = bitAnd->getOperand(0);
839 MDefinition* bitAndR = bitAnd->getOperand(1);
840 MIRType bitAndLTy = bitAndL->type();
841 MIRType bitAndRTy = bitAndR->type();
842 if (bitAnd->isEmittedAtUses() && bitAndLTy == bitAndRTy &&
843 (bitAndLTy == MIRType::Int32 ||
844 (targetIs64 && bitAndLTy == MIRType::Int64))) {
845 // Pattern match succeeded.
846 ReorderCommutative(&bitAndL, &bitAndR, test);
847 if (compCond == Assembler::Equal) {
848 compCond = Assembler::Zero;
849 } else if (compCond == Assembler::NotEqual) {
850 compCond = Assembler::NonZero;
851 } else {
852 MOZ_ASSERT_UNREACHABLE("inequality operators cannot be folded");
854 MOZ_ASSERT_IF(!targetIs64, bitAndLTy == MIRType::Int32);
855 lowerForBitAndAndBranch(
856 new (alloc()) LBitAndAndBranch(
857 ifTrue, ifFalse, bitAndLTy == MIRType::Int64, compCond),
858 test, bitAndL, bitAndR);
859 return;
864 // Check if the operand for this test is a compare operation. If it is, we
865 // want to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse
866 // the compare and jump instructions.
867 if (opd->isCompare() && opd->isEmittedAtUses()) {
868 MCompare* comp = opd->toCompare();
869 MDefinition* left = comp->lhs();
870 MDefinition* right = comp->rhs();
872 // Try to fold the comparison so that we don't have to handle all cases.
873 bool result;
874 if (comp->tryFold(&result)) {
875 add(new (alloc()) LGoto(result ? ifTrue : ifFalse));
876 return;
879 // Emit LCompare*AndBranch.
881 // Compare and branch null/undefined.
882 // The second operand has known null/undefined type,
883 // so just test the first operand.
884 if (comp->compareType() == MCompare::Compare_Null ||
885 comp->compareType() == MCompare::Compare_Undefined) {
886 if (left->type() == MIRType::Object) {
887 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchT(
888 comp, useRegister(left), ifTrue, ifFalse, temp());
889 add(lir, test);
890 return;
893 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchV(
894 comp, ifTrue, ifFalse, useBox(left), temp(), tempToUnbox());
895 add(lir, test);
896 return;
899 // Compare and branch Int32, Symbol or Object pointers.
900 if (comp->isInt32Comparison() ||
901 comp->compareType() == MCompare::Compare_UInt32 ||
902 comp->compareType() == MCompare::Compare_UIntPtr ||
903 comp->compareType() == MCompare::Compare_Object ||
904 comp->compareType() == MCompare::Compare_Symbol) {
905 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
906 LAllocation lhs = useRegister(left);
907 LAllocation rhs;
908 if (comp->isInt32Comparison() ||
909 comp->compareType() == MCompare::Compare_UInt32 ||
910 comp->compareType() == MCompare::Compare_UIntPtr) {
911 rhs = useAnyOrInt32Constant(right);
912 } else {
913 rhs = useAny(right);
915 LCompareAndBranch* lir =
916 new (alloc()) LCompareAndBranch(comp, op, lhs, rhs, ifTrue, ifFalse);
917 add(lir, test);
918 return;
921 // Compare and branch Int64.
922 if (comp->compareType() == MCompare::Compare_Int64 ||
923 comp->compareType() == MCompare::Compare_UInt64) {
924 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
925 lowerForCompareI64AndBranch(test, comp, op, left, right, ifTrue, ifFalse);
926 return;
929 // Compare and branch doubles.
930 if (comp->isDoubleComparison()) {
931 LAllocation lhs = useRegister(left);
932 LAllocation rhs = useRegister(right);
933 LCompareDAndBranch* lir =
934 new (alloc()) LCompareDAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
935 add(lir, test);
936 return;
939 // Compare and branch floats.
940 if (comp->isFloat32Comparison()) {
941 LAllocation lhs = useRegister(left);
942 LAllocation rhs = useRegister(right);
943 LCompareFAndBranch* lir =
944 new (alloc()) LCompareFAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
945 add(lir, test);
946 return;
950 // Check if the operand for this test is a bitand operation. If it is, we want
951 // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
952 if (opd->isBitAnd() && opd->isEmittedAtUses()) {
953 MDefinition* lhs = opd->getOperand(0);
954 MDefinition* rhs = opd->getOperand(1);
955 if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32) {
956 ReorderCommutative(&lhs, &rhs, test);
957 lowerForBitAndAndBranch(new (alloc()) LBitAndAndBranch(ifTrue, ifFalse,
958 /*is64=*/false),
959 test, lhs, rhs);
960 return;
964 #if defined(ENABLE_WASM_SIMD) && \
965 (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || \
966 defined(JS_CODEGEN_ARM64))
967 // Check if the operand for this test is an any_true/all_true SIMD operation.
968 // If it is, we want to emit an LWasmReduceAndBranchSimd128 node to avoid
969 // generating an intermediate boolean result.
970 if (opd->isWasmReduceSimd128() && opd->isEmittedAtUses()) {
971 MWasmReduceSimd128* node = opd->toWasmReduceSimd128();
972 if (canFoldReduceSimd128AndBranch(node->simdOp())) {
973 # ifdef DEBUG
974 js::wasm::ReportSimdAnalysis("simd128-to-scalar-and-branch -> folded");
975 # endif
976 auto* lir = new (alloc()) LWasmReduceAndBranchSimd128(
977 useRegister(node->input()), node->simdOp(), ifTrue, ifFalse);
978 add(lir, test);
979 return;
982 #endif
984 if (opd->isIsObject() && opd->isEmittedAtUses()) {
985 MDefinition* input = opd->toIsObject()->input();
986 MOZ_ASSERT(input->type() == MIRType::Value);
988 LIsObjectAndBranch* lir =
989 new (alloc()) LIsObjectAndBranch(ifTrue, ifFalse, useBoxAtStart(input));
990 add(lir, test);
991 return;
994 if (opd->isIsNullOrUndefined() && opd->isEmittedAtUses()) {
995 MIsNullOrUndefined* isNullOrUndefined = opd->toIsNullOrUndefined();
996 MDefinition* input = isNullOrUndefined->value();
997 MOZ_ASSERT(input->type() == MIRType::Value);
999 auto* lir = new (alloc()) LIsNullOrUndefinedAndBranch(
1000 isNullOrUndefined, ifTrue, ifFalse, useBoxAtStart(input));
1001 add(lir, test);
1002 return;
1005 if (opd->isIsNoIter()) {
1006 MOZ_ASSERT(opd->isEmittedAtUses());
1008 MDefinition* input = opd->toIsNoIter()->input();
1009 MOZ_ASSERT(input->type() == MIRType::Value);
1011 LIsNoIterAndBranch* lir =
1012 new (alloc()) LIsNoIterAndBranch(ifTrue, ifFalse, useBox(input));
1013 add(lir, test);
1014 return;
1017 switch (opd->type()) {
1018 case MIRType::Double:
1019 add(new (alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
1020 break;
1021 case MIRType::Float32:
1022 add(new (alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
1023 break;
1024 case MIRType::Int32:
1025 case MIRType::Boolean:
1026 add(new (alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
1027 break;
1028 case MIRType::Int64:
1029 add(new (alloc())
1030 LTestI64AndBranch(useInt64Register(opd), ifTrue, ifFalse));
1031 break;
1032 case MIRType::BigInt:
1033 add(new (alloc()) LTestBIAndBranch(useRegister(opd), ifTrue, ifFalse));
1034 break;
1035 default:
1036 MOZ_CRASH("Bad type");
1040 static inline bool CanEmitCompareAtUses(MInstruction* ins) {
1041 if (!ins->canEmitAtUses()) {
1042 return false;
1045 // If the result is never used, we can usefully defer emission to the use
1046 // point, since that will never happen.
1047 MUseIterator iter(ins->usesBegin());
1048 if (iter == ins->usesEnd()) {
1049 return true;
1052 // If the first use isn't of the expected form, the answer is No.
1053 MNode* node = iter->consumer();
1054 if (!node->isDefinition()) {
1055 return false;
1058 MDefinition* use = node->toDefinition();
1059 if (!use->isTest() && !use->isWasmSelect()) {
1060 return false;
1063 // Emission can be deferred to the first use point, but only if there are no
1064 // other use points.
1065 iter++;
1066 return iter == ins->usesEnd();
1069 void LIRGenerator::visitCompare(MCompare* comp) {
1070 MDefinition* left = comp->lhs();
1071 MDefinition* right = comp->rhs();
1073 // Try to fold the comparison so that we don't have to handle all cases.
1074 bool result;
1075 if (comp->tryFold(&result)) {
1076 define(new (alloc()) LInteger(result), comp);
1077 return;
1080 // Move below the emitAtUses call if we ever implement
1081 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
1082 // make sense and avoids confusion.
1083 if (comp->compareType() == MCompare::Compare_String) {
1084 if (IsEqualityOp(comp->jsop())) {
1085 MConstant* constant = nullptr;
1086 if (left->isConstant()) {
1087 constant = left->toConstant();
1088 } else if (right->isConstant()) {
1089 constant = right->toConstant();
1092 if (constant) {
1093 JSLinearString* linear = &constant->toString()->asLinear();
1094 size_t length = linear->length();
1096 // Limit the number of inline instructions used for character
1097 // comparisons. Use the same instruction limit for both encodings, i.e.
1098 // two-byte uses half the limit of Latin-1 strings.
1099 constexpr size_t Latin1StringCompareCutoff = 32;
1100 constexpr size_t TwoByteStringCompareCutoff = 16;
1102 bool canCompareInline =
1103 length > 0 &&
1104 (linear->hasLatin1Chars() ? length <= Latin1StringCompareCutoff
1105 : length <= TwoByteStringCompareCutoff);
1106 if (canCompareInline) {
1107 MDefinition* input = left->isConstant() ? right : left;
1109 auto* lir = new (alloc()) LCompareSInline(useRegister(input), linear);
1110 define(lir, comp);
1111 assignSafepoint(lir, comp);
1112 return;
1117 LCompareS* lir =
1118 new (alloc()) LCompareS(useRegister(left), useRegister(right));
1119 define(lir, comp);
1120 assignSafepoint(lir, comp);
1121 return;
1124 // Compare two BigInts.
1125 if (comp->compareType() == MCompare::Compare_BigInt) {
1126 auto* lir = new (alloc()) LCompareBigInt(
1127 useRegister(left), useRegister(right), temp(), temp(), temp());
1128 define(lir, comp);
1129 return;
1132 // Compare BigInt with Int32.
1133 if (comp->compareType() == MCompare::Compare_BigInt_Int32) {
1134 auto* lir = new (alloc()) LCompareBigIntInt32(
1135 useRegister(left), useRegister(right), temp(), temp());
1136 define(lir, comp);
1137 return;
1140 // Compare BigInt with Double.
1141 if (comp->compareType() == MCompare::Compare_BigInt_Double) {
1142 auto* lir = new (alloc()) LCompareBigIntDouble(useRegisterAtStart(left),
1143 useRegisterAtStart(right),
1144 tempFixed(CallTempReg0));
1145 defineReturn(lir, comp);
1146 return;
1149 // Compare BigInt with String.
1150 if (comp->compareType() == MCompare::Compare_BigInt_String) {
1151 auto* lir = new (alloc()) LCompareBigIntString(useRegisterAtStart(left),
1152 useRegisterAtStart(right));
1153 defineReturn(lir, comp);
1154 assignSafepoint(lir, comp);
1155 return;
1158 // Sniff out if the output of this compare is used only for a branching.
1159 // If it is, then we will emit an LCompare*AndBranch instruction in place
1160 // of this compare and any test that uses this compare. Thus, we can
1161 // ignore this Compare.
1162 if (CanEmitCompareAtUses(comp)) {
1163 emitAtUses(comp);
1164 return;
1167 // Compare Null and Undefined.
1168 if (comp->compareType() == MCompare::Compare_Null ||
1169 comp->compareType() == MCompare::Compare_Undefined) {
1170 if (left->type() == MIRType::Object) {
1171 define(new (alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp);
1172 return;
1175 auto* lir = new (alloc())
1176 LIsNullOrLikeUndefinedV(useBox(left), temp(), tempToUnbox());
1177 define(lir, comp);
1178 return;
1181 // Compare Int32, Symbol, Object or Wasm pointers.
1182 if (comp->isInt32Comparison() ||
1183 comp->compareType() == MCompare::Compare_UInt32 ||
1184 comp->compareType() == MCompare::Compare_UIntPtr ||
1185 comp->compareType() == MCompare::Compare_Object ||
1186 comp->compareType() == MCompare::Compare_Symbol ||
1187 comp->compareType() == MCompare::Compare_RefOrNull) {
1188 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1189 LAllocation lhs = useRegister(left);
1190 LAllocation rhs;
1191 if (comp->isInt32Comparison() ||
1192 comp->compareType() == MCompare::Compare_UInt32 ||
1193 comp->compareType() == MCompare::Compare_UIntPtr) {
1194 rhs = useAnyOrInt32Constant(right);
1195 } else {
1196 rhs = useAny(right);
1198 define(new (alloc()) LCompare(op, lhs, rhs), comp);
1199 return;
1202 // Compare Int64.
1203 if (comp->compareType() == MCompare::Compare_Int64 ||
1204 comp->compareType() == MCompare::Compare_UInt64) {
1205 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1206 define(new (alloc()) LCompareI64(op, useInt64Register(left),
1207 useInt64OrConstant(right)),
1208 comp);
1209 return;
1212 // Compare doubles.
1213 if (comp->isDoubleComparison()) {
1214 define(new (alloc()) LCompareD(useRegister(left), useRegister(right)),
1215 comp);
1216 return;
1219 // Compare float32.
1220 if (comp->isFloat32Comparison()) {
1221 define(new (alloc()) LCompareF(useRegister(left), useRegister(right)),
1222 comp);
1223 return;
1226 MOZ_CRASH("Unrecognized compare type.");
1229 void LIRGenerator::visitSameValueDouble(MSameValueDouble* ins) {
1230 MDefinition* lhs = ins->lhs();
1231 MDefinition* rhs = ins->rhs();
1233 MOZ_ASSERT(lhs->type() == MIRType::Double);
1234 MOZ_ASSERT(rhs->type() == MIRType::Double);
1236 auto* lir = new (alloc())
1237 LSameValueDouble(useRegister(lhs), useRegister(rhs), tempDouble());
1238 define(lir, ins);
1241 void LIRGenerator::visitSameValue(MSameValue* ins) {
1242 MDefinition* lhs = ins->lhs();
1243 MDefinition* rhs = ins->rhs();
1245 MOZ_ASSERT(lhs->type() == MIRType::Value);
1246 MOZ_ASSERT(rhs->type() == MIRType::Value);
1248 auto* lir = new (alloc()) LSameValue(useBox(lhs), useBox(rhs));
1249 define(lir, ins);
1250 assignSafepoint(lir, ins);
1253 void LIRGenerator::lowerBitOp(JSOp op, MBinaryInstruction* ins) {
1254 MDefinition* lhs = ins->getOperand(0);
1255 MDefinition* rhs = ins->getOperand(1);
1256 MOZ_ASSERT(IsIntType(ins->type()));
1258 if (ins->type() == MIRType::Int32) {
1259 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1260 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1261 ReorderCommutative(&lhs, &rhs, ins);
1262 lowerForALU(new (alloc()) LBitOpI(op), ins, lhs, rhs);
1263 return;
1266 if (ins->type() == MIRType::Int64) {
1267 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1268 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1269 ReorderCommutative(&lhs, &rhs, ins);
1270 lowerForALUInt64(new (alloc()) LBitOpI64(op), ins, lhs, rhs);
1271 return;
1274 MOZ_CRASH("Unhandled integer specialization");
1277 void LIRGenerator::visitTypeOf(MTypeOf* ins) {
1278 MDefinition* opd = ins->input();
1280 if (opd->type() == MIRType::Object) {
1281 auto* lir = new (alloc()) LTypeOfO(useRegister(opd));
1282 define(lir, ins);
1283 return;
1286 MOZ_ASSERT(opd->type() == MIRType::Value);
1288 LTypeOfV* lir = new (alloc()) LTypeOfV(useBox(opd), tempToUnbox());
1289 define(lir, ins);
1292 void LIRGenerator::visitTypeOfName(MTypeOfName* ins) {
1293 MDefinition* input = ins->input();
1294 MOZ_ASSERT(input->type() == MIRType::Int32);
1296 auto* lir = new (alloc()) LTypeOfName(useRegister(input));
1297 define(lir, ins);
1300 void LIRGenerator::visitTypeOfIs(MTypeOfIs* ins) {
1301 MDefinition* input = ins->input();
1303 MOZ_ASSERT(input->type() == MIRType::Object ||
1304 input->type() == MIRType::Value);
1306 switch (ins->jstype()) {
1307 case JSTYPE_UNDEFINED:
1308 case JSTYPE_OBJECT:
1309 case JSTYPE_FUNCTION: {
1310 if (input->type() == MIRType::Object) {
1311 auto* lir = new (alloc()) LTypeOfIsNonPrimitiveO(useRegister(input));
1312 define(lir, ins);
1313 } else {
1314 auto* lir =
1315 new (alloc()) LTypeOfIsNonPrimitiveV(useBox(input), tempToUnbox());
1316 define(lir, ins);
1318 return;
1321 case JSTYPE_STRING:
1322 case JSTYPE_NUMBER:
1323 case JSTYPE_BOOLEAN:
1324 case JSTYPE_SYMBOL:
1325 case JSTYPE_BIGINT: {
1326 MOZ_ASSERT(input->type() == MIRType::Value);
1328 auto* lir = new (alloc()) LTypeOfIsPrimitive(useBoxAtStart(input));
1329 define(lir, ins);
1330 return;
1333 #ifdef ENABLE_RECORD_TUPLE
1334 case JSTYPE_RECORD:
1335 case JSTYPE_TUPLE:
1336 #endif
1337 case JSTYPE_LIMIT:
1338 break;
1340 MOZ_CRASH("Unhandled JSType");
1343 void LIRGenerator::visitToAsyncIter(MToAsyncIter* ins) {
1344 LToAsyncIter* lir = new (alloc()) LToAsyncIter(
1345 useRegisterAtStart(ins->iterator()), useBoxAtStart(ins->nextMethod()));
1346 defineReturn(lir, ins);
1347 assignSafepoint(lir, ins);
1350 void LIRGenerator::visitToPropertyKeyCache(MToPropertyKeyCache* ins) {
1351 MDefinition* input = ins->getOperand(0);
1352 MOZ_ASSERT(ins->type() == MIRType::Value);
1354 auto* lir = new (alloc()) LToPropertyKeyCache(useBox(input));
1355 defineBox(lir, ins);
1356 assignSafepoint(lir, ins);
1359 void LIRGenerator::visitBitNot(MBitNot* ins) {
1360 MDefinition* input = ins->getOperand(0);
1362 if (ins->type() == MIRType::Int32) {
1363 MOZ_ASSERT(input->type() == MIRType::Int32);
1364 lowerForALU(new (alloc()) LBitNotI(), ins, input);
1365 return;
1368 if (ins->type() == MIRType::Int64) {
1369 MOZ_ASSERT(input->type() == MIRType::Int64);
1370 lowerForALUInt64(new (alloc()) LBitNotI64(), ins, input);
1371 return;
1374 MOZ_CRASH("Unhandled integer specialization");
1377 static bool CanEmitBitAndAtUses(MInstruction* ins) {
1378 if (!ins->canEmitAtUses()) {
1379 return false;
1382 MIRType tyL = ins->getOperand(0)->type();
1383 MIRType tyR = ins->getOperand(1)->type();
1384 if (tyL != tyR || (tyL != MIRType::Int32 && tyL != MIRType::Int64)) {
1385 return false;
1388 MUseIterator iter(ins->usesBegin());
1389 if (iter == ins->usesEnd()) {
1390 return false;
1393 MNode* node = iter->consumer();
1394 if (!node->isDefinition() || !node->toDefinition()->isInstruction()) {
1395 return false;
1398 MInstruction* use = node->toDefinition()->toInstruction();
1399 if (!use->isTest() && !(use->isCompare() && CanEmitCompareAtUses(use))) {
1400 return false;
1403 iter++;
1404 return iter == ins->usesEnd();
1407 void LIRGenerator::visitBitAnd(MBitAnd* ins) {
1408 // Sniff out if the output of this bitand is used only for a branching.
1409 // If it is, then we will emit an LBitAndAndBranch instruction in place
1410 // of this bitand and any test that uses this bitand. Thus, we can
1411 // ignore this BitAnd.
1412 if (CanEmitBitAndAtUses(ins)) {
1413 emitAtUses(ins);
1414 } else {
1415 lowerBitOp(JSOp::BitAnd, ins);
1419 void LIRGenerator::visitBitOr(MBitOr* ins) { lowerBitOp(JSOp::BitOr, ins); }
1421 void LIRGenerator::visitBitXor(MBitXor* ins) { lowerBitOp(JSOp::BitXor, ins); }
1423 void LIRGenerator::visitWasmBinaryBitwise(MWasmBinaryBitwise* ins) {
1424 switch (ins->subOpcode()) {
1425 case MWasmBinaryBitwise::SubOpcode::And:
1426 if (CanEmitBitAndAtUses(ins)) {
1427 emitAtUses(ins);
1428 } else {
1429 lowerBitOp(JSOp::BitAnd, ins);
1431 break;
1432 case MWasmBinaryBitwise::SubOpcode::Or:
1433 lowerBitOp(JSOp::BitOr, ins);
1434 break;
1435 case MWasmBinaryBitwise::SubOpcode::Xor:
1436 lowerBitOp(JSOp::BitXor, ins);
1437 break;
1438 default:
1439 MOZ_CRASH();
1443 void LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) {
1444 MDefinition* lhs = ins->getOperand(0);
1445 MDefinition* rhs = ins->getOperand(1);
1447 if (op == JSOp::Ursh && ins->type() == MIRType::Double) {
1448 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1449 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1450 lowerUrshD(ins->toUrsh());
1451 return;
1454 MOZ_ASSERT(IsIntType(ins->type()));
1456 if (ins->type() == MIRType::Int32) {
1457 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1458 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1460 LShiftI* lir = new (alloc()) LShiftI(op);
1461 if (op == JSOp::Ursh) {
1462 if (ins->toUrsh()->fallible()) {
1463 assignSnapshot(lir, ins->bailoutKind());
1466 lowerForShift(lir, ins, lhs, rhs);
1467 return;
1470 if (ins->type() == MIRType::Int64) {
1471 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1472 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1473 lowerForShiftInt64(new (alloc()) LShiftI64(op), ins, lhs, rhs);
1474 return;
1477 MOZ_CRASH("Unhandled integer specialization");
1480 void LIRGenerator::visitLsh(MLsh* ins) { lowerShiftOp(JSOp::Lsh, ins); }
1482 void LIRGenerator::visitRsh(MRsh* ins) { lowerShiftOp(JSOp::Rsh, ins); }
1484 void LIRGenerator::visitUrsh(MUrsh* ins) { lowerShiftOp(JSOp::Ursh, ins); }
1486 void LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins) {
1487 LInstructionHelper<1, 1, 0>* lir;
1489 if (ins->mode() == MSignExtendInt32::Byte) {
1490 lir = new (alloc())
1491 LSignExtendInt32(useByteOpRegisterAtStart(ins->input()), ins->mode());
1492 } else {
1493 lir = new (alloc())
1494 LSignExtendInt32(useRegisterAtStart(ins->input()), ins->mode());
1497 define(lir, ins);
1500 void LIRGenerator::visitRotate(MRotate* ins) {
1501 MDefinition* input = ins->input();
1502 MDefinition* count = ins->count();
1504 if (ins->type() == MIRType::Int32) {
1505 auto* lir = new (alloc()) LRotate();
1506 lowerForShift(lir, ins, input, count);
1507 } else if (ins->type() == MIRType::Int64) {
1508 auto* lir = new (alloc()) LRotateI64();
1509 lowerForShiftInt64(lir, ins, input, count);
1510 } else {
1511 MOZ_CRASH("unexpected type in visitRotate");
1515 void LIRGenerator::visitFloor(MFloor* ins) {
1516 MIRType type = ins->input()->type();
1517 MOZ_ASSERT(IsFloatingPointType(type));
1519 LInstructionHelper<1, 1, 0>* lir;
1520 if (type == MIRType::Double) {
1521 lir = new (alloc()) LFloor(useRegister(ins->input()));
1522 } else {
1523 lir = new (alloc()) LFloorF(useRegister(ins->input()));
1526 assignSnapshot(lir, ins->bailoutKind());
1527 define(lir, ins);
1530 void LIRGenerator::visitCeil(MCeil* ins) {
1531 MIRType type = ins->input()->type();
1532 MOZ_ASSERT(IsFloatingPointType(type));
1534 LInstructionHelper<1, 1, 0>* lir;
1535 if (type == MIRType::Double) {
1536 lir = new (alloc()) LCeil(useRegister(ins->input()));
1537 } else {
1538 lir = new (alloc()) LCeilF(useRegister(ins->input()));
1541 assignSnapshot(lir, ins->bailoutKind());
1542 define(lir, ins);
1545 void LIRGenerator::visitRound(MRound* ins) {
1546 MIRType type = ins->input()->type();
1547 MOZ_ASSERT(IsFloatingPointType(type));
1549 LInstructionHelper<1, 1, 1>* lir;
1550 if (type == MIRType::Double) {
1551 lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble());
1552 } else {
1553 lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32());
1556 assignSnapshot(lir, ins->bailoutKind());
1557 define(lir, ins);
1560 void LIRGenerator::visitTrunc(MTrunc* ins) {
1561 MIRType type = ins->input()->type();
1562 MOZ_ASSERT(IsFloatingPointType(type));
1564 LInstructionHelper<1, 1, 0>* lir;
1565 if (type == MIRType::Double) {
1566 lir = new (alloc()) LTrunc(useRegister(ins->input()));
1567 } else {
1568 lir = new (alloc()) LTruncF(useRegister(ins->input()));
1571 assignSnapshot(lir, ins->bailoutKind());
1572 define(lir, ins);
1575 void LIRGenerator::visitNearbyInt(MNearbyInt* ins) {
1576 MIRType inputType = ins->input()->type();
1577 MOZ_ASSERT(IsFloatingPointType(inputType));
1578 MOZ_ASSERT(ins->type() == inputType);
1580 LInstructionHelper<1, 1, 0>* lir;
1581 if (inputType == MIRType::Double) {
1582 lir = new (alloc()) LNearbyInt(useRegisterAtStart(ins->input()));
1583 } else {
1584 lir = new (alloc()) LNearbyIntF(useRegisterAtStart(ins->input()));
1587 define(lir, ins);
1590 void LIRGenerator::visitMinMax(MMinMax* ins) {
1591 MDefinition* first = ins->getOperand(0);
1592 MDefinition* second = ins->getOperand(1);
1594 ReorderCommutative(&first, &second, ins);
1596 LMinMaxBase* lir;
1597 switch (ins->type()) {
1598 case MIRType::Int32:
1599 lir = new (alloc())
1600 LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
1601 break;
1602 case MIRType::Float32:
1603 lir = new (alloc())
1604 LMinMaxF(useRegisterAtStart(first), useRegister(second));
1605 break;
1606 case MIRType::Double:
1607 lir = new (alloc())
1608 LMinMaxD(useRegisterAtStart(first), useRegister(second));
1609 break;
1610 default:
1611 MOZ_CRASH();
1614 // Input reuse is OK (for now) even on ARM64: floating min/max are fairly
1615 // expensive due to SNaN -> QNaN conversion, and int min/max is for asm.js.
1616 defineReuseInput(lir, ins, 0);
1619 void LIRGenerator::visitMinMaxArray(MMinMaxArray* ins) {
1620 LInstructionHelper<1, 1, 3>* lir;
1621 if (ins->type() == MIRType::Int32) {
1622 lir = new (alloc())
1623 LMinMaxArrayI(useRegisterAtStart(ins->array()), temp(), temp(), temp());
1624 } else {
1625 MOZ_ASSERT(ins->type() == MIRType::Double);
1626 lir = new (alloc()) LMinMaxArrayD(useRegisterAtStart(ins->array()),
1627 tempDouble(), temp(), temp());
1629 assignSnapshot(lir, ins->bailoutKind());
1630 define(lir, ins);
1633 LInstructionHelper<1, 1, 0>* LIRGenerator::allocateAbs(MAbs* ins,
1634 LAllocation input) {
1635 MDefinition* num = ins->input();
1636 MOZ_ASSERT(IsNumberType(num->type()));
1638 LInstructionHelper<1, 1, 0>* lir;
1639 switch (num->type()) {
1640 case MIRType::Int32:
1641 lir = new (alloc()) LAbsI(input);
1642 // needed to handle abs(INT32_MIN)
1643 if (ins->fallible()) {
1644 assignSnapshot(lir, ins->bailoutKind());
1646 break;
1647 case MIRType::Float32:
1648 lir = new (alloc()) LAbsF(input);
1649 break;
1650 case MIRType::Double:
1651 lir = new (alloc()) LAbsD(input);
1652 break;
1653 default:
1654 MOZ_CRASH();
1656 return lir;
1659 void LIRGenerator::visitClz(MClz* ins) {
1660 MDefinition* num = ins->num();
1662 MOZ_ASSERT(IsIntType(ins->type()));
1664 if (ins->type() == MIRType::Int32) {
1665 LClzI* lir = new (alloc()) LClzI(useRegisterAtStart(num));
1666 define(lir, ins);
1667 return;
1670 auto* lir = new (alloc()) LClzI64(useInt64RegisterAtStart(num));
1671 defineInt64(lir, ins);
1674 void LIRGenerator::visitCtz(MCtz* ins) {
1675 MDefinition* num = ins->num();
1677 MOZ_ASSERT(IsIntType(ins->type()));
1679 if (ins->type() == MIRType::Int32) {
1680 LCtzI* lir = new (alloc()) LCtzI(useRegisterAtStart(num));
1681 define(lir, ins);
1682 return;
1685 auto* lir = new (alloc()) LCtzI64(useInt64RegisterAtStart(num));
1686 defineInt64(lir, ins);
1689 void LIRGenerator::visitPopcnt(MPopcnt* ins) {
1690 MDefinition* num = ins->num();
1692 MOZ_ASSERT(IsIntType(ins->type()));
1694 if (ins->type() == MIRType::Int32) {
1695 LPopcntI* lir = new (alloc()) LPopcntI(useRegisterAtStart(num), temp());
1696 define(lir, ins);
1697 return;
1700 auto* lir = new (alloc()) LPopcntI64(useInt64RegisterAtStart(num), temp());
1701 defineInt64(lir, ins);
1704 void LIRGenerator::visitSqrt(MSqrt* ins) {
1705 MDefinition* num = ins->input();
1706 MOZ_ASSERT(IsFloatingPointType(num->type()));
1708 LInstructionHelper<1, 1, 0>* lir;
1709 if (num->type() == MIRType::Double) {
1710 lir = new (alloc()) LSqrtD(useRegisterAtStart(num));
1711 } else {
1712 lir = new (alloc()) LSqrtF(useRegisterAtStart(num));
1714 define(lir, ins);
1717 void LIRGenerator::visitAtan2(MAtan2* ins) {
1718 MDefinition* y = ins->y();
1719 MOZ_ASSERT(y->type() == MIRType::Double);
1721 MDefinition* x = ins->x();
1722 MOZ_ASSERT(x->type() == MIRType::Double);
1724 LAtan2D* lir = new (alloc()) LAtan2D(
1725 useRegisterAtStart(y), useRegisterAtStart(x), tempFixed(CallTempReg0));
1726 defineReturn(lir, ins);
1729 void LIRGenerator::visitHypot(MHypot* ins) {
1730 LHypot* lir = nullptr;
1731 uint32_t length = ins->numOperands();
1732 for (uint32_t i = 0; i < length; ++i) {
1733 MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double);
1736 switch (length) {
1737 case 2:
1738 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1739 useRegisterAtStart(ins->getOperand(1)),
1740 tempFixed(CallTempReg0));
1741 break;
1742 case 3:
1743 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1744 useRegisterAtStart(ins->getOperand(1)),
1745 useRegisterAtStart(ins->getOperand(2)),
1746 tempFixed(CallTempReg0));
1747 break;
1748 case 4:
1749 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1750 useRegisterAtStart(ins->getOperand(1)),
1751 useRegisterAtStart(ins->getOperand(2)),
1752 useRegisterAtStart(ins->getOperand(3)),
1753 tempFixed(CallTempReg0));
1754 break;
1755 default:
1756 MOZ_CRASH("Unexpected number of arguments to LHypot.");
1759 defineReturn(lir, ins);
1762 void LIRGenerator::visitPow(MPow* ins) {
1763 MDefinition* input = ins->input();
1764 MDefinition* power = ins->power();
1766 if (ins->type() == MIRType::Int32) {
1767 MOZ_ASSERT(input->type() == MIRType::Int32);
1768 MOZ_ASSERT(power->type() == MIRType::Int32);
1770 if (input->isConstant()) {
1771 // Restrict this optimization to |base <= 256| to avoid generating too
1772 // many consecutive shift instructions.
1773 int32_t base = input->toConstant()->toInt32();
1774 if (2 <= base && base <= 256 && mozilla::IsPowerOfTwo(uint32_t(base))) {
1775 lowerPowOfTwoI(ins);
1776 return;
1780 auto* lir = new (alloc())
1781 LPowII(useRegister(input), useRegister(power), temp(), temp());
1782 assignSnapshot(lir, ins->bailoutKind());
1783 define(lir, ins);
1784 return;
1787 MOZ_ASSERT(ins->type() == MIRType::Double);
1788 MOZ_ASSERT(input->type() == MIRType::Double);
1789 MOZ_ASSERT(power->type() == MIRType::Int32 ||
1790 power->type() == MIRType::Double);
1792 LInstruction* lir;
1793 if (power->type() == MIRType::Int32) {
1794 lir =
1795 new (alloc()) LPowI(useRegisterAtStart(input),
1796 useRegisterAtStart(power), tempFixed(CallTempReg0));
1797 } else {
1798 lir =
1799 new (alloc()) LPowD(useRegisterAtStart(input),
1800 useRegisterAtStart(power), tempFixed(CallTempReg0));
1802 defineReturn(lir, ins);
1805 void LIRGenerator::visitSign(MSign* ins) {
1806 if (ins->type() == ins->input()->type()) {
1807 LInstructionHelper<1, 1, 0>* lir;
1808 if (ins->type() == MIRType::Int32) {
1809 lir = new (alloc()) LSignI(useRegister(ins->input()));
1810 } else {
1811 MOZ_ASSERT(ins->type() == MIRType::Double);
1812 lir = new (alloc()) LSignD(useRegister(ins->input()));
1814 define(lir, ins);
1815 } else {
1816 MOZ_ASSERT(ins->type() == MIRType::Int32);
1817 MOZ_ASSERT(ins->input()->type() == MIRType::Double);
1819 auto* lir = new (alloc()) LSignDI(useRegister(ins->input()), tempDouble());
1820 assignSnapshot(lir, ins->bailoutKind());
1821 define(lir, ins);
1825 void LIRGenerator::visitMathFunction(MMathFunction* ins) {
1826 MOZ_ASSERT(IsFloatingPointType(ins->type()));
1827 MOZ_ASSERT(ins->type() == ins->input()->type());
1829 LInstruction* lir;
1830 if (ins->type() == MIRType::Double) {
1831 lir = new (alloc()) LMathFunctionD(useRegisterAtStart(ins->input()),
1832 tempFixed(CallTempReg0));
1833 } else {
1834 lir = new (alloc()) LMathFunctionF(useRegisterAtStart(ins->input()),
1835 tempFixed(CallTempReg0));
1837 defineReturn(lir, ins);
1840 void LIRGenerator::visitRandom(MRandom* ins) {
1841 auto* lir = new (alloc()) LRandom(temp(), tempInt64(), tempInt64());
1842 define(lir, ins);
1845 // Try to mark an add or sub instruction as able to recover its input when
1846 // bailing out.
1847 template <typename S, typename T>
1848 static void MaybeSetRecoversInput(S* mir, T* lir) {
1849 MOZ_ASSERT(lir->mirRaw() == mir);
1850 if (!mir->fallible() || !lir->snapshot()) {
1851 return;
1854 if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT) {
1855 return;
1858 // The original operands to an add or sub can't be recovered if they both
1859 // use the same register.
1860 if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
1861 lir->lhs()->toUse()->virtualRegister() ==
1862 lir->rhs()->toUse()->virtualRegister()) {
1863 return;
1866 // Add instructions that are on two different values can recover
1867 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
1868 // of that input does not need to be kept alive in the snapshot
1869 // for the instruction.
1871 lir->setRecoversInput();
1873 const LUse* input = lir->getOperand(lir->output()->getReusedInput())->toUse();
1874 lir->snapshot()->rewriteRecoveredInput(*input);
1877 void LIRGenerator::visitAdd(MAdd* ins) {
1878 MDefinition* lhs = ins->getOperand(0);
1879 MDefinition* rhs = ins->getOperand(1);
1881 MOZ_ASSERT(lhs->type() == rhs->type());
1882 MOZ_ASSERT(IsNumberType(ins->type()));
1884 if (ins->type() == MIRType::Int32) {
1885 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1886 ReorderCommutative(&lhs, &rhs, ins);
1887 LAddI* lir = new (alloc()) LAddI;
1889 if (ins->fallible()) {
1890 assignSnapshot(lir, ins->bailoutKind());
1893 lowerForALU(lir, ins, lhs, rhs);
1894 MaybeSetRecoversInput(ins, lir);
1895 return;
1898 if (ins->type() == MIRType::Int64) {
1899 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1900 ReorderCommutative(&lhs, &rhs, ins);
1901 LAddI64* lir = new (alloc()) LAddI64;
1902 lowerForALUInt64(lir, ins, lhs, rhs);
1903 return;
1906 if (ins->type() == MIRType::Double) {
1907 MOZ_ASSERT(lhs->type() == MIRType::Double);
1908 ReorderCommutative(&lhs, &rhs, ins);
1909 lowerForFPU(new (alloc()) LMathD(JSOp::Add), ins, lhs, rhs);
1910 return;
1913 if (ins->type() == MIRType::Float32) {
1914 MOZ_ASSERT(lhs->type() == MIRType::Float32);
1915 ReorderCommutative(&lhs, &rhs, ins);
1916 lowerForFPU(new (alloc()) LMathF(JSOp::Add), ins, lhs, rhs);
1917 return;
1920 MOZ_CRASH("Unhandled number specialization");
1923 void LIRGenerator::visitSub(MSub* ins) {
1924 MDefinition* lhs = ins->lhs();
1925 MDefinition* rhs = ins->rhs();
1927 MOZ_ASSERT(lhs->type() == rhs->type());
1928 MOZ_ASSERT(IsNumberType(ins->type()));
1930 if (ins->type() == MIRType::Int32) {
1931 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1933 LSubI* lir = new (alloc()) LSubI;
1934 if (ins->fallible()) {
1935 assignSnapshot(lir, ins->bailoutKind());
1938 // If our LHS is a constant 0 and we don't have to worry about results that
1939 // can't be represented as an int32, we can optimize to an LNegI.
1940 if (!ins->fallible() && lhs->isConstant() &&
1941 lhs->toConstant()->toInt32() == 0) {
1942 lowerNegI(ins, rhs);
1943 return;
1946 lowerForALU(lir, ins, lhs, rhs);
1947 MaybeSetRecoversInput(ins, lir);
1948 return;
1951 if (ins->type() == MIRType::Int64) {
1952 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1954 // If our LHS is a constant 0, we can optimize to an LNegI64.
1955 if (lhs->isConstant() && lhs->toConstant()->toInt64() == 0) {
1956 lowerNegI64(ins, rhs);
1957 return;
1960 LSubI64* lir = new (alloc()) LSubI64;
1961 lowerForALUInt64(lir, ins, lhs, rhs);
1962 return;
1965 if (ins->type() == MIRType::Double) {
1966 MOZ_ASSERT(lhs->type() == MIRType::Double);
1967 lowerForFPU(new (alloc()) LMathD(JSOp::Sub), ins, lhs, rhs);
1968 return;
1971 if (ins->type() == MIRType::Float32) {
1972 MOZ_ASSERT(lhs->type() == MIRType::Float32);
1973 lowerForFPU(new (alloc()) LMathF(JSOp::Sub), ins, lhs, rhs);
1974 return;
1977 MOZ_CRASH("Unhandled number specialization");
1980 void LIRGenerator::visitMul(MMul* ins) {
1981 MDefinition* lhs = ins->lhs();
1982 MDefinition* rhs = ins->rhs();
1983 MOZ_ASSERT(lhs->type() == rhs->type());
1984 MOZ_ASSERT(IsNumberType(ins->type()));
1986 if (ins->type() == MIRType::Int32) {
1987 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1988 ReorderCommutative(&lhs, &rhs, ins);
1990 // If our RHS is a constant -1 and we don't have to worry about results that
1991 // can't be represented as an int32, we can optimize to an LNegI.
1992 if (!ins->fallible() && rhs->isConstant() &&
1993 rhs->toConstant()->toInt32() == -1) {
1994 lowerNegI(ins, lhs);
1995 return;
1998 lowerMulI(ins, lhs, rhs);
1999 return;
2002 if (ins->type() == MIRType::Int64) {
2003 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2004 ReorderCommutative(&lhs, &rhs, ins);
2006 // If our RHS is a constant -1, we can optimize to an LNegI64.
2007 if (rhs->isConstant() && rhs->toConstant()->toInt64() == -1) {
2008 lowerNegI64(ins, lhs);
2009 return;
2012 LMulI64* lir = new (alloc()) LMulI64;
2013 lowerForMulInt64(lir, ins, lhs, rhs);
2014 return;
2017 if (ins->type() == MIRType::Double) {
2018 MOZ_ASSERT(lhs->type() == MIRType::Double);
2019 ReorderCommutative(&lhs, &rhs, ins);
2021 // If our RHS is a constant -1.0, we can optimize to an LNegD.
2022 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2023 rhs->toConstant()->toDouble() == -1.0) {
2024 defineReuseInput(new (alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
2025 return;
2028 lowerForFPU(new (alloc()) LMathD(JSOp::Mul), ins, lhs, rhs);
2029 return;
2032 if (ins->type() == MIRType::Float32) {
2033 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2034 ReorderCommutative(&lhs, &rhs, ins);
2036 // We apply the same optimizations as for doubles
2037 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2038 rhs->toConstant()->toFloat32() == -1.0f) {
2039 defineReuseInput(new (alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
2040 return;
2043 lowerForFPU(new (alloc()) LMathF(JSOp::Mul), ins, lhs, rhs);
2044 return;
2047 MOZ_CRASH("Unhandled number specialization");
2050 void LIRGenerator::visitDiv(MDiv* ins) {
2051 MDefinition* lhs = ins->lhs();
2052 MDefinition* rhs = ins->rhs();
2053 MOZ_ASSERT(lhs->type() == rhs->type());
2054 MOZ_ASSERT(IsNumberType(ins->type()));
2056 if (ins->type() == MIRType::Int32) {
2057 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2058 lowerDivI(ins);
2059 return;
2062 if (ins->type() == MIRType::Int64) {
2063 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2064 lowerDivI64(ins);
2065 return;
2068 if (ins->type() == MIRType::Double) {
2069 MOZ_ASSERT(lhs->type() == MIRType::Double);
2070 lowerForFPU(new (alloc()) LMathD(JSOp::Div), ins, lhs, rhs);
2071 return;
2074 if (ins->type() == MIRType::Float32) {
2075 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2076 lowerForFPU(new (alloc()) LMathF(JSOp::Div), ins, lhs, rhs);
2077 return;
2080 MOZ_CRASH("Unhandled number specialization");
2083 void LIRGenerator::visitWasmBuiltinDivI64(MWasmBuiltinDivI64* div) {
2084 lowerWasmBuiltinDivI64(div);
2087 void LIRGenerator::visitWasmBuiltinModI64(MWasmBuiltinModI64* mod) {
2088 lowerWasmBuiltinModI64(mod);
2091 void LIRGenerator::visitBuiltinInt64ToFloatingPoint(
2092 MBuiltinInt64ToFloatingPoint* ins) {
2093 lowerBuiltinInt64ToFloatingPoint(ins);
2096 void LIRGenerator::visitWasmBuiltinTruncateToInt64(
2097 MWasmBuiltinTruncateToInt64* ins) {
2098 lowerWasmBuiltinTruncateToInt64(ins);
2101 void LIRGenerator::visitWasmBuiltinModD(MWasmBuiltinModD* ins) {
2102 MOZ_ASSERT(gen->compilingWasm());
2103 LWasmBuiltinModD* lir = new (alloc()) LWasmBuiltinModD(
2104 useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
2105 useFixedAtStart(ins->tls(), WasmTlsReg));
2106 defineReturn(lir, ins);
2109 void LIRGenerator::visitMod(MMod* ins) {
2110 MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type());
2111 MOZ_ASSERT(IsNumberType(ins->type()));
2113 if (ins->type() == MIRType::Int32) {
2114 MOZ_ASSERT(ins->type() == MIRType::Int32);
2115 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32);
2116 lowerModI(ins);
2117 return;
2120 if (ins->type() == MIRType::Int64) {
2121 MOZ_ASSERT(ins->type() == MIRType::Int64);
2122 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64);
2123 lowerModI64(ins);
2124 return;
2127 if (ins->type() == MIRType::Double) {
2128 MOZ_ASSERT(ins->lhs()->type() == MIRType::Double);
2129 MOZ_ASSERT(ins->rhs()->type() == MIRType::Double);
2131 MOZ_ASSERT(!gen->compilingWasm());
2133 if (Assembler::HasRoundInstruction(RoundingMode::TowardsZero)) {
2134 if (ins->rhs()->isConstant()) {
2135 double d = ins->rhs()->toConstant()->toDouble();
2136 int32_t div;
2137 if (mozilla::NumberIsInt32(d, &div) && div > 0 &&
2138 mozilla::IsPowerOfTwo(uint32_t(div))) {
2139 auto* lir = new (alloc()) LModPowTwoD(useRegister(ins->lhs()), div);
2140 define(lir, ins);
2141 return;
2146 // Ion does an unaligned ABI call and thus needs a temp register.
2147 // Note: useRegisterAtStart is safe here, the temp is not a FP register.
2148 LModD* lir = new (alloc())
2149 LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
2150 tempFixed(CallTempReg0));
2151 defineReturn(lir, ins);
2152 return;
2155 MOZ_CRASH("Unhandled number specialization");
2158 void LIRGenerator::visitBigIntAdd(MBigIntAdd* ins) {
2159 auto* lir = new (alloc()) LBigIntAdd(useRegister(ins->lhs()),
2160 useRegister(ins->rhs()), temp(), temp());
2161 define(lir, ins);
2162 assignSafepoint(lir, ins);
2165 void LIRGenerator::visitBigIntSub(MBigIntSub* ins) {
2166 auto* lir = new (alloc()) LBigIntSub(useRegister(ins->lhs()),
2167 useRegister(ins->rhs()), temp(), temp());
2168 define(lir, ins);
2169 assignSafepoint(lir, ins);
2172 void LIRGenerator::visitBigIntMul(MBigIntMul* ins) {
2173 auto* lir = new (alloc()) LBigIntMul(useRegister(ins->lhs()),
2174 useRegister(ins->rhs()), temp(), temp());
2175 define(lir, ins);
2176 assignSafepoint(lir, ins);
2179 void LIRGenerator::visitBigIntDiv(MBigIntDiv* ins) { lowerBigIntDiv(ins); }
2181 void LIRGenerator::visitBigIntMod(MBigIntMod* ins) { lowerBigIntMod(ins); }
2183 void LIRGenerator::visitBigIntPow(MBigIntPow* ins) {
2184 auto* lir = new (alloc()) LBigIntPow(useRegister(ins->lhs()),
2185 useRegister(ins->rhs()), temp(), temp());
2186 define(lir, ins);
2187 assignSafepoint(lir, ins);
2190 void LIRGenerator::visitBigIntBitAnd(MBigIntBitAnd* ins) {
2191 auto* lir = new (alloc()) LBigIntBitAnd(
2192 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2193 define(lir, ins);
2194 assignSafepoint(lir, ins);
2197 void LIRGenerator::visitBigIntBitOr(MBigIntBitOr* ins) {
2198 auto* lir = new (alloc()) LBigIntBitOr(
2199 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2200 define(lir, ins);
2201 assignSafepoint(lir, ins);
2204 void LIRGenerator::visitBigIntBitXor(MBigIntBitXor* ins) {
2205 auto* lir = new (alloc()) LBigIntBitXor(
2206 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2207 define(lir, ins);
2208 assignSafepoint(lir, ins);
2211 void LIRGenerator::visitBigIntLsh(MBigIntLsh* ins) { lowerBigIntLsh(ins); }
2213 void LIRGenerator::visitBigIntRsh(MBigIntRsh* ins) { lowerBigIntRsh(ins); }
2215 void LIRGenerator::visitBigIntIncrement(MBigIntIncrement* ins) {
2216 auto* lir =
2217 new (alloc()) LBigIntIncrement(useRegister(ins->input()), temp(), temp());
2218 define(lir, ins);
2219 assignSafepoint(lir, ins);
2222 void LIRGenerator::visitBigIntDecrement(MBigIntDecrement* ins) {
2223 auto* lir =
2224 new (alloc()) LBigIntDecrement(useRegister(ins->input()), temp(), temp());
2225 define(lir, ins);
2226 assignSafepoint(lir, ins);
2229 void LIRGenerator::visitBigIntNegate(MBigIntNegate* ins) {
2230 auto* lir = new (alloc()) LBigIntNegate(useRegister(ins->input()), temp());
2231 define(lir, ins);
2232 assignSafepoint(lir, ins);
2235 void LIRGenerator::visitBigIntBitNot(MBigIntBitNot* ins) {
2236 auto* lir =
2237 new (alloc()) LBigIntBitNot(useRegister(ins->input()), temp(), temp());
2238 define(lir, ins);
2239 assignSafepoint(lir, ins);
2242 void LIRGenerator::visitConcat(MConcat* ins) {
2243 MDefinition* lhs = ins->getOperand(0);
2244 MDefinition* rhs = ins->getOperand(1);
2246 MOZ_ASSERT(lhs->type() == MIRType::String);
2247 MOZ_ASSERT(rhs->type() == MIRType::String);
2248 MOZ_ASSERT(ins->type() == MIRType::String);
2250 LConcat* lir = new (alloc()) LConcat(
2251 useFixedAtStart(lhs, CallTempReg0), useFixedAtStart(rhs, CallTempReg1),
2252 tempFixed(CallTempReg0), tempFixed(CallTempReg1), tempFixed(CallTempReg2),
2253 tempFixed(CallTempReg3), tempFixed(CallTempReg4));
2254 defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
2255 assignSafepoint(lir, ins);
2258 void LIRGenerator::visitCharCodeAt(MCharCodeAt* ins) {
2259 MDefinition* str = ins->string();
2260 MDefinition* idx = ins->index();
2262 MOZ_ASSERT(str->type() == MIRType::String);
2263 MOZ_ASSERT(idx->type() == MIRType::Int32);
2265 LCharCodeAt* lir =
2266 new (alloc()) LCharCodeAt(useRegister(str), useRegister(idx), temp());
2267 define(lir, ins);
2268 assignSafepoint(lir, ins);
2271 void LIRGenerator::visitFromCharCode(MFromCharCode* ins) {
2272 MDefinition* code = ins->getOperand(0);
2274 MOZ_ASSERT(code->type() == MIRType::Int32);
2276 LFromCharCode* lir = new (alloc()) LFromCharCode(useRegister(code));
2277 define(lir, ins);
2278 assignSafepoint(lir, ins);
2281 void LIRGenerator::visitFromCodePoint(MFromCodePoint* ins) {
2282 MDefinition* codePoint = ins->getOperand(0);
2284 MOZ_ASSERT(codePoint->type() == MIRType::Int32);
2286 LFromCodePoint* lir =
2287 new (alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp());
2288 assignSnapshot(lir, ins->bailoutKind());
2289 define(lir, ins);
2290 assignSafepoint(lir, ins);
2293 void LIRGenerator::visitStringConvertCase(MStringConvertCase* ins) {
2294 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2296 auto* lir =
2297 new (alloc()) LStringConvertCase(useRegisterAtStart(ins->string()));
2298 defineReturn(lir, ins);
2299 assignSafepoint(lir, ins);
2302 void LIRGenerator::visitStart(MStart* start) {}
2304 void LIRGenerator::visitNop(MNop* nop) {}
2306 void LIRGenerator::visitLimitedTruncate(MLimitedTruncate* nop) {
2307 redefine(nop, nop->input());
2310 void LIRGenerator::visitOsrEntry(MOsrEntry* entry) {
2311 LOsrEntry* lir = new (alloc()) LOsrEntry(temp());
2312 defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
2315 void LIRGenerator::visitOsrValue(MOsrValue* value) {
2316 LOsrValue* lir = new (alloc()) LOsrValue(useRegister(value->entry()));
2317 defineBox(lir, value);
2320 void LIRGenerator::visitOsrReturnValue(MOsrReturnValue* value) {
2321 LOsrReturnValue* lir =
2322 new (alloc()) LOsrReturnValue(useRegister(value->entry()));
2323 defineBox(lir, value);
2326 void LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain* object) {
2327 LOsrEnvironmentChain* lir =
2328 new (alloc()) LOsrEnvironmentChain(useRegister(object->entry()));
2329 define(lir, object);
2332 void LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject* object) {
2333 LOsrArgumentsObject* lir =
2334 new (alloc()) LOsrArgumentsObject(useRegister(object->entry()));
2335 define(lir, object);
2338 void LIRGenerator::visitToDouble(MToDouble* convert) {
2339 MDefinition* opd = convert->input();
2340 mozilla::DebugOnly<MToFPInstruction::ConversionKind> conversion =
2341 convert->conversion();
2343 switch (opd->type()) {
2344 case MIRType::Value: {
2345 LValueToDouble* lir = new (alloc()) LValueToDouble(useBox(opd));
2346 assignSnapshot(lir, convert->bailoutKind());
2347 define(lir, convert);
2348 break;
2351 case MIRType::Null:
2352 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2353 lowerConstantDouble(0, convert);
2354 break;
2356 case MIRType::Undefined:
2357 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2358 lowerConstantDouble(GenericNaN(), convert);
2359 break;
2361 case MIRType::Boolean:
2362 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2363 [[fallthrough]];
2365 case MIRType::Int32: {
2366 LInt32ToDouble* lir =
2367 new (alloc()) LInt32ToDouble(useRegisterAtStart(opd));
2368 define(lir, convert);
2369 break;
2372 case MIRType::Float32: {
2373 LFloat32ToDouble* lir =
2374 new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
2375 define(lir, convert);
2376 break;
2379 case MIRType::Double:
2380 redefine(convert, opd);
2381 break;
2383 default:
2384 // Objects might be effectful. Symbols will throw.
2385 // Strings are complicated - we don't handle them yet.
2386 MOZ_CRASH("unexpected type");
2390 void LIRGenerator::visitToFloat32(MToFloat32* convert) {
2391 MDefinition* opd = convert->input();
2392 mozilla::DebugOnly<MToFloat32::ConversionKind> conversion =
2393 convert->conversion();
2395 switch (opd->type()) {
2396 case MIRType::Value: {
2397 LValueToFloat32* lir = new (alloc()) LValueToFloat32(useBox(opd));
2398 assignSnapshot(lir, convert->bailoutKind());
2399 define(lir, convert);
2400 break;
2403 case MIRType::Null:
2404 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2405 lowerConstantFloat32(0, convert);
2406 break;
2408 case MIRType::Undefined:
2409 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2410 lowerConstantFloat32(GenericNaN(), convert);
2411 break;
2413 case MIRType::Boolean:
2414 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2415 [[fallthrough]];
2417 case MIRType::Int32: {
2418 LInt32ToFloat32* lir =
2419 new (alloc()) LInt32ToFloat32(useRegisterAtStart(opd));
2420 define(lir, convert);
2421 break;
2424 case MIRType::Double: {
2425 LDoubleToFloat32* lir =
2426 new (alloc()) LDoubleToFloat32(useRegisterAtStart(opd));
2427 define(lir, convert);
2428 break;
2431 case MIRType::Float32:
2432 redefine(convert, opd);
2433 break;
2435 default:
2436 // Objects might be effectful. Symbols will throw.
2437 // Strings are complicated - we don't handle them yet.
2438 MOZ_CRASH("unexpected type");
2442 void LIRGenerator::visitToNumberInt32(MToNumberInt32* convert) {
2443 MDefinition* opd = convert->input();
2445 switch (opd->type()) {
2446 case MIRType::Value: {
2447 auto* lir = new (alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(),
2448 LValueToInt32::NORMAL);
2449 assignSnapshot(lir, convert->bailoutKind());
2450 define(lir, convert);
2451 if (lir->mode() == LValueToInt32::TRUNCATE ||
2452 lir->mode() == LValueToInt32::TRUNCATE_NOWRAP) {
2453 assignSafepoint(lir, convert);
2455 break;
2458 case MIRType::Null:
2459 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any);
2460 define(new (alloc()) LInteger(0), convert);
2461 break;
2463 case MIRType::Boolean:
2464 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any ||
2465 convert->conversion() ==
2466 IntConversionInputKind::NumbersOrBoolsOnly);
2467 redefine(convert, opd);
2468 break;
2470 case MIRType::Int32:
2471 redefine(convert, opd);
2472 break;
2474 case MIRType::Float32: {
2475 LFloat32ToInt32* lir = new (alloc()) LFloat32ToInt32(useRegister(opd));
2476 assignSnapshot(lir, convert->bailoutKind());
2477 define(lir, convert);
2478 break;
2481 case MIRType::Double: {
2482 LDoubleToInt32* lir = new (alloc()) LDoubleToInt32(useRegister(opd));
2483 assignSnapshot(lir, convert->bailoutKind());
2484 define(lir, convert);
2485 break;
2488 case MIRType::String:
2489 case MIRType::Symbol:
2490 case MIRType::BigInt:
2491 case MIRType::Object:
2492 case MIRType::Undefined:
2493 // Objects might be effectful. Symbols and BigInts throw. Undefined
2494 // coerces to NaN, not int32.
2495 MOZ_CRASH("ToInt32 invalid input type");
2497 default:
2498 MOZ_CRASH("unexpected type");
2502 void LIRGenerator::visitToIntegerInt32(MToIntegerInt32* convert) {
2503 MDefinition* opd = convert->input();
2505 switch (opd->type()) {
2506 case MIRType::Value: {
2507 auto* lir = new (alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(),
2508 LValueToInt32::TRUNCATE_NOWRAP);
2509 assignSnapshot(lir, convert->bailoutKind());
2510 define(lir, convert);
2511 assignSafepoint(lir, convert);
2512 break;
2515 case MIRType::Undefined:
2516 case MIRType::Null:
2517 define(new (alloc()) LInteger(0), convert);
2518 break;
2520 case MIRType::Boolean:
2521 case MIRType::Int32:
2522 redefine(convert, opd);
2523 break;
2525 case MIRType::Float32: {
2526 auto* lir = new (alloc()) LFloat32ToIntegerInt32(useRegister(opd));
2527 assignSnapshot(lir, convert->bailoutKind());
2528 define(lir, convert);
2529 break;
2532 case MIRType::Double: {
2533 auto* lir = new (alloc()) LDoubleToIntegerInt32(useRegister(opd));
2534 assignSnapshot(lir, convert->bailoutKind());
2535 define(lir, convert);
2536 break;
2539 case MIRType::String:
2540 case MIRType::Symbol:
2541 case MIRType::BigInt:
2542 case MIRType::Object:
2543 // Objects might be effectful. Symbols and BigInts throw.
2544 // Strings are complicated - we don't handle them yet.
2545 MOZ_CRASH("ToIntegerInt32 invalid input type");
2547 default:
2548 MOZ_CRASH("unexpected type");
2552 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) {
2553 MDefinition* opd = truncate->input();
2555 switch (opd->type()) {
2556 case MIRType::Value: {
2557 LValueToInt32* lir = new (alloc()) LValueToInt32(
2558 useBox(opd), tempDouble(), temp(), LValueToInt32::TRUNCATE);
2559 assignSnapshot(lir, truncate->bailoutKind());
2560 define(lir, truncate);
2561 assignSafepoint(lir, truncate);
2562 break;
2565 case MIRType::Null:
2566 case MIRType::Undefined:
2567 define(new (alloc()) LInteger(0), truncate);
2568 break;
2570 case MIRType::Int32:
2571 case MIRType::Boolean:
2572 redefine(truncate, opd);
2573 break;
2575 case MIRType::Double:
2576 // May call into JS::ToInt32() on the slow OOL path.
2577 gen->setNeedsStaticStackAlignment();
2578 lowerTruncateDToInt32(truncate);
2579 break;
2581 case MIRType::Float32:
2582 // May call into JS::ToInt32() on the slow OOL path.
2583 gen->setNeedsStaticStackAlignment();
2584 lowerTruncateFToInt32(truncate);
2585 break;
2587 default:
2588 // Objects might be effectful. Symbols throw.
2589 // Strings are complicated - we don't handle them yet.
2590 MOZ_CRASH("unexpected type");
2594 void LIRGenerator::visitInt32ToIntPtr(MInt32ToIntPtr* ins) {
2595 MDefinition* input = ins->input();
2596 MOZ_ASSERT(input->type() == MIRType::Int32);
2597 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
2599 #ifdef JS_64BIT
2600 // If the result is only used by instructions that expect a bounds-checked
2601 // index, we must have eliminated or hoisted a bounds check and we can assume
2602 // the index is non-negative. This lets us generate more efficient code.
2603 // In debug builds we verify this non-negative assumption at runtime.
2604 if (ins->canBeNegative()) {
2605 bool canBeNegative = false;
2606 for (MUseDefIterator iter(ins); iter; iter++) {
2607 if (!iter.def()->isSpectreMaskIndex() &&
2608 !iter.def()->isLoadUnboxedScalar() &&
2609 !iter.def()->isStoreUnboxedScalar() &&
2610 !iter.def()->isLoadDataViewElement() &&
2611 !iter.def()->isStoreDataViewElement()) {
2612 canBeNegative = true;
2613 break;
2616 if (!canBeNegative) {
2617 ins->setCanNotBeNegative();
2621 if (ins->canBeNegative()) {
2622 auto* lir = new (alloc()) LInt32ToIntPtr(useAnyAtStart(input));
2623 define(lir, ins);
2624 } else {
2625 auto* lir = new (alloc()) LInt32ToIntPtr(useRegisterAtStart(input));
2626 defineReuseInput(lir, ins, 0);
2628 #else
2629 // On 32-bit platforms this is a no-op.
2630 redefine(ins, input);
2631 #endif
2634 void LIRGenerator::visitNonNegativeIntPtrToInt32(
2635 MNonNegativeIntPtrToInt32* ins) {
2636 MDefinition* input = ins->input();
2637 MOZ_ASSERT(input->type() == MIRType::IntPtr);
2638 MOZ_ASSERT(ins->type() == MIRType::Int32);
2640 #ifdef JS_64BIT
2641 auto* lir =
2642 new (alloc()) LNonNegativeIntPtrToInt32(useRegisterAtStart(input));
2643 assignSnapshot(lir, ins->bailoutKind());
2644 defineReuseInput(lir, ins, 0);
2645 #else
2646 // On 32-bit platforms this is a no-op.
2647 redefine(ins, input);
2648 #endif
2651 void LIRGenerator::visitWasmExtendU32Index(MWasmExtendU32Index* ins) {
2652 #ifdef JS_64BIT
2653 // Technically this produces an Int64 register and I guess we could clean that
2654 // up, but it's a 64-bit only operation, so it doesn't actually matter.
2656 MDefinition* input = ins->input();
2657 MOZ_ASSERT(input->type() == MIRType::Int32);
2658 MOZ_ASSERT(ins->type() == MIRType::Int64);
2660 // Input reuse is OK even on ARM64 because this node *must* reuse its input in
2661 // order not to generate any code at all, as is the intent.
2662 auto* lir = new (alloc()) LWasmExtendU32Index(useRegisterAtStart(input));
2663 defineReuseInput(lir, ins, 0);
2664 #else
2665 MOZ_CRASH("64-bit only");
2666 #endif
2669 void LIRGenerator::visitWasmWrapU32Index(MWasmWrapU32Index* ins) {
2670 MDefinition* input = ins->input();
2671 MOZ_ASSERT(input->type() == MIRType::Int64);
2672 MOZ_ASSERT(ins->type() == MIRType::Int32);
2674 // Tricky: On 64-bit, this just returns its input (except on MIPS64 there may
2675 // be a sign/zero extension). On 32-bit, it returns the low register of the
2676 // input, and should generate no code.
2678 // If this assertion does not hold then using "input" unadorned as an alias
2679 // for the low register will not work.
2680 #if defined(JS_NUNBOX32)
2681 static_assert(INT64LOW_INDEX == 0);
2682 #endif
2684 auto* lir = new (alloc()) LWasmWrapU32Index(useRegisterAtStart(input));
2685 defineReuseInput(lir, ins, 0);
2688 void LIRGenerator::visitIntPtrToDouble(MIntPtrToDouble* ins) {
2689 MDefinition* input = ins->input();
2690 MOZ_ASSERT(input->type() == MIRType::IntPtr);
2691 MOZ_ASSERT(ins->type() == MIRType::Double);
2693 auto* lir = new (alloc()) LIntPtrToDouble(useRegister(input));
2694 define(lir, ins);
2697 void LIRGenerator::visitAdjustDataViewLength(MAdjustDataViewLength* ins) {
2698 MDefinition* input = ins->input();
2699 MOZ_ASSERT(input->type() == MIRType::IntPtr);
2701 auto* lir = new (alloc()) LAdjustDataViewLength(useRegisterAtStart(input));
2702 assignSnapshot(lir, ins->bailoutKind());
2703 defineReuseInput(lir, ins, 0);
2706 void LIRGenerator::visitToBigInt(MToBigInt* ins) {
2707 MDefinition* opd = ins->input();
2709 switch (opd->type()) {
2710 case MIRType::Value: {
2711 auto* lir = new (alloc()) LValueToBigInt(useBox(opd));
2712 assignSnapshot(lir, ins->bailoutKind());
2713 define(lir, ins);
2714 assignSafepoint(lir, ins);
2715 break;
2718 case MIRType::BigInt:
2719 redefine(ins, opd);
2720 break;
2722 default:
2723 MOZ_CRASH("unexpected type");
2727 void LIRGenerator::visitToInt64(MToInt64* ins) {
2728 MDefinition* opd = ins->input();
2730 switch (opd->type()) {
2731 case MIRType::Value: {
2732 auto* lir = new (alloc()) LValueToInt64(useBox(opd), temp());
2733 assignSnapshot(lir, ins->bailoutKind());
2734 defineInt64(lir, ins);
2735 assignSafepoint(lir, ins);
2736 break;
2739 case MIRType::Boolean: {
2740 auto* lir = new (alloc()) LBooleanToInt64(useRegisterAtStart(opd));
2741 defineInt64(lir, ins);
2742 break;
2745 case MIRType::String: {
2746 auto* lir = new (alloc()) LStringToInt64(useRegister(opd));
2747 defineInt64(lir, ins);
2748 assignSafepoint(lir, ins);
2749 break;
2752 // An Int64 may be passed here from a BigInt to Int64 conversion.
2753 case MIRType::Int64: {
2754 redefine(ins, opd);
2755 break;
2758 default:
2759 // Undefined, Null, Number, and Symbol throw.
2760 // Objects may be effectful.
2761 // BigInt operands are eliminated by the type policy.
2762 MOZ_CRASH("unexpected type");
2766 void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64* ins) {
2767 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
2768 auto* lir = new (alloc()) LTruncateBigIntToInt64(useRegister(ins->input()));
2769 defineInt64(lir, ins);
2772 void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt* ins) {
2773 MOZ_ASSERT(ins->input()->type() == MIRType::Int64);
2774 auto* lir =
2775 new (alloc()) LInt64ToBigInt(useInt64Register(ins->input()), temp());
2776 define(lir, ins);
2777 assignSafepoint(lir, ins);
2780 void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) {
2781 MDefinition* input = ins->input();
2782 switch (input->type()) {
2783 case MIRType::Double:
2784 case MIRType::Float32: {
2785 auto* lir = new (alloc()) LWasmTruncateToInt32(useRegisterAtStart(input));
2786 define(lir, ins);
2787 break;
2789 default:
2790 MOZ_CRASH("unexpected type in WasmTruncateToInt32");
2794 void LIRGenerator::visitWasmBuiltinTruncateToInt32(
2795 MWasmBuiltinTruncateToInt32* truncate) {
2796 mozilla::DebugOnly<MDefinition*> opd = truncate->input();
2797 MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
2799 // May call into JS::ToInt32() on the slow OOL path.
2800 gen->setNeedsStaticStackAlignment();
2801 lowerWasmBuiltinTruncateToInt32(truncate);
2804 void LIRGenerator::visitWasmBoxValue(MWasmBoxValue* ins) {
2805 LWasmBoxValue* lir = new (alloc()) LWasmBoxValue(useBox(ins->input()));
2806 define(lir, ins);
2807 assignSafepoint(lir, ins);
2810 void LIRGenerator::visitWasmAnyRefFromJSObject(MWasmAnyRefFromJSObject* ins) {
2811 LWasmAnyRefFromJSObject* lir =
2812 new (alloc()) LWasmAnyRefFromJSObject(useRegisterAtStart(ins->input()));
2813 define(lir, ins);
2816 void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) {
2817 define(new (alloc()) LWrapInt64ToInt32(useInt64AtStart(ins->input())), ins);
2820 void LIRGenerator::visitToString(MToString* ins) {
2821 MDefinition* opd = ins->input();
2823 switch (opd->type()) {
2824 case MIRType::Null: {
2825 const JSAtomState& names = gen->runtime->names();
2826 LPointer* lir = new (alloc()) LPointer(names.null);
2827 define(lir, ins);
2828 break;
2831 case MIRType::Undefined: {
2832 const JSAtomState& names = gen->runtime->names();
2833 LPointer* lir = new (alloc()) LPointer(names.undefined);
2834 define(lir, ins);
2835 break;
2838 case MIRType::Boolean: {
2839 LBooleanToString* lir = new (alloc()) LBooleanToString(useRegister(opd));
2840 define(lir, ins);
2841 break;
2844 case MIRType::Double: {
2845 LDoubleToString* lir =
2846 new (alloc()) LDoubleToString(useRegister(opd), temp());
2848 define(lir, ins);
2849 assignSafepoint(lir, ins);
2850 break;
2853 case MIRType::Int32: {
2854 LIntToString* lir = new (alloc()) LIntToString(useRegister(opd));
2856 define(lir, ins);
2857 assignSafepoint(lir, ins);
2858 break;
2861 case MIRType::String:
2862 redefine(ins, ins->input());
2863 break;
2865 case MIRType::Value: {
2866 LValueToString* lir =
2867 new (alloc()) LValueToString(useBox(opd), tempToUnbox());
2868 if (ins->needsSnapshot()) {
2869 assignSnapshot(lir, ins->bailoutKind());
2871 define(lir, ins);
2872 assignSafepoint(lir, ins);
2873 break;
2876 default:
2877 // Float32, symbols, bigint, and objects are not supported.
2878 MOZ_CRASH("unexpected type");
2882 void LIRGenerator::visitRegExp(MRegExp* ins) {
2883 LRegExp* lir = new (alloc()) LRegExp(temp());
2884 define(lir, ins);
2885 assignSafepoint(lir, ins);
2888 void LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) {
2889 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
2890 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2891 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
2893 LRegExpMatcher* lir = new (alloc()) LRegExpMatcher(
2894 useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
2895 useFixedAtStart(ins->string(), RegExpMatcherStringReg),
2896 useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg));
2897 defineReturn(lir, ins);
2898 assignSafepoint(lir, ins);
2901 void LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) {
2902 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
2903 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2904 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
2906 LRegExpSearcher* lir = new (alloc()) LRegExpSearcher(
2907 useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg),
2908 useFixedAtStart(ins->string(), RegExpTesterStringReg),
2909 useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg));
2910 defineReturn(lir, ins);
2911 assignSafepoint(lir, ins);
2914 void LIRGenerator::visitRegExpTester(MRegExpTester* ins) {
2915 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
2916 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2917 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
2919 LRegExpTester* lir = new (alloc()) LRegExpTester(
2920 useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg),
2921 useFixedAtStart(ins->string(), RegExpTesterStringReg),
2922 useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg));
2923 defineReturn(lir, ins);
2924 assignSafepoint(lir, ins);
2927 void LIRGenerator::visitRegExpPrototypeOptimizable(
2928 MRegExpPrototypeOptimizable* ins) {
2929 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
2930 MOZ_ASSERT(ins->type() == MIRType::Boolean);
2931 LRegExpPrototypeOptimizable* lir = new (alloc())
2932 LRegExpPrototypeOptimizable(useRegister(ins->object()), temp());
2933 define(lir, ins);
2936 void LIRGenerator::visitRegExpInstanceOptimizable(
2937 MRegExpInstanceOptimizable* ins) {
2938 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
2939 MOZ_ASSERT(ins->proto()->type() == MIRType::Object);
2940 MOZ_ASSERT(ins->type() == MIRType::Boolean);
2941 LRegExpInstanceOptimizable* lir = new (alloc()) LRegExpInstanceOptimizable(
2942 useRegister(ins->object()), useRegister(ins->proto()), temp());
2943 define(lir, ins);
2946 void LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) {
2947 MOZ_ASSERT(ins->str()->type() == MIRType::String);
2948 MOZ_ASSERT(ins->type() == MIRType::Int32);
2949 LGetFirstDollarIndex* lir = new (alloc())
2950 LGetFirstDollarIndex(useRegister(ins->str()), temp(), temp(), temp());
2951 define(lir, ins);
2952 assignSafepoint(lir, ins);
2955 void LIRGenerator::visitStringReplace(MStringReplace* ins) {
2956 MOZ_ASSERT(ins->pattern()->type() == MIRType::String);
2957 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2958 MOZ_ASSERT(ins->replacement()->type() == MIRType::String);
2960 LStringReplace* lir = new (alloc())
2961 LStringReplace(useRegisterOrConstantAtStart(ins->string()),
2962 useRegisterAtStart(ins->pattern()),
2963 useRegisterOrConstantAtStart(ins->replacement()));
2964 defineReturn(lir, ins);
2965 assignSafepoint(lir, ins);
2968 void LIRGenerator::visitBinaryCache(MBinaryCache* ins) {
2969 MDefinition* lhs = ins->getOperand(0);
2970 MDefinition* rhs = ins->getOperand(1);
2972 MOZ_ASSERT(ins->type() == MIRType::Value || ins->type() == MIRType::Boolean);
2973 LInstruction* lir;
2974 if (ins->type() == MIRType::Value) {
2975 LBinaryValueCache* valueLir = new (alloc()) LBinaryValueCache(
2976 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
2977 defineBox(valueLir, ins);
2978 lir = valueLir;
2979 } else {
2980 MOZ_ASSERT(ins->type() == MIRType::Boolean);
2981 LBinaryBoolCache* boolLir = new (alloc()) LBinaryBoolCache(
2982 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
2983 define(boolLir, ins);
2984 lir = boolLir;
2986 assignSafepoint(lir, ins);
2989 void LIRGenerator::visitUnaryCache(MUnaryCache* ins) {
2990 MDefinition* input = ins->getOperand(0);
2991 MOZ_ASSERT(ins->type() == MIRType::Value);
2993 LUnaryCache* lir = new (alloc()) LUnaryCache(useBox(input));
2994 defineBox(lir, ins);
2995 assignSafepoint(lir, ins);
2998 void LIRGenerator::visitModuleMetadata(MModuleMetadata* ins) {
2999 LModuleMetadata* lir = new (alloc()) LModuleMetadata();
3000 defineReturn(lir, ins);
3001 assignSafepoint(lir, ins);
3004 void LIRGenerator::visitDynamicImport(MDynamicImport* ins) {
3005 LDynamicImport* lir = new (alloc()) LDynamicImport(
3006 useBoxAtStart(ins->specifier()), useBoxAtStart(ins->options()));
3007 defineReturn(lir, ins);
3008 assignSafepoint(lir, ins);
3011 void LIRGenerator::visitLambda(MLambda* ins) {
3012 auto* lir =
3013 new (alloc()) LLambda(useRegister(ins->environmentChain()), temp());
3014 define(lir, ins);
3015 assignSafepoint(lir, ins);
3018 void LIRGenerator::visitLambdaArrow(MLambdaArrow* ins) {
3019 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3020 MOZ_ASSERT(ins->newTargetDef()->type() == MIRType::Value);
3022 LLambdaArrow* lir =
3023 new (alloc()) LLambdaArrow(useRegister(ins->environmentChain()),
3024 useBox(ins->newTargetDef()), temp());
3025 define(lir, ins);
3026 assignSafepoint(lir, ins);
3029 void LIRGenerator::visitFunctionWithProto(MFunctionWithProto* ins) {
3030 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3031 MOZ_ASSERT(ins->prototype()->type() == MIRType::Object);
3033 auto* lir = new (alloc())
3034 LFunctionWithProto(useRegisterAtStart(ins->environmentChain()),
3035 useRegisterAtStart(ins->prototype()));
3036 defineReturn(lir, ins);
3037 assignSafepoint(lir, ins);
3040 void LIRGenerator::visitSetFunName(MSetFunName* ins) {
3041 MOZ_ASSERT(ins->fun()->type() == MIRType::Object);
3042 MOZ_ASSERT(ins->name()->type() == MIRType::Value);
3044 LSetFunName* lir = new (alloc())
3045 LSetFunName(useRegisterAtStart(ins->fun()), useBoxAtStart(ins->name()));
3046 add(lir, ins);
3047 assignSafepoint(lir, ins);
3050 void LIRGenerator::visitNewLexicalEnvironmentObject(
3051 MNewLexicalEnvironmentObject* ins) {
3052 MDefinition* enclosing = ins->enclosing();
3053 MOZ_ASSERT(enclosing->type() == MIRType::Object);
3055 LNewLexicalEnvironmentObject* lir =
3056 new (alloc()) LNewLexicalEnvironmentObject(useRegisterAtStart(enclosing));
3058 defineReturn(lir, ins);
3059 assignSafepoint(lir, ins);
3062 void LIRGenerator::visitCopyLexicalEnvironmentObject(
3063 MCopyLexicalEnvironmentObject* ins) {
3064 MDefinition* env = ins->env();
3065 MOZ_ASSERT(env->type() == MIRType::Object);
3067 LCopyLexicalEnvironmentObject* lir =
3068 new (alloc()) LCopyLexicalEnvironmentObject(useRegisterAtStart(env));
3070 defineReturn(lir, ins);
3071 assignSafepoint(lir, ins);
3074 void LIRGenerator::visitNewClassBodyEnvironmentObject(
3075 MNewClassBodyEnvironmentObject* ins) {
3076 MDefinition* enclosing = ins->enclosing();
3077 MOZ_ASSERT(enclosing->type() == MIRType::Object);
3079 LNewClassBodyEnvironmentObject* lir = new (alloc())
3080 LNewClassBodyEnvironmentObject(useRegisterAtStart(enclosing));
3082 defineReturn(lir, ins);
3083 assignSafepoint(lir, ins);
3086 void LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins) {
3087 MDefinition* obj = ins->object();
3088 MOZ_ASSERT(obj->type() == MIRType::Object);
3090 add(new (alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
3093 void LIRGenerator::visitSlots(MSlots* ins) {
3094 define(new (alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
3097 void LIRGenerator::visitElements(MElements* ins) {
3098 define(new (alloc()) LElements(useRegisterAtStart(ins->object())), ins);
3101 void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot* ins) {
3102 MOZ_ASSERT(ins->type() == MIRType::Value);
3103 defineBox(new (alloc()) LLoadDynamicSlotV(useRegisterAtStart(ins->slots())),
3104 ins);
3107 void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins) {
3108 define(new (alloc())
3109 LFunctionEnvironment(useRegisterAtStart(ins->function())),
3110 ins);
3113 void LIRGenerator::visitHomeObject(MHomeObject* ins) {
3114 define(new (alloc()) LHomeObject(useRegisterAtStart(ins->function())), ins);
3117 void LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase* ins) {
3118 MOZ_ASSERT(ins->homeObject()->type() == MIRType::Object);
3119 MOZ_ASSERT(ins->type() == MIRType::Value);
3121 auto lir =
3122 new (alloc()) LHomeObjectSuperBase(useRegisterAtStart(ins->homeObject()));
3123 defineBox(lir, ins);
3126 void LIRGenerator::visitInterruptCheck(MInterruptCheck* ins) {
3127 LInstruction* lir = new (alloc()) LInterruptCheck();
3128 add(lir, ins);
3129 assignSafepoint(lir, ins);
3132 void LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck* ins) {
3133 auto* lir =
3134 new (alloc()) LWasmInterruptCheck(useRegisterAtStart(ins->tlsPtr()));
3135 add(lir, ins);
3137 assignWasmSafepoint(lir, ins);
3140 void LIRGenerator::visitWasmTrap(MWasmTrap* ins) {
3141 add(new (alloc()) LWasmTrap, ins);
3144 void LIRGenerator::visitWasmReinterpret(MWasmReinterpret* ins) {
3145 if (ins->type() == MIRType::Int64) {
3146 defineInt64(new (alloc())
3147 LWasmReinterpretToI64(useRegisterAtStart(ins->input())),
3148 ins);
3149 } else if (ins->input()->type() == MIRType::Int64) {
3150 define(new (alloc())
3151 LWasmReinterpretFromI64(useInt64RegisterAtStart(ins->input())),
3152 ins);
3153 } else {
3154 define(new (alloc()) LWasmReinterpret(useRegisterAtStart(ins->input())),
3155 ins);
3159 void LIRGenerator::visitStoreDynamicSlot(MStoreDynamicSlot* ins) {
3160 LInstruction* lir;
3162 switch (ins->value()->type()) {
3163 case MIRType::Value:
3164 lir = new (alloc())
3165 LStoreDynamicSlotV(useRegister(ins->slots()), useBox(ins->value()));
3166 add(lir, ins);
3167 break;
3169 case MIRType::Double:
3170 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3171 useRegister(ins->value())),
3172 ins);
3173 break;
3175 case MIRType::Float32:
3176 MOZ_CRASH("Float32 shouldn't be stored in a slot.");
3178 default:
3179 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3180 useRegisterOrConstant(ins->value())),
3181 ins);
3182 break;
3186 // Returns true iff |def| is a constant that's either not a GC thing or is not
3187 // allocated in the nursery.
3188 static bool IsNonNurseryConstant(MDefinition* def) {
3189 if (!def->isConstant()) {
3190 return false;
3192 Value v = def->toConstant()->toJSValue();
3193 return !v.isGCThing() || !IsInsideNursery(v.toGCThing());
3196 void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) {
3197 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3199 // LPostWriteBarrier assumes that if it has a constant object then that
3200 // object is tenured, and does not need to be tested for being in the
3201 // nursery. Ensure that assumption holds by lowering constant nursery
3202 // objects to a register.
3203 bool useConstantObject = IsNonNurseryConstant(ins->object());
3205 switch (ins->value()->type()) {
3206 case MIRType::Object: {
3207 LDefinition tmp =
3208 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3209 LPostWriteBarrierO* lir = new (alloc())
3210 LPostWriteBarrierO(useConstantObject ? useOrConstant(ins->object())
3211 : useRegister(ins->object()),
3212 useRegister(ins->value()), tmp);
3213 add(lir, ins);
3214 assignSafepoint(lir, ins);
3215 break;
3217 case MIRType::String: {
3218 LDefinition tmp =
3219 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3220 LPostWriteBarrierS* lir = new (alloc())
3221 LPostWriteBarrierS(useConstantObject ? useOrConstant(ins->object())
3222 : useRegister(ins->object()),
3223 useRegister(ins->value()), tmp);
3224 add(lir, ins);
3225 assignSafepoint(lir, ins);
3226 break;
3228 case MIRType::BigInt: {
3229 LDefinition tmp =
3230 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3231 auto* lir = new (alloc())
3232 LPostWriteBarrierBI(useConstantObject ? useOrConstant(ins->object())
3233 : useRegister(ins->object()),
3234 useRegister(ins->value()), tmp);
3235 add(lir, ins);
3236 assignSafepoint(lir, ins);
3237 break;
3239 case MIRType::Value: {
3240 LDefinition tmp =
3241 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3242 LPostWriteBarrierV* lir = new (alloc())
3243 LPostWriteBarrierV(useConstantObject ? useOrConstant(ins->object())
3244 : useRegister(ins->object()),
3245 useBox(ins->value()), tmp);
3246 add(lir, ins);
3247 assignSafepoint(lir, ins);
3248 break;
3250 default:
3251 // Currently, only objects and strings can be in the nursery. Other
3252 // instruction types cannot hold nursery pointers.
3253 break;
3257 void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) {
3258 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3259 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3261 // LPostWriteElementBarrier assumes that if it has a constant object then that
3262 // object is tenured, and does not need to be tested for being in the
3263 // nursery. Ensure that assumption holds by lowering constant nursery
3264 // objects to a register.
3265 bool useConstantObject =
3266 ins->object()->isConstant() &&
3267 !IsInsideNursery(&ins->object()->toConstant()->toObject());
3269 switch (ins->value()->type()) {
3270 case MIRType::Object: {
3271 LDefinition tmp =
3272 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3273 LPostWriteElementBarrierO* lir = new (alloc()) LPostWriteElementBarrierO(
3274 useConstantObject ? useOrConstant(ins->object())
3275 : useRegister(ins->object()),
3276 useRegister(ins->value()), useRegister(ins->index()), tmp);
3277 add(lir, ins);
3278 assignSafepoint(lir, ins);
3279 break;
3281 case MIRType::String: {
3282 LDefinition tmp =
3283 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3284 LPostWriteElementBarrierS* lir = new (alloc()) LPostWriteElementBarrierS(
3285 useConstantObject ? useOrConstant(ins->object())
3286 : useRegister(ins->object()),
3287 useRegister(ins->value()), useRegister(ins->index()), tmp);
3288 add(lir, ins);
3289 assignSafepoint(lir, ins);
3290 break;
3292 case MIRType::BigInt: {
3293 LDefinition tmp =
3294 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3295 auto* lir = new (alloc()) LPostWriteElementBarrierBI(
3296 useConstantObject ? useOrConstant(ins->object())
3297 : useRegister(ins->object()),
3298 useRegister(ins->value()), useRegister(ins->index()), tmp);
3299 add(lir, ins);
3300 assignSafepoint(lir, ins);
3301 break;
3303 case MIRType::Value: {
3304 LDefinition tmp =
3305 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3306 LPostWriteElementBarrierV* lir = new (alloc()) LPostWriteElementBarrierV(
3307 useConstantObject ? useOrConstant(ins->object())
3308 : useRegister(ins->object()),
3309 useRegister(ins->index()), useBox(ins->value()), tmp);
3310 add(lir, ins);
3311 assignSafepoint(lir, ins);
3312 break;
3314 default:
3315 // Currently, only objects, strings, and bigints can be in the nursery.
3316 // Other instruction types cannot hold nursery pointers.
3317 break;
3321 void LIRGenerator::visitArrayLength(MArrayLength* ins) {
3322 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3323 auto* lir = new (alloc()) LArrayLength(useRegisterAtStart(ins->elements()));
3324 assignSnapshot(lir, ins->bailoutKind());
3325 define(lir, ins);
3328 void LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) {
3329 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3330 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3332 MOZ_ASSERT(ins->index()->isConstant());
3333 add(new (alloc()) LSetArrayLength(useRegister(ins->elements()),
3334 useRegisterOrConstant(ins->index())),
3335 ins);
3338 void LIRGenerator::visitFunctionLength(MFunctionLength* ins) {
3339 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3341 auto* lir = new (alloc()) LFunctionLength(useRegister(ins->function()));
3342 assignSnapshot(lir, ins->bailoutKind());
3343 define(lir, ins);
3346 void LIRGenerator::visitFunctionName(MFunctionName* ins) {
3347 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3349 auto* lir = new (alloc()) LFunctionName(useRegister(ins->function()));
3350 assignSnapshot(lir, ins->bailoutKind());
3351 define(lir, ins);
3354 void LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator* ins) {
3355 MOZ_ASSERT(ins->iter()->type() == MIRType::Object);
3356 MOZ_ASSERT(ins->result()->type() == MIRType::Object);
3357 auto lir = new (alloc()) LGetNextEntryForIterator(useRegister(ins->iter()),
3358 useRegister(ins->result()),
3359 temp(), temp(), temp());
3360 define(lir, ins);
3363 void LIRGenerator::visitArrayBufferByteLength(MArrayBufferByteLength* ins) {
3364 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3365 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3367 auto* lir =
3368 new (alloc()) LArrayBufferByteLength(useRegisterAtStart(ins->object()));
3369 define(lir, ins);
3372 void LIRGenerator::visitArrayBufferViewLength(MArrayBufferViewLength* ins) {
3373 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3374 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3376 auto* lir =
3377 new (alloc()) LArrayBufferViewLength(useRegisterAtStart(ins->object()));
3378 define(lir, ins);
3381 void LIRGenerator::visitArrayBufferViewByteOffset(
3382 MArrayBufferViewByteOffset* ins) {
3383 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3384 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3386 auto* lir = new (alloc())
3387 LArrayBufferViewByteOffset(useRegisterAtStart(ins->object()));
3388 define(lir, ins);
3391 void LIRGenerator::visitArrayBufferViewElements(MArrayBufferViewElements* ins) {
3392 MOZ_ASSERT(ins->type() == MIRType::Elements);
3393 define(new (alloc())
3394 LArrayBufferViewElements(useRegisterAtStart(ins->object())),
3395 ins);
3398 void LIRGenerator::visitTypedArrayElementSize(MTypedArrayElementSize* ins) {
3399 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3400 define(new (alloc())
3401 LTypedArrayElementSize(useRegisterAtStart(ins->object())),
3402 ins);
3405 void LIRGenerator::visitGuardHasAttachedArrayBuffer(
3406 MGuardHasAttachedArrayBuffer* ins) {
3407 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3409 auto* lir = new (alloc())
3410 LGuardHasAttachedArrayBuffer(useRegister(ins->object()), temp());
3411 assignSnapshot(lir, ins->bailoutKind());
3412 add(lir, ins);
3413 redefine(ins, ins->object());
3416 void LIRGenerator::visitGuardNumberToIntPtrIndex(
3417 MGuardNumberToIntPtrIndex* ins) {
3418 MDefinition* input = ins->input();
3419 MOZ_ASSERT(input->type() == MIRType::Double);
3421 auto* lir = new (alloc()) LGuardNumberToIntPtrIndex(useRegister(input));
3422 if (!ins->supportOOB()) {
3423 assignSnapshot(lir, ins->bailoutKind());
3425 define(lir, ins);
3428 void LIRGenerator::visitInitializedLength(MInitializedLength* ins) {
3429 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3430 define(new (alloc()) LInitializedLength(useRegisterAtStart(ins->elements())),
3431 ins);
3434 void LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) {
3435 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3436 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3438 MOZ_ASSERT(ins->index()->isConstant());
3439 add(new (alloc()) LSetInitializedLength(useRegister(ins->elements()),
3440 useRegisterOrConstant(ins->index())),
3441 ins);
3444 void LIRGenerator::visitNot(MNot* ins) {
3445 MDefinition* op = ins->input();
3447 // String is converted to length of string in the type analysis phase (see
3448 // TestPolicy).
3449 MOZ_ASSERT(op->type() != MIRType::String);
3451 // - boolean: x xor 1
3452 // - int32: LCompare(x, 0)
3453 // - double: LCompare(x, 0)
3454 // - null or undefined: true
3455 // - symbol: false
3456 // - bigint: LNotBI(x)
3457 // - object: false if it never emulates undefined, else LNotO(x)
3458 switch (op->type()) {
3459 case MIRType::Boolean: {
3460 MConstant* cons = MConstant::New(alloc(), Int32Value(1));
3461 ins->block()->insertBefore(ins, cons);
3462 lowerForALU(new (alloc()) LBitOpI(JSOp::BitXor), ins, op, cons);
3463 break;
3465 case MIRType::Int32:
3466 define(new (alloc()) LNotI(useRegisterAtStart(op)), ins);
3467 break;
3468 case MIRType::Int64:
3469 define(new (alloc()) LNotI64(useInt64RegisterAtStart(op)), ins);
3470 break;
3471 case MIRType::Double:
3472 define(new (alloc()) LNotD(useRegister(op)), ins);
3473 break;
3474 case MIRType::Float32:
3475 define(new (alloc()) LNotF(useRegister(op)), ins);
3476 break;
3477 case MIRType::Undefined:
3478 case MIRType::Null:
3479 define(new (alloc()) LInteger(1), ins);
3480 break;
3481 case MIRType::Symbol:
3482 define(new (alloc()) LInteger(0), ins);
3483 break;
3484 case MIRType::BigInt:
3485 define(new (alloc()) LNotBI(useRegisterAtStart(op)), ins);
3486 break;
3487 case MIRType::Object:
3488 define(new (alloc()) LNotO(useRegister(op)), ins);
3489 break;
3490 case MIRType::Value: {
3491 auto* lir = new (alloc()) LNotV(useBox(op), tempDouble(), temp(), temp());
3492 define(lir, ins);
3493 break;
3496 default:
3497 MOZ_CRASH("Unexpected MIRType.");
3501 void LIRGenerator::visitBoundsCheck(MBoundsCheck* ins) {
3502 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
3503 MOZ_ASSERT(ins->index()->type() == ins->type());
3504 MOZ_ASSERT(ins->length()->type() == ins->type());
3506 if (!ins->fallible()) {
3507 return;
3510 LInstruction* check;
3511 if (ins->minimum() || ins->maximum()) {
3512 check = new (alloc())
3513 LBoundsCheckRange(useRegisterOrInt32Constant(ins->index()),
3514 useAny(ins->length()), temp());
3515 } else {
3516 check = new (alloc()) LBoundsCheck(useRegisterOrInt32Constant(ins->index()),
3517 useAnyOrInt32Constant(ins->length()));
3519 assignSnapshot(check, ins->bailoutKind());
3520 add(check, ins);
3523 void LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins) {
3524 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
3525 MOZ_ASSERT(ins->index()->type() == ins->type());
3526 MOZ_ASSERT(ins->length()->type() == ins->type());
3528 auto* lir = new (alloc())
3529 LSpectreMaskIndex(useRegister(ins->index()), useAny(ins->length()));
3530 define(lir, ins);
3533 void LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins) {
3534 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3536 if (!ins->fallible()) {
3537 return;
3540 LInstruction* check =
3541 new (alloc()) LBoundsCheckLower(useRegister(ins->index()));
3542 assignSnapshot(check, ins->bailoutKind());
3543 add(check, ins);
3546 void LIRGenerator::visitInArray(MInArray* ins) {
3547 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3548 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3549 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
3550 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3551 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3553 auto* lir = new (alloc()) LInArray(useRegister(ins->elements()),
3554 useRegisterOrConstant(ins->index()),
3555 useRegister(ins->initLength()));
3556 if (ins->needsNegativeIntCheck()) {
3557 assignSnapshot(lir, ins->bailoutKind());
3559 define(lir, ins);
3562 void LIRGenerator::visitGuardElementNotHole(MGuardElementNotHole* ins) {
3563 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3564 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3566 auto* guard = new (alloc())
3567 LGuardElementNotHole(useRegisterAtStart(ins->elements()),
3568 useRegisterOrConstantAtStart(ins->index()));
3569 assignSnapshot(guard, ins->bailoutKind());
3570 add(guard, ins);
3573 void LIRGenerator::visitLoadElement(MLoadElement* ins) {
3574 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3575 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3576 MOZ_ASSERT(ins->type() == MIRType::Value);
3578 auto* lir = new (alloc()) LLoadElementV(useRegister(ins->elements()),
3579 useRegisterOrConstant(ins->index()));
3580 assignSnapshot(lir, ins->bailoutKind());
3581 defineBox(lir, ins);
3584 void LIRGenerator::visitLoadElementHole(MLoadElementHole* ins) {
3585 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3586 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3587 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
3588 MOZ_ASSERT(ins->type() == MIRType::Value);
3590 LLoadElementHole* lir = new (alloc())
3591 LLoadElementHole(useRegister(ins->elements()), useRegister(ins->index()),
3592 useRegister(ins->initLength()));
3593 if (ins->needsNegativeIntCheck()) {
3594 assignSnapshot(lir, ins->bailoutKind());
3596 defineBox(lir, ins);
3599 void LIRGenerator::visitStoreElement(MStoreElement* ins) {
3600 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3601 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3603 const LUse elements = useRegister(ins->elements());
3604 const LAllocation index = useRegisterOrConstant(ins->index());
3606 switch (ins->value()->type()) {
3607 case MIRType::Value: {
3608 LInstruction* lir =
3609 new (alloc()) LStoreElementV(elements, index, useBox(ins->value()));
3610 if (ins->fallible()) {
3611 assignSnapshot(lir, ins->bailoutKind());
3613 add(lir, ins);
3614 break;
3617 default: {
3618 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3619 LInstruction* lir = new (alloc()) LStoreElementT(elements, index, value);
3620 if (ins->fallible()) {
3621 assignSnapshot(lir, ins->bailoutKind());
3623 add(lir, ins);
3624 break;
3629 void LIRGenerator::visitStoreHoleValueElement(MStoreHoleValueElement* ins) {
3630 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3631 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3633 auto* lir = new (alloc()) LStoreHoleValueElement(useRegister(ins->elements()),
3634 useRegister(ins->index()));
3635 add(lir, ins);
3638 static bool BoundsCheckNeedsSpectreTemp() {
3639 // On x86, spectreBoundsCheck32 can emit better code if it has a scratch
3640 // register and index masking is enabled.
3641 #ifdef JS_CODEGEN_X86
3642 return JitOptions.spectreIndexMasking;
3643 #else
3644 return false;
3645 #endif
3648 void LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) {
3649 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3650 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3652 const LUse object = useRegister(ins->object());
3653 const LUse elements = useRegister(ins->elements());
3654 const LAllocation index = useRegister(ins->index());
3656 LDefinition spectreTemp =
3657 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
3659 LInstruction* lir;
3660 switch (ins->value()->type()) {
3661 case MIRType::Value:
3662 lir = new (alloc()) LStoreElementHoleV(object, elements, index,
3663 useBox(ins->value()), spectreTemp);
3664 break;
3666 default: {
3667 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3668 lir = new (alloc())
3669 LStoreElementHoleT(object, elements, index, value, spectreTemp);
3670 break;
3674 add(lir, ins);
3675 assignSafepoint(lir, ins);
3678 void LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) {
3679 define(new (alloc()) LEffectiveAddress(useRegister(ins->base()),
3680 useRegister(ins->index())),
3681 ins);
3684 void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) {
3685 MOZ_ASSERT(ins->type() == MIRType::Value);
3687 auto* lir =
3688 new (alloc()) LArrayPopShift(useRegister(ins->object()), temp(), temp());
3689 assignSnapshot(lir, ins->bailoutKind());
3690 defineBox(lir, ins);
3692 if (ins->mode() == MArrayPopShift::Shift) {
3693 assignSafepoint(lir, ins);
3697 void LIRGenerator::visitArrayPush(MArrayPush* ins) {
3698 MOZ_ASSERT(ins->type() == MIRType::Int32);
3699 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
3701 LUse object = useRegister(ins->object());
3703 LDefinition spectreTemp =
3704 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
3706 auto* lir = new (alloc())
3707 LArrayPush(object, useBox(ins->value()), temp(), spectreTemp);
3708 // We will bailout before pushing if the length would overflow INT32_MAX.
3709 assignSnapshot(lir, ins->bailoutKind());
3710 define(lir, ins);
3711 assignSafepoint(lir, ins);
3714 void LIRGenerator::visitArraySlice(MArraySlice* ins) {
3715 MOZ_ASSERT(ins->type() == MIRType::Object);
3716 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3717 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
3718 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
3720 LArraySlice* lir = new (alloc()) LArraySlice(
3721 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
3722 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
3723 tempFixed(CallTempReg1));
3724 assignSnapshot(lir, ins->bailoutKind());
3725 defineReturn(lir, ins);
3726 assignSafepoint(lir, ins);
3729 void LIRGenerator::visitArrayJoin(MArrayJoin* ins) {
3730 MOZ_ASSERT(ins->type() == MIRType::String);
3731 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
3732 MOZ_ASSERT(ins->sep()->type() == MIRType::String);
3734 auto* lir = new (alloc())
3735 LArrayJoin(useRegisterAtStart(ins->array()),
3736 useRegisterAtStart(ins->sep()), tempFixed(CallTempReg0));
3737 defineReturn(lir, ins);
3738 assignSafepoint(lir, ins);
3741 void LIRGenerator::visitStringSplit(MStringSplit* ins) {
3742 MOZ_ASSERT(ins->type() == MIRType::Object);
3743 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3744 MOZ_ASSERT(ins->separator()->type() == MIRType::String);
3746 LStringSplit* lir = new (alloc()) LStringSplit(
3747 useRegisterAtStart(ins->string()), useRegisterAtStart(ins->separator()));
3748 defineReturn(lir, ins);
3749 assignSafepoint(lir, ins);
3752 void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) {
3753 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3754 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
3755 MOZ_ASSERT(IsNumericType(ins->type()) || ins->type() == MIRType::Boolean);
3757 if (Scalar::isBigIntType(ins->storageType()) &&
3758 ins->requiresMemoryBarrier()) {
3759 lowerAtomicLoad64(ins);
3760 return;
3763 const LUse elements = useRegister(ins->elements());
3764 const LAllocation index = useRegisterOrIndexConstant(
3765 ins->index(), ins->storageType(), ins->offsetAdjustment());
3767 Synchronization sync = Synchronization::Load();
3768 if (ins->requiresMemoryBarrier()) {
3769 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
3770 add(fence, ins);
3773 if (!Scalar::isBigIntType(ins->storageType())) {
3774 // We need a temp register for Uint32Array with known double result.
3775 LDefinition tempDef = LDefinition::BogusTemp();
3776 if (ins->storageType() == Scalar::Uint32 &&
3777 IsFloatingPointType(ins->type())) {
3778 tempDef = temp();
3781 auto* lir = new (alloc()) LLoadUnboxedScalar(elements, index, tempDef);
3782 if (ins->fallible()) {
3783 assignSnapshot(lir, ins->bailoutKind());
3785 define(lir, ins);
3786 } else {
3787 MOZ_ASSERT(ins->type() == MIRType::BigInt);
3789 auto* lir =
3790 new (alloc()) LLoadUnboxedBigInt(elements, index, temp(), tempInt64());
3791 define(lir, ins);
3792 assignSafepoint(lir, ins);
3795 if (ins->requiresMemoryBarrier()) {
3796 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
3797 add(fence, ins);
3801 void LIRGenerator::visitLoadDataViewElement(MLoadDataViewElement* ins) {
3802 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3803 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
3805 MOZ_ASSERT(IsNumericType(ins->type()));
3807 const LUse elements = useRegister(ins->elements());
3808 const LUse index = useRegister(ins->index());
3809 const LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
3811 // We need a temp register for:
3812 // - Uint32Array with known double result,
3813 // - Float32Array,
3814 // - and BigInt64Array and BigUint64Array.
3815 LDefinition tempDef = LDefinition::BogusTemp();
3816 if ((ins->storageType() == Scalar::Uint32 &&
3817 IsFloatingPointType(ins->type())) ||
3818 ins->storageType() == Scalar::Float32) {
3819 tempDef = temp();
3821 if (Scalar::isBigIntType(ins->storageType())) {
3822 #ifdef JS_CODEGEN_X86
3823 // There are not enough registers on x86.
3824 if (littleEndian.isConstant()) {
3825 tempDef = temp();
3827 #else
3828 tempDef = temp();
3829 #endif
3832 // We also need a separate 64-bit temp register for:
3833 // - Float64Array
3834 // - and BigInt64Array and BigUint64Array.
3835 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
3836 if (Scalar::byteSize(ins->storageType()) == 8) {
3837 temp64Def = tempInt64();
3840 auto* lir = new (alloc())
3841 LLoadDataViewElement(elements, index, littleEndian, tempDef, temp64Def);
3842 if (ins->fallible()) {
3843 assignSnapshot(lir, ins->bailoutKind());
3845 define(lir, ins);
3846 if (Scalar::isBigIntType(ins->storageType())) {
3847 assignSafepoint(lir, ins);
3851 void LIRGenerator::visitClampToUint8(MClampToUint8* ins) {
3852 MDefinition* in = ins->input();
3854 switch (in->type()) {
3855 case MIRType::Boolean:
3856 redefine(ins, in);
3857 break;
3859 case MIRType::Int32:
3860 defineReuseInput(new (alloc()) LClampIToUint8(useRegisterAtStart(in)),
3861 ins, 0);
3862 break;
3864 case MIRType::Double:
3865 // LClampDToUint8 clobbers its input register. Making it available as
3866 // a temp copy describes this behavior to the register allocator.
3867 define(new (alloc())
3868 LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)),
3869 ins);
3870 break;
3872 case MIRType::Value: {
3873 LClampVToUint8* lir =
3874 new (alloc()) LClampVToUint8(useBox(in), tempDouble());
3875 assignSnapshot(lir, ins->bailoutKind());
3876 define(lir, ins);
3877 assignSafepoint(lir, ins);
3878 break;
3881 default:
3882 MOZ_CRASH("unexpected type");
3886 void LIRGenerator::visitLoadTypedArrayElementHole(
3887 MLoadTypedArrayElementHole* ins) {
3888 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3889 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
3891 MOZ_ASSERT(ins->type() == MIRType::Value);
3893 const LUse object = useRegister(ins->object());
3894 const LAllocation index = useRegister(ins->index());
3896 if (!Scalar::isBigIntType(ins->arrayType())) {
3897 auto* lir = new (alloc()) LLoadTypedArrayElementHole(object, index, temp());
3898 if (ins->fallible()) {
3899 assignSnapshot(lir, ins->bailoutKind());
3901 defineBox(lir, ins);
3902 } else {
3903 #ifdef JS_CODEGEN_X86
3904 LDefinition tmp = LDefinition::BogusTemp();
3905 #else
3906 LDefinition tmp = temp();
3907 #endif
3909 auto* lir = new (alloc())
3910 LLoadTypedArrayElementHoleBigInt(object, index, tmp, tempInt64());
3911 defineBox(lir, ins);
3912 assignSafepoint(lir, ins);
3916 void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) {
3917 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3918 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
3920 if (ins->isFloatWrite()) {
3921 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
3922 ins->value()->type() == MIRType::Float32);
3923 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
3924 ins->value()->type() == MIRType::Double);
3925 } else if (ins->isBigIntWrite()) {
3926 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
3927 } else {
3928 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
3931 if (ins->isBigIntWrite() && ins->requiresMemoryBarrier()) {
3932 lowerAtomicStore64(ins);
3933 return;
3936 LUse elements = useRegister(ins->elements());
3937 LAllocation index =
3938 useRegisterOrIndexConstant(ins->index(), ins->writeType());
3939 LAllocation value;
3941 // For byte arrays, the value has to be in a byte register on x86.
3942 if (ins->isByteWrite()) {
3943 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
3944 } else if (ins->isBigIntWrite()) {
3945 value = useRegister(ins->value());
3946 } else {
3947 value = useRegisterOrNonDoubleConstant(ins->value());
3950 // Optimization opportunity for atomics: on some platforms there
3951 // is a store instruction that incorporates the necessary
3952 // barriers, and we could use that instead of separate barrier and
3953 // store instructions. See bug #1077027.
3954 Synchronization sync = Synchronization::Store();
3955 if (ins->requiresMemoryBarrier()) {
3956 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
3957 add(fence, ins);
3959 if (!ins->isBigIntWrite()) {
3960 add(new (alloc()) LStoreUnboxedScalar(elements, index, value), ins);
3961 } else {
3962 add(new (alloc()) LStoreUnboxedBigInt(elements, index, value, tempInt64()),
3963 ins);
3965 if (ins->requiresMemoryBarrier()) {
3966 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
3967 add(fence, ins);
3971 void LIRGenerator::visitStoreDataViewElement(MStoreDataViewElement* ins) {
3972 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3973 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
3974 MOZ_ASSERT(ins->littleEndian()->type() == MIRType::Boolean);
3976 if (ins->isFloatWrite()) {
3977 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
3978 ins->value()->type() == MIRType::Float32);
3979 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
3980 ins->value()->type() == MIRType::Double);
3981 } else if (ins->isBigIntWrite()) {
3982 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
3983 } else {
3984 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
3987 LUse elements = useRegister(ins->elements());
3988 LUse index = useRegister(ins->index());
3989 LAllocation value;
3990 if (ins->isBigIntWrite()) {
3991 value = useRegister(ins->value());
3992 } else {
3993 value = useRegisterOrNonDoubleConstant(ins->value());
3995 LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
3997 LDefinition tempDef = LDefinition::BogusTemp();
3998 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
3999 if (Scalar::byteSize(ins->writeType()) < 8) {
4000 tempDef = temp();
4001 } else {
4002 temp64Def = tempInt64();
4005 add(new (alloc()) LStoreDataViewElement(elements, index, value, littleEndian,
4006 tempDef, temp64Def),
4007 ins);
4010 void LIRGenerator::visitStoreTypedArrayElementHole(
4011 MStoreTypedArrayElementHole* ins) {
4012 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4013 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4014 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr);
4016 if (ins->isFloatWrite()) {
4017 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32,
4018 ins->value()->type() == MIRType::Float32);
4019 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64,
4020 ins->value()->type() == MIRType::Double);
4021 } else if (ins->isBigIntWrite()) {
4022 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4023 } else {
4024 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4027 LUse elements = useRegister(ins->elements());
4028 LAllocation length = useAny(ins->length());
4029 LAllocation index = useRegister(ins->index());
4031 // For byte arrays, the value has to be in a byte register on x86.
4032 LAllocation value;
4033 if (ins->isByteWrite()) {
4034 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4035 } else if (ins->isBigIntWrite()) {
4036 value = useRegister(ins->value());
4037 } else {
4038 value = useRegisterOrNonDoubleConstant(ins->value());
4041 if (!ins->isBigIntWrite()) {
4042 LDefinition spectreTemp =
4043 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4044 auto* lir = new (alloc()) LStoreTypedArrayElementHole(
4045 elements, length, index, value, spectreTemp);
4046 add(lir, ins);
4047 } else {
4048 auto* lir = new (alloc()) LStoreTypedArrayElementHoleBigInt(
4049 elements, length, index, value, tempInt64());
4050 add(lir, ins);
4054 void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) {
4055 MDefinition* obj = ins->object();
4056 MOZ_ASSERT(obj->type() == MIRType::Object);
4058 MIRType type = ins->type();
4060 if (type == MIRType::Value) {
4061 LLoadFixedSlotV* lir =
4062 new (alloc()) LLoadFixedSlotV(useRegisterAtStart(obj));
4063 defineBox(lir, ins);
4064 } else {
4065 LLoadFixedSlotT* lir =
4066 new (alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type));
4067 define(lir, ins);
4071 void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) {
4072 MDefinition* obj = ins->object();
4073 MOZ_ASSERT(obj->type() == MIRType::Object);
4075 LLoadFixedSlotAndUnbox* lir =
4076 new (alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj));
4077 if (ins->fallible()) {
4078 assignSnapshot(lir, ins->bailoutKind());
4080 define(lir, ins);
4083 void LIRGenerator::visitLoadDynamicSlotAndUnbox(MLoadDynamicSlotAndUnbox* ins) {
4084 MDefinition* slots = ins->slots();
4085 MOZ_ASSERT(slots->type() == MIRType::Slots);
4087 auto* lir = new (alloc()) LLoadDynamicSlotAndUnbox(useRegisterAtStart(slots));
4088 if (ins->fallible()) {
4089 assignSnapshot(lir, ins->bailoutKind());
4091 define(lir, ins);
4094 void LIRGenerator::visitLoadElementAndUnbox(MLoadElementAndUnbox* ins) {
4095 MDefinition* elements = ins->elements();
4096 MDefinition* index = ins->index();
4097 MOZ_ASSERT(elements->type() == MIRType::Elements);
4098 MOZ_ASSERT(index->type() == MIRType::Int32);
4100 auto* lir = new (alloc())
4101 LLoadElementAndUnbox(useRegister(elements), useRegisterOrConstant(index));
4102 if (ins->fallible()) {
4103 assignSnapshot(lir, ins->bailoutKind());
4105 define(lir, ins);
4108 void LIRGenerator::visitAddAndStoreSlot(MAddAndStoreSlot* ins) {
4109 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4111 LDefinition maybeTemp = LDefinition::BogusTemp();
4112 if (ins->kind() != MAddAndStoreSlot::Kind::FixedSlot) {
4113 maybeTemp = temp();
4116 auto* lir = new (alloc()) LAddAndStoreSlot(useRegister(ins->object()),
4117 useBox(ins->value()), maybeTemp);
4118 add(lir, ins);
4121 void LIRGenerator::visitAllocateAndStoreSlot(MAllocateAndStoreSlot* ins) {
4122 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4124 auto* lir = new (alloc()) LAllocateAndStoreSlot(
4125 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()),
4126 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4127 assignSnapshot(lir, ins->bailoutKind());
4128 add(lir, ins);
4131 void LIRGenerator::visitAddSlotAndCallAddPropHook(
4132 MAddSlotAndCallAddPropHook* ins) {
4133 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4134 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4136 auto* lir = new (alloc()) LAddSlotAndCallAddPropHook(
4137 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
4138 add(lir, ins);
4139 assignSafepoint(lir, ins);
4142 void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) {
4143 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4145 if (ins->value()->type() == MIRType::Value) {
4146 LStoreFixedSlotV* lir = new (alloc())
4147 LStoreFixedSlotV(useRegister(ins->object()), useBox(ins->value()));
4148 add(lir, ins);
4149 } else {
4150 LStoreFixedSlotT* lir = new (alloc()) LStoreFixedSlotT(
4151 useRegister(ins->object()), useRegisterOrConstant(ins->value()));
4152 add(lir, ins);
4156 void LIRGenerator::visitGetNameCache(MGetNameCache* ins) {
4157 MOZ_ASSERT(ins->envObj()->type() == MIRType::Object);
4159 // Emit an overrecursed check: this is necessary because the cache can
4160 // attach a scripted getter stub that calls this script recursively.
4161 gen->setNeedsOverrecursedCheck();
4163 LGetNameCache* lir =
4164 new (alloc()) LGetNameCache(useRegister(ins->envObj()), temp());
4165 defineBox(lir, ins);
4166 assignSafepoint(lir, ins);
4169 void LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) {
4170 LCallGetIntrinsicValue* lir = new (alloc()) LCallGetIntrinsicValue();
4171 defineReturn(lir, ins);
4172 assignSafepoint(lir, ins);
4175 void LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache* ins) {
4176 MDefinition* obj = ins->object();
4177 MDefinition* receiver = ins->receiver();
4178 MDefinition* id = ins->idval();
4180 gen->setNeedsOverrecursedCheck();
4182 bool useConstId =
4183 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4185 auto* lir = new (alloc())
4186 LGetPropSuperCache(useRegister(obj), useBoxOrTyped(receiver),
4187 useBoxOrTypedOrConstant(id, useConstId));
4188 defineBox(lir, ins);
4189 assignSafepoint(lir, ins);
4192 void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) {
4193 MDefinition* value = ins->value();
4194 MOZ_ASSERT(value->type() == MIRType::Object ||
4195 value->type() == MIRType::Value);
4197 MDefinition* id = ins->idval();
4198 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4199 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4201 // Emit an overrecursed check: this is necessary because the cache can
4202 // attach a scripted getter stub that calls this script recursively.
4203 gen->setNeedsOverrecursedCheck();
4205 // If this is a GetProp, the id is a constant string. Allow passing it as a
4206 // constant to reduce register allocation pressure.
4207 bool useConstId =
4208 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4210 auto* lir = new (alloc()) LGetPropertyCache(
4211 useBoxOrTyped(value), useBoxOrTypedOrConstant(id, useConstId));
4212 defineBox(lir, ins);
4213 assignSafepoint(lir, ins);
4216 void LIRGenerator::visitBindNameCache(MBindNameCache* ins) {
4217 MOZ_ASSERT(ins->envChain()->type() == MIRType::Object);
4218 MOZ_ASSERT(ins->type() == MIRType::Object);
4220 LBindNameCache* lir =
4221 new (alloc()) LBindNameCache(useRegister(ins->envChain()), temp());
4222 define(lir, ins);
4223 assignSafepoint(lir, ins);
4226 void LIRGenerator::visitCallBindVar(MCallBindVar* ins) {
4227 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
4228 MOZ_ASSERT(ins->type() == MIRType::Object);
4230 LCallBindVar* lir =
4231 new (alloc()) LCallBindVar(useRegister(ins->environmentChain()));
4232 define(lir, ins);
4235 void LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins) {
4236 LGuardObjectIdentity* guard = new (alloc()) LGuardObjectIdentity(
4237 useRegister(ins->object()), useRegister(ins->expected()));
4238 assignSnapshot(guard, ins->bailoutKind());
4239 add(guard, ins);
4240 redefine(ins, ins->object());
4243 void LIRGenerator::visitGuardSpecificFunction(MGuardSpecificFunction* ins) {
4244 auto* guard = new (alloc()) LGuardSpecificFunction(
4245 useRegister(ins->function()), useRegister(ins->expected()));
4246 assignSnapshot(guard, ins->bailoutKind());
4247 add(guard, ins);
4248 redefine(ins, ins->function());
4251 void LIRGenerator::visitGuardSpecificAtom(MGuardSpecificAtom* ins) {
4252 auto* guard =
4253 new (alloc()) LGuardSpecificAtom(useRegister(ins->str()), temp());
4254 assignSnapshot(guard, ins->bailoutKind());
4255 add(guard, ins);
4256 redefine(ins, ins->str());
4257 assignSafepoint(guard, ins);
4260 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol* ins) {
4261 auto* guard = new (alloc()) LGuardSpecificSymbol(useRegister(ins->symbol()));
4262 assignSnapshot(guard, ins->bailoutKind());
4263 add(guard, ins);
4264 redefine(ins, ins->symbol());
4267 void LIRGenerator::visitGuardStringToIndex(MGuardStringToIndex* ins) {
4268 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4269 auto* guard = new (alloc()) LGuardStringToIndex(useRegister(ins->string()));
4270 assignSnapshot(guard, ins->bailoutKind());
4271 define(guard, ins);
4272 assignSafepoint(guard, ins);
4275 void LIRGenerator::visitGuardStringToInt32(MGuardStringToInt32* ins) {
4276 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4277 auto* guard =
4278 new (alloc()) LGuardStringToInt32(useRegister(ins->string()), temp());
4279 assignSnapshot(guard, ins->bailoutKind());
4280 define(guard, ins);
4281 assignSafepoint(guard, ins);
4284 void LIRGenerator::visitGuardStringToDouble(MGuardStringToDouble* ins) {
4285 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4286 auto* guard = new (alloc())
4287 LGuardStringToDouble(useRegister(ins->string()), temp(), temp());
4288 assignSnapshot(guard, ins->bailoutKind());
4289 define(guard, ins);
4290 assignSafepoint(guard, ins);
4293 void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements* ins) {
4294 auto* guard =
4295 new (alloc()) LGuardNoDenseElements(useRegister(ins->object()), temp());
4296 assignSnapshot(guard, ins->bailoutKind());
4297 add(guard, ins);
4298 redefine(ins, ins->object());
4301 void LIRGenerator::visitGuardShape(MGuardShape* ins) {
4302 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4304 if (JitOptions.spectreObjectMitigations) {
4305 auto* lir =
4306 new (alloc()) LGuardShape(useRegisterAtStart(ins->object()), temp());
4307 assignSnapshot(lir, ins->bailoutKind());
4308 defineReuseInput(lir, ins, 0);
4309 } else {
4310 auto* lir = new (alloc())
4311 LGuardShape(useRegister(ins->object()), LDefinition::BogusTemp());
4312 assignSnapshot(lir, ins->bailoutKind());
4313 add(lir, ins);
4314 redefine(ins, ins->object());
4318 void LIRGenerator::visitGuardProto(MGuardProto* ins) {
4319 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4320 MOZ_ASSERT(ins->expected()->type() == MIRType::Object);
4322 auto* lir = new (alloc()) LGuardProto(useRegister(ins->object()),
4323 useRegister(ins->expected()), temp());
4324 assignSnapshot(lir, ins->bailoutKind());
4325 add(lir, ins);
4326 redefine(ins, ins->object());
4329 void LIRGenerator::visitGuardNullProto(MGuardNullProto* ins) {
4330 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4332 auto* lir = new (alloc()) LGuardNullProto(useRegister(ins->object()), temp());
4333 assignSnapshot(lir, ins->bailoutKind());
4334 add(lir, ins);
4335 redefine(ins, ins->object());
4338 void LIRGenerator::visitGuardIsNativeObject(MGuardIsNativeObject* ins) {
4339 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4341 auto* lir =
4342 new (alloc()) LGuardIsNativeObject(useRegister(ins->object()), temp());
4343 assignSnapshot(lir, ins->bailoutKind());
4344 add(lir, ins);
4345 redefine(ins, ins->object());
4348 void LIRGenerator::visitGuardIsProxy(MGuardIsProxy* ins) {
4349 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4351 auto* lir = new (alloc()) LGuardIsProxy(useRegister(ins->object()), temp());
4352 assignSnapshot(lir, ins->bailoutKind());
4353 add(lir, ins);
4354 redefine(ins, ins->object());
4357 void LIRGenerator::visitGuardIsNotProxy(MGuardIsNotProxy* ins) {
4358 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4360 auto* lir =
4361 new (alloc()) LGuardIsNotProxy(useRegister(ins->object()), temp());
4362 assignSnapshot(lir, ins->bailoutKind());
4363 add(lir, ins);
4364 redefine(ins, ins->object());
4367 void LIRGenerator::visitGuardIsNotDOMProxy(MGuardIsNotDOMProxy* ins) {
4368 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
4370 auto* lir =
4371 new (alloc()) LGuardIsNotDOMProxy(useRegister(ins->proxy()), temp());
4372 assignSnapshot(lir, ins->bailoutKind());
4373 add(lir, ins);
4374 redefine(ins, ins->proxy());
4377 void LIRGenerator::visitProxyGet(MProxyGet* ins) {
4378 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
4379 auto* lir = new (alloc())
4380 LProxyGet(useRegisterAtStart(ins->proxy()), tempFixed(CallTempReg0));
4381 defineReturn(lir, ins);
4382 assignSafepoint(lir, ins);
4385 void LIRGenerator::visitProxyGetByValue(MProxyGetByValue* ins) {
4386 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
4387 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
4388 auto* lir = new (alloc()) LProxyGetByValue(useRegisterAtStart(ins->proxy()),
4389 useBoxAtStart(ins->idVal()));
4390 defineReturn(lir, ins);
4391 assignSafepoint(lir, ins);
4394 void LIRGenerator::visitProxyHasProp(MProxyHasProp* ins) {
4395 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
4396 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
4397 auto* lir = new (alloc()) LProxyHasProp(useRegisterAtStart(ins->proxy()),
4398 useBoxAtStart(ins->idVal()));
4399 defineReturn(lir, ins);
4400 assignSafepoint(lir, ins);
4403 void LIRGenerator::visitProxySet(MProxySet* ins) {
4404 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
4405 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
4406 auto* lir = new (alloc())
4407 LProxySet(useRegisterAtStart(ins->proxy()), useBoxAtStart(ins->rhs()),
4408 tempFixed(CallTempReg0));
4409 add(lir, ins);
4410 assignSafepoint(lir, ins);
4413 void LIRGenerator::visitProxySetByValue(MProxySetByValue* ins) {
4414 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
4415 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
4416 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
4417 auto* lir = new (alloc())
4418 LProxySetByValue(useRegisterAtStart(ins->proxy()),
4419 useBoxAtStart(ins->idVal()), useBoxAtStart(ins->rhs()));
4420 add(lir, ins);
4421 assignSafepoint(lir, ins);
4424 void LIRGenerator::visitCallSetArrayLength(MCallSetArrayLength* ins) {
4425 MOZ_ASSERT(ins->obj()->type() == MIRType::Object);
4426 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
4427 auto* lir = new (alloc()) LCallSetArrayLength(useRegisterAtStart(ins->obj()),
4428 useBoxAtStart(ins->rhs()));
4429 add(lir, ins);
4430 assignSafepoint(lir, ins);
4433 void LIRGenerator::visitMegamorphicLoadSlot(MMegamorphicLoadSlot* ins) {
4434 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4435 auto* lir = new (alloc()) LMegamorphicLoadSlot(
4436 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0),
4437 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
4438 assignSnapshot(lir, ins->bailoutKind());
4439 defineReturn(lir, ins);
4442 void LIRGenerator::visitMegamorphicLoadSlotByValue(
4443 MMegamorphicLoadSlotByValue* ins) {
4444 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4445 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
4446 auto* lir = new (alloc()) LMegamorphicLoadSlotByValue(
4447 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()),
4448 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4449 assignSnapshot(lir, ins->bailoutKind());
4450 defineReturn(lir, ins);
4453 void LIRGenerator::visitMegamorphicStoreSlot(MMegamorphicStoreSlot* ins) {
4454 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4455 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
4456 auto* lir = new (alloc())
4457 LMegamorphicStoreSlot(useRegisterAtStart(ins->object()),
4458 useBoxAtStart(ins->rhs()), tempFixed(CallTempReg0),
4459 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
4460 assignSnapshot(lir, ins->bailoutKind());
4461 add(lir, ins);
4464 void LIRGenerator::visitMegamorphicHasProp(MMegamorphicHasProp* ins) {
4465 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4466 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
4467 auto* lir = new (alloc()) LMegamorphicHasProp(
4468 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()),
4469 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4470 assignSnapshot(lir, ins->bailoutKind());
4471 defineReturn(lir, ins);
4474 void LIRGenerator::visitGuardIsNotArrayBufferMaybeShared(
4475 MGuardIsNotArrayBufferMaybeShared* ins) {
4476 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4478 auto* lir = new (alloc())
4479 LGuardIsNotArrayBufferMaybeShared(useRegister(ins->object()), temp());
4480 assignSnapshot(lir, ins->bailoutKind());
4481 add(lir, ins);
4482 redefine(ins, ins->object());
4485 void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray* ins) {
4486 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4488 auto* lir =
4489 new (alloc()) LGuardIsTypedArray(useRegister(ins->object()), temp());
4490 assignSnapshot(lir, ins->bailoutKind());
4491 add(lir, ins);
4492 redefine(ins, ins->object());
4495 void LIRGenerator::visitNurseryObject(MNurseryObject* ins) {
4496 MOZ_ASSERT(ins->type() == MIRType::Object);
4498 auto* lir = new (alloc()) LNurseryObject();
4499 define(lir, ins);
4502 void LIRGenerator::visitGuardValue(MGuardValue* ins) {
4503 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4504 auto* lir = new (alloc()) LGuardValue(useBox(ins->value()));
4505 assignSnapshot(lir, ins->bailoutKind());
4506 add(lir, ins);
4507 redefine(ins, ins->value());
4510 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined* ins) {
4511 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4512 auto* lir = new (alloc()) LGuardNullOrUndefined(useBox(ins->value()));
4513 assignSnapshot(lir, ins->bailoutKind());
4514 add(lir, ins);
4515 redefine(ins, ins->value());
4518 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject* ins) {
4519 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4520 auto* lir = new (alloc()) LGuardIsNotObject(useBox(ins->value()));
4521 assignSnapshot(lir, ins->bailoutKind());
4522 add(lir, ins);
4523 redefine(ins, ins->value());
4526 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags* ins) {
4527 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
4529 auto* lir = new (alloc()) LGuardFunctionFlags(useRegister(ins->function()));
4530 assignSnapshot(lir, ins->bailoutKind());
4531 add(lir, ins);
4532 redefine(ins, ins->function());
4535 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor(
4536 MGuardFunctionIsNonBuiltinCtor* ins) {
4537 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
4539 auto* lir = new (alloc())
4540 LGuardFunctionIsNonBuiltinCtor(useRegister(ins->function()), temp());
4541 assignSnapshot(lir, ins->bailoutKind());
4542 add(lir, ins);
4543 redefine(ins, ins->function());
4546 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind* ins) {
4547 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
4549 auto* lir =
4550 new (alloc()) LGuardFunctionKind(useRegister(ins->function()), temp());
4551 assignSnapshot(lir, ins->bailoutKind());
4552 add(lir, ins);
4553 redefine(ins, ins->function());
4556 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript* ins) {
4557 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
4559 auto* lir = new (alloc()) LGuardFunctionScript(useRegister(ins->function()));
4560 assignSnapshot(lir, ins->bailoutKind());
4561 add(lir, ins);
4562 redefine(ins, ins->function());
4565 void LIRGenerator::visitAssertRange(MAssertRange* ins) {
4566 MDefinition* input = ins->input();
4567 LInstruction* lir = nullptr;
4569 switch (input->type()) {
4570 case MIRType::Boolean:
4571 case MIRType::Int32:
4572 case MIRType::IntPtr:
4573 lir = new (alloc()) LAssertRangeI(useRegisterAtStart(input));
4574 break;
4576 case MIRType::Double:
4577 lir = new (alloc()) LAssertRangeD(useRegister(input), tempDouble());
4578 break;
4580 case MIRType::Float32:
4581 lir = new (alloc())
4582 LAssertRangeF(useRegister(input), tempDouble(), tempDouble());
4583 break;
4585 case MIRType::Value:
4586 lir = new (alloc()) LAssertRangeV(useBox(input), tempToUnbox(),
4587 tempDouble(), tempDouble());
4588 break;
4590 default:
4591 MOZ_CRASH("Unexpected Range for MIRType");
4592 break;
4595 lir->setMir(ins);
4596 add(lir);
4599 void LIRGenerator::visitAssertClass(MAssertClass* ins) {
4600 auto* lir =
4601 new (alloc()) LAssertClass(useRegisterAtStart(ins->input()), temp());
4602 add(lir, ins);
4605 void LIRGenerator::visitAssertShape(MAssertShape* ins) {
4606 auto* lir = new (alloc()) LAssertShape(useRegisterAtStart(ins->input()));
4607 add(lir, ins);
4610 void LIRGenerator::visitDeleteProperty(MDeleteProperty* ins) {
4611 LCallDeleteProperty* lir =
4612 new (alloc()) LCallDeleteProperty(useBoxAtStart(ins->value()));
4613 defineReturn(lir, ins);
4614 assignSafepoint(lir, ins);
4617 void LIRGenerator::visitDeleteElement(MDeleteElement* ins) {
4618 LCallDeleteElement* lir = new (alloc()) LCallDeleteElement(
4619 useBoxAtStart(ins->value()), useBoxAtStart(ins->index()));
4620 defineReturn(lir, ins);
4621 assignSafepoint(lir, ins);
4624 void LIRGenerator::visitValueToIterator(MValueToIterator* ins) {
4625 auto* lir = new (alloc()) LValueToIterator(useBoxAtStart(ins->value()));
4626 defineReturn(lir, ins);
4627 assignSafepoint(lir, ins);
4630 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) {
4631 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4633 MDefinition* id = ins->idval();
4634 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4635 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4637 // If this is a SetProp, the id is a constant string. Allow passing it as a
4638 // constant to reduce register allocation pressure.
4639 bool useConstId =
4640 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4641 bool useConstValue = IsNonNurseryConstant(ins->value());
4643 // Emit an overrecursed check: this is necessary because the cache can
4644 // attach a scripted setter stub that calls this script recursively.
4645 gen->setNeedsOverrecursedCheck();
4647 // We need a double temp register for TypedArray or TypedObject stubs.
4648 LDefinition tempD = tempFixed(FloatReg0);
4650 LInstruction* lir = new (alloc()) LSetPropertyCache(
4651 useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId),
4652 useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD);
4653 add(lir, ins);
4654 assignSafepoint(lir, ins);
4657 void LIRGenerator::visitCallSetElement(MCallSetElement* ins) {
4658 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4659 MOZ_ASSERT(ins->index()->type() == MIRType::Value);
4660 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4662 LCallSetElement* lir = new (alloc())
4663 LCallSetElement(useRegisterAtStart(ins->object()),
4664 useBoxAtStart(ins->index()), useBoxAtStart(ins->value()));
4665 add(lir, ins);
4666 assignSafepoint(lir, ins);
4669 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache* ins) {
4670 MDefinition* value = ins->value();
4671 MOZ_ASSERT(value->type() == MIRType::Object ||
4672 value->type() == MIRType::Value);
4674 LGetIteratorCache* lir =
4675 new (alloc()) LGetIteratorCache(useBoxOrTyped(value), temp(), temp());
4676 define(lir, ins);
4677 assignSafepoint(lir, ins);
4680 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache* ins) {
4681 MDefinition* value = ins->value();
4682 MOZ_ASSERT(value->type() == MIRType::Value);
4684 auto* lir = new (alloc()) LOptimizeSpreadCallCache(useBox(value), temp());
4685 defineBox(lir, ins);
4686 assignSafepoint(lir, ins);
4689 void LIRGenerator::visitIteratorMore(MIteratorMore* ins) {
4690 LIteratorMore* lir =
4691 new (alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
4692 defineBox(lir, ins);
4695 void LIRGenerator::visitIsNoIter(MIsNoIter* ins) {
4696 MOZ_ASSERT(ins->hasOneUse());
4697 emitAtUses(ins);
4700 void LIRGenerator::visitIteratorEnd(MIteratorEnd* ins) {
4701 LIteratorEnd* lir = new (alloc())
4702 LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
4703 add(lir, ins);
4706 void LIRGenerator::visitStringLength(MStringLength* ins) {
4707 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4708 define(new (alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
4711 void LIRGenerator::visitArgumentsLength(MArgumentsLength* ins) {
4712 define(new (alloc()) LArgumentsLength(), ins);
4715 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument* ins) {
4716 LGetFrameArgument* lir =
4717 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
4718 defineBox(lir, ins);
4721 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole* ins) {
4722 LDefinition spectreTemp =
4723 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4725 auto* lir = new (alloc()) LGetFrameArgumentHole(
4726 useRegister(ins->index()), useRegister(ins->length()), spectreTemp);
4727 assignSnapshot(lir, ins->bailoutKind());
4728 defineBox(lir, ins);
4731 void LIRGenerator::visitNewTarget(MNewTarget* ins) {
4732 LNewTarget* lir = new (alloc()) LNewTarget();
4733 defineBox(lir, ins);
4736 void LIRGenerator::visitRest(MRest* ins) {
4737 MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32);
4739 LRest* lir = new (alloc())
4740 LRest(useRegisterAtStart(ins->numActuals()), tempFixed(CallTempReg0),
4741 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
4742 defineReturn(lir, ins);
4743 assignSafepoint(lir, ins);
4746 void LIRGenerator::visitThrow(MThrow* ins) {
4747 MDefinition* value = ins->getOperand(0);
4748 MOZ_ASSERT(value->type() == MIRType::Value);
4750 LThrow* lir = new (alloc()) LThrow(useBoxAtStart(value));
4751 add(lir, ins);
4752 assignSafepoint(lir, ins);
4755 void LIRGenerator::visitInCache(MInCache* ins) {
4756 MDefinition* lhs = ins->lhs();
4757 MDefinition* rhs = ins->rhs();
4759 MOZ_ASSERT(lhs->type() == MIRType::String || lhs->type() == MIRType::Symbol ||
4760 lhs->type() == MIRType::Int32 || lhs->type() == MIRType::Value);
4761 MOZ_ASSERT(rhs->type() == MIRType::Object);
4763 LInCache* lir =
4764 new (alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp());
4765 define(lir, ins);
4766 assignSafepoint(lir, ins);
4769 void LIRGenerator::visitHasOwnCache(MHasOwnCache* ins) {
4770 MDefinition* value = ins->value();
4771 MOZ_ASSERT(value->type() == MIRType::Object ||
4772 value->type() == MIRType::Value);
4774 MDefinition* id = ins->idval();
4775 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4776 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4778 // Emit an overrecursed check: this is necessary because the cache can
4779 // attach a scripted getter stub that calls this script recursively.
4780 gen->setNeedsOverrecursedCheck();
4782 LHasOwnCache* lir =
4783 new (alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id));
4784 define(lir, ins);
4785 assignSafepoint(lir, ins);
4788 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache* ins) {
4789 MDefinition* value = ins->value();
4790 MOZ_ASSERT(value->type() == MIRType::Object ||
4791 value->type() == MIRType::Value);
4793 MDefinition* id = ins->idval();
4794 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4795 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4797 LCheckPrivateFieldCache* lir = new (alloc())
4798 LCheckPrivateFieldCache(useBoxOrTyped(value), useBoxOrTyped(id));
4799 define(lir, ins);
4800 assignSafepoint(lir, ins);
4803 void LIRGenerator::visitNewPrivateName(MNewPrivateName* ins) {
4804 auto* lir = new (alloc()) LNewPrivateName();
4805 defineReturn(lir, ins);
4806 assignSafepoint(lir, ins);
4809 void LIRGenerator::visitInstanceOf(MInstanceOf* ins) {
4810 MDefinition* lhs = ins->lhs();
4811 MDefinition* rhs = ins->rhs();
4813 MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object);
4814 MOZ_ASSERT(rhs->type() == MIRType::Object);
4816 if (lhs->type() == MIRType::Object) {
4817 auto* lir = new (alloc())
4818 LInstanceOfO(useRegister(lhs), useRegisterOrConstant(rhs));
4819 define(lir, ins);
4820 assignSafepoint(lir, ins);
4821 } else {
4822 auto* lir =
4823 new (alloc()) LInstanceOfV(useBox(lhs), useRegisterOrConstant(rhs));
4824 define(lir, ins);
4825 assignSafepoint(lir, ins);
4829 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins) {
4830 MDefinition* lhs = ins->lhs();
4831 MDefinition* rhs = ins->rhs();
4833 MOZ_ASSERT(lhs->type() == MIRType::Value);
4834 MOZ_ASSERT(rhs->type() == MIRType::Object);
4836 LInstanceOfCache* lir =
4837 new (alloc()) LInstanceOfCache(useBox(lhs), useRegister(rhs));
4838 define(lir, ins);
4839 assignSafepoint(lir, ins);
4842 void LIRGenerator::visitIsArray(MIsArray* ins) {
4843 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4845 if (ins->value()->type() == MIRType::Object) {
4846 LIsArrayO* lir = new (alloc()) LIsArrayO(useRegister(ins->value()));
4847 define(lir, ins);
4848 assignSafepoint(lir, ins);
4849 } else {
4850 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4851 LIsArrayV* lir = new (alloc()) LIsArrayV(useBox(ins->value()), temp());
4852 define(lir, ins);
4853 assignSafepoint(lir, ins);
4857 void LIRGenerator::visitIsTypedArray(MIsTypedArray* ins) {
4858 MOZ_ASSERT(ins->value()->type() == MIRType::Object);
4859 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4861 auto* lir = new (alloc()) LIsTypedArray(useRegister(ins->value()));
4862 define(lir, ins);
4864 if (ins->isPossiblyWrapped()) {
4865 assignSafepoint(lir, ins);
4869 void LIRGenerator::visitIsCallable(MIsCallable* ins) {
4870 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4872 if (ins->object()->type() == MIRType::Object) {
4873 define(new (alloc()) LIsCallableO(useRegister(ins->object())), ins);
4874 } else {
4875 MOZ_ASSERT(ins->object()->type() == MIRType::Value);
4876 define(new (alloc()) LIsCallableV(useBox(ins->object()), temp()), ins);
4880 void LIRGenerator::visitIsConstructor(MIsConstructor* ins) {
4881 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4882 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4883 define(new (alloc()) LIsConstructor(useRegister(ins->object())), ins);
4886 void LIRGenerator::visitIsCrossRealmArrayConstructor(
4887 MIsCrossRealmArrayConstructor* ins) {
4888 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4889 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4890 define(new (alloc())
4891 LIsCrossRealmArrayConstructor(useRegister(ins->object())),
4892 ins);
4895 static bool CanEmitIsObjectOrIsNullOrUndefinedAtUses(MInstruction* ins) {
4896 if (!ins->canEmitAtUses()) {
4897 return false;
4900 MUseIterator iter(ins->usesBegin());
4901 if (iter == ins->usesEnd()) {
4902 return false;
4905 MNode* node = iter->consumer();
4906 if (!node->isDefinition()) {
4907 return false;
4910 if (!node->toDefinition()->isTest()) {
4911 return false;
4914 iter++;
4915 return iter == ins->usesEnd();
4918 void LIRGenerator::visitIsObject(MIsObject* ins) {
4919 if (CanEmitIsObjectOrIsNullOrUndefinedAtUses(ins)) {
4920 emitAtUses(ins);
4921 return;
4924 MDefinition* opd = ins->input();
4925 MOZ_ASSERT(opd->type() == MIRType::Value);
4926 LIsObject* lir = new (alloc()) LIsObject(useBoxAtStart(opd));
4927 define(lir, ins);
4930 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined* ins) {
4931 if (CanEmitIsObjectOrIsNullOrUndefinedAtUses(ins)) {
4932 emitAtUses(ins);
4933 return;
4936 MDefinition* opd = ins->input();
4937 MOZ_ASSERT(opd->type() == MIRType::Value);
4938 LIsNullOrUndefined* lir =
4939 new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd));
4940 define(lir, ins);
4943 void LIRGenerator::visitHasClass(MHasClass* ins) {
4944 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4945 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4946 define(new (alloc()) LHasClass(useRegister(ins->object())), ins);
4949 void LIRGenerator::visitGuardToClass(MGuardToClass* ins) {
4950 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4951 MOZ_ASSERT(ins->type() == MIRType::Object);
4952 LGuardToClass* lir =
4953 new (alloc()) LGuardToClass(useRegisterAtStart(ins->object()), temp());
4954 assignSnapshot(lir, ins->bailoutKind());
4955 defineReuseInput(lir, ins, 0);
4958 void LIRGenerator::visitGuardToFunction(MGuardToFunction* ins) {
4959 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4960 MOZ_ASSERT(ins->type() == MIRType::Object);
4961 LGuardToFunction* lir =
4962 new (alloc()) LGuardToFunction(useRegisterAtStart(ins->object()), temp());
4963 assignSnapshot(lir, ins->bailoutKind());
4964 defineReuseInput(lir, ins, 0);
4967 void LIRGenerator::visitObjectClassToString(MObjectClassToString* ins) {
4968 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4969 MOZ_ASSERT(ins->type() == MIRType::String);
4970 auto* lir = new (alloc()) LObjectClassToString(
4971 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0));
4972 assignSnapshot(lir, ins->bailoutKind());
4973 defineReturn(lir, ins);
4976 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) {
4977 MOZ_ASSERT(ins->offset());
4978 if (ins->base()->type() == MIRType::Int32) {
4979 MOZ_ASSERT(ins->type() == MIRType::Int32);
4980 MOZ_ASSERT(ins->offset() <= UINT32_MAX); // Because memory32
4981 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins);
4982 } else {
4983 MOZ_ASSERT(ins->type() == MIRType::Int64);
4984 #ifdef JS_64BIT
4985 defineInt64(new (alloc())
4986 LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
4987 ins);
4988 #else
4989 // Avoid situation where the input is (a,b) and the output is (b,a).
4990 defineInt64ReuseInput(
4991 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
4992 ins, 0);
4993 #endif
4997 void LIRGenerator::visitWasmLoadTls(MWasmLoadTls* ins) {
4998 if (ins->type() == MIRType::Int64) {
4999 #ifdef JS_PUNBOX64
5000 LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
5001 #else
5002 // Avoid reusing tlsPtr for a 64-bit output pair as the load clobbers the
5003 // first half of that pair before loading the second half.
5004 LAllocation tlsPtr = useRegister(ins->tlsPtr());
5005 #endif
5006 auto* lir = new (alloc()) LWasmLoadTls64(tlsPtr);
5007 defineInt64(lir, ins);
5008 } else {
5009 auto* lir = new (alloc()) LWasmLoadTls(useRegisterAtStart(ins->tlsPtr()));
5010 define(lir, ins);
5014 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) {
5015 MOZ_ASSERT(!ins->isRedundant());
5017 MDefinition* index = ins->index();
5018 MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
5020 MOZ_ASSERT(boundsCheckLimit->type() == index->type());
5022 if (index->type() == MIRType::Int64) {
5023 if (JitOptions.spectreIndexMasking) {
5024 auto* lir = new (alloc()) LWasmBoundsCheck64(
5025 useInt64RegisterAtStart(index), useInt64Register(boundsCheckLimit));
5026 defineInt64ReuseInput(lir, ins, 0);
5027 } else {
5028 auto* lir = new (alloc())
5029 LWasmBoundsCheck64(useInt64RegisterAtStart(index),
5030 useInt64RegisterAtStart(boundsCheckLimit));
5031 add(lir, ins);
5033 } else {
5034 MOZ_ASSERT(index->type() == MIRType::Int32);
5036 if (JitOptions.spectreIndexMasking) {
5037 auto* lir = new (alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
5038 useRegister(boundsCheckLimit));
5039 defineReuseInput(lir, ins, 0);
5040 } else {
5041 auto* lir = new (alloc()) LWasmBoundsCheck(
5042 useRegisterAtStart(index), useRegisterAtStart(boundsCheckLimit));
5043 add(lir, ins);
5048 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) {
5049 MDefinition* index = ins->index();
5050 if (index->type() == MIRType::Int64) {
5051 auto* lir =
5052 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index));
5053 add(lir, ins);
5054 } else {
5055 auto* lir = new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index));
5056 add(lir, ins);
5060 void LIRGenerator::visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins) {
5061 size_t offs = offsetof(wasm::TlsData, globalArea) + ins->globalDataOffset();
5062 if (ins->type() == MIRType::Int64) {
5063 #ifdef JS_PUNBOX64
5064 LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
5065 #else
5066 // Avoid reusing tlsPtr for the output pair as the load clobbers the first
5067 // half of that pair before loading the second half.
5068 LAllocation tlsPtr = useRegister(ins->tlsPtr());
5069 #endif
5070 defineInt64(new (alloc()) LWasmLoadSlotI64(tlsPtr, offs), ins);
5071 } else {
5072 LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
5073 define(new (alloc()) LWasmLoadSlot(tlsPtr, offs, ins->type()), ins);
5077 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell* ins) {
5078 if (ins->type() == MIRType::Int64) {
5079 #ifdef JS_PUNBOX64
5080 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5081 #else
5082 // Avoid reusing cellPtr for the output pair as the load clobbers the first
5083 // half of that pair before loading the second half.
5084 LAllocation cellPtr = useRegister(ins->cellPtr());
5085 #endif
5086 defineInt64(new (alloc()) LWasmLoadSlotI64(cellPtr, /*offs=*/0), ins);
5087 } else {
5088 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5089 define(new (alloc()) LWasmLoadSlot(cellPtr, /*offs=*/0, ins->type()), ins);
5093 void LIRGenerator::visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins) {
5094 MDefinition* value = ins->value();
5095 size_t offs = offsetof(wasm::TlsData, globalArea) + ins->globalDataOffset();
5096 if (value->type() == MIRType::Int64) {
5097 #ifdef JS_PUNBOX64
5098 LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
5099 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5100 #else
5101 LAllocation tlsPtr = useRegister(ins->tlsPtr());
5102 LInt64Allocation valueAlloc = useInt64Register(value);
5103 #endif
5104 add(new (alloc()) LWasmStoreSlotI64(valueAlloc, tlsPtr, offs), ins);
5105 } else {
5106 MOZ_ASSERT(value->type() != MIRType::RefOrNull);
5107 LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
5108 LAllocation valueAlloc = useRegisterAtStart(value);
5109 add(new (alloc()) LWasmStoreSlot(valueAlloc, tlsPtr, offs, value->type()),
5110 ins);
5114 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell* ins) {
5115 MDefinition* value = ins->value();
5116 size_t offs = 0;
5117 if (value->type() == MIRType::Int64) {
5118 #ifdef JS_PUNBOX64
5119 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5120 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5121 #else
5122 LAllocation cellPtr = useRegister(ins->cellPtr());
5123 LInt64Allocation valueAlloc = useInt64Register(value);
5124 #endif
5125 add(new (alloc()) LWasmStoreSlotI64(valueAlloc, cellPtr, offs));
5126 } else {
5127 MOZ_ASSERT(value->type() != MIRType::RefOrNull);
5128 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5129 LAllocation valueAlloc = useRegisterAtStart(value);
5130 add(new (alloc()) LWasmStoreSlot(valueAlloc, cellPtr, offs, value->type()));
5134 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult* ins) {
5135 MDefinition* stackResultArea = ins->stackResultArea();
5136 MDefinition* value = ins->value();
5137 size_t offs = ins->offset();
5138 LInstruction* lir;
5139 if (value->type() == MIRType::Int64) {
5140 lir = new (alloc()) LWasmStoreSlotI64(useInt64Register(value),
5141 useRegister(stackResultArea), offs);
5142 } else {
5143 MOZ_ASSERT(value->type() != MIRType::RefOrNull);
5144 lir = new (alloc()) LWasmStoreSlot(
5145 useRegister(value), useRegister(stackResultArea), offs, value->type());
5147 add(lir, ins);
5150 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer* ins) {
5151 LAllocation base = useRegisterAtStart(ins->base());
5152 define(new (alloc()) LWasmDerivedPointer(base), ins);
5155 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef* ins) {
5156 LAllocation tls = useRegister(ins->tls());
5157 LAllocation valueAddr = useFixed(ins->valueAddr(), PreBarrierReg);
5158 LAllocation value = useRegister(ins->value());
5159 add(new (alloc()) LWasmStoreRef(tls, valueAddr, value, temp()), ins);
5162 void LIRGenerator::visitWasmParameter(MWasmParameter* ins) {
5163 ABIArg abi = ins->abi();
5164 if (ins->type() == MIRType::StackResults) {
5165 // Functions that return stack results receive an extra incoming parameter
5166 // with type MIRType::StackResults. This value is a pointer to fresh
5167 // memory. Here we treat it as if it were in fact MIRType::Pointer.
5168 auto* lir = new (alloc()) LWasmParameter;
5169 LDefinition def(LDefinition::TypeFrom(MIRType::Pointer),
5170 LDefinition::FIXED);
5171 def.setOutput(abi.argInRegister() ? LAllocation(abi.reg())
5172 : LArgument(abi.offsetFromArgBase()));
5173 define(lir, ins, def);
5174 return;
5176 if (abi.argInRegister()) {
5177 #if defined(JS_NUNBOX32)
5178 if (abi.isGeneralRegPair()) {
5179 defineInt64Fixed(
5180 new (alloc()) LWasmParameterI64, ins,
5181 LInt64Allocation(LAllocation(AnyRegister(abi.gpr64().high)),
5182 LAllocation(AnyRegister(abi.gpr64().low))));
5183 return;
5185 #endif
5186 defineFixed(new (alloc()) LWasmParameter, ins, LAllocation(abi.reg()));
5187 return;
5189 if (ins->type() == MIRType::Int64) {
5190 MOZ_ASSERT(!abi.argInRegister());
5191 defineInt64Fixed(
5192 new (alloc()) LWasmParameterI64, ins,
5193 #if defined(JS_NUNBOX32)
5194 LInt64Allocation(LArgument(abi.offsetFromArgBase() + INT64HIGH_OFFSET),
5195 LArgument(abi.offsetFromArgBase() + INT64LOW_OFFSET))
5196 #else
5197 LInt64Allocation(LArgument(abi.offsetFromArgBase()))
5198 #endif
5200 } else {
5201 MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType::RefOrNull
5202 #ifdef ENABLE_WASM_SIMD
5203 || ins->type() == MIRType::Simd128
5204 #endif
5206 defineFixed(new (alloc()) LWasmParameter, ins,
5207 LArgument(abi.offsetFromArgBase()));
5211 void LIRGenerator::visitWasmReturn(MWasmReturn* ins) {
5212 MDefinition* rval = ins->getOperand(0);
5213 MDefinition* tlsParam = ins->getOperand(1);
5215 if (rval->type() == MIRType::Int64) {
5216 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64),
5217 useFixed(tlsParam, WasmTlsReg)));
5218 return;
5221 LAllocation returnReg;
5222 if (rval->type() == MIRType::Float32) {
5223 returnReg = useFixed(rval, ReturnFloat32Reg);
5224 } else if (rval->type() == MIRType::Double) {
5225 returnReg = useFixed(rval, ReturnDoubleReg);
5226 #ifdef ENABLE_WASM_SIMD
5227 } else if (rval->type() == MIRType::Simd128) {
5228 returnReg = useFixed(rval, ReturnSimd128Reg);
5229 #endif
5230 } else if (rval->type() == MIRType::Int32 ||
5231 rval->type() == MIRType::RefOrNull) {
5232 returnReg = useFixed(rval, ReturnReg);
5233 } else {
5234 MOZ_CRASH("Unexpected wasm return type");
5237 LWasmReturn* lir =
5238 new (alloc()) LWasmReturn(useFixed(tlsParam, WasmTlsReg), returnReg);
5239 add(lir);
5242 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins) {
5243 MDefinition* tlsParam = ins->getOperand(0);
5244 LWasmReturnVoid* lir =
5245 new (alloc()) LWasmReturnVoid(useFixed(tlsParam, WasmTlsReg));
5246 add(lir);
5249 void LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) {
5250 if (ins->arg()->type() == MIRType::Int64) {
5251 add(new (alloc())
5252 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())),
5253 ins);
5254 } else if (IsFloatingPointType(ins->arg()->type())) {
5255 MOZ_ASSERT(!ins->arg()->isEmittedAtUses());
5256 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins);
5257 } else {
5258 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins->arg())),
5259 ins);
5263 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult* ins) {
5264 auto* lir = new (alloc()) LWasmRegisterResult();
5265 uint32_t vreg = getVirtualRegister();
5266 MOZ_ASSERT(ins->type() != MIRType::Int64);
5267 auto type = LDefinition::TypeFrom(ins->type());
5268 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ins->loc())));
5269 ins->setVirtualRegister(vreg);
5270 add(lir, ins);
5273 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult* ins) {
5274 auto* lir = new (alloc()) LWasmRegisterResult();
5275 uint32_t vreg = getVirtualRegister();
5276 auto type = LDefinition::TypeFrom(ins->type());
5277 lir->setDef(0, LDefinition(vreg, type, LFloatReg(ins->loc())));
5278 ins->setVirtualRegister(vreg);
5279 add(lir, ins);
5282 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result* ins) {
5283 MOZ_ASSERT(ins->type() == MIRType::Int64);
5284 uint32_t vreg = getVirtualRegister();
5286 #if defined(JS_NUNBOX32)
5287 auto* lir = new (alloc()) LWasmRegisterPairResult();
5288 lir->setDef(INT64LOW_INDEX,
5289 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL,
5290 LGeneralReg(ins->loc().low)));
5291 lir->setDef(INT64HIGH_INDEX,
5292 LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL,
5293 LGeneralReg(ins->loc().high)));
5294 getVirtualRegister();
5295 #elif defined(JS_PUNBOX64)
5296 auto* lir = new (alloc()) LWasmRegisterResult();
5297 lir->setDef(
5298 0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ins->loc().reg)));
5299 #else
5300 # error expected either JS_NUNBOX32 or JS_PUNBOX64
5301 #endif
5303 ins->setVirtualRegister(vreg);
5304 add(lir, ins);
5307 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea* ins) {
5308 MOZ_ASSERT(ins->type() == MIRType::StackResults);
5309 auto* lir = new (alloc()) LWasmStackResultArea(temp());
5310 uint32_t vreg = getVirtualRegister();
5311 lir->setDef(0,
5312 LDefinition(vreg, LDefinition::STACKRESULTS, LDefinition::STACK));
5313 ins->setVirtualRegister(vreg);
5314 add(lir, ins);
5317 void LIRGenerator::visitWasmStackResult(MWasmStackResult* ins) {
5318 MWasmStackResultArea* area = ins->resultArea()->toWasmStackResultArea();
5319 LDefinition::Policy pol = LDefinition::STACK;
5321 if (ins->type() == MIRType::Int64) {
5322 auto* lir = new (alloc()) LWasmStackResult64;
5323 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
5324 uint32_t vreg = getVirtualRegister();
5325 LDefinition::Type typ = LDefinition::GENERAL;
5326 #if defined(JS_NUNBOX32)
5327 getVirtualRegister();
5328 lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, typ, pol));
5329 lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, typ, pol));
5330 #else
5331 lir->setDef(0, LDefinition(vreg, typ, pol));
5332 #endif
5333 ins->setVirtualRegister(vreg);
5334 add(lir, ins);
5335 return;
5338 auto* lir = new (alloc()) LWasmStackResult;
5339 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
5340 uint32_t vreg = getVirtualRegister();
5341 LDefinition::Type typ = LDefinition::TypeFrom(ins->type());
5342 lir->setDef(0, LDefinition(vreg, typ, pol));
5343 ins->setVirtualRegister(vreg);
5344 add(lir, ins);
5347 void LIRGenerator::visitWasmCall(MWasmCall* ins) {
5348 bool needsBoundsCheck = true;
5349 if (ins->callee().isTable()) {
5350 MDefinition* index = ins->getOperand(ins->numArgs());
5352 if (ins->callee().which() == wasm::CalleeDesc::WasmTable &&
5353 index->isConstant()) {
5354 if (uint32_t(index->toConstant()->toInt32()) <
5355 ins->callee().wasmTableMinLength()) {
5356 needsBoundsCheck = false;
5361 auto* lir = allocateVariadic<LWasmCall>(ins->numOperands(), needsBoundsCheck);
5362 if (!lir) {
5363 abort(AbortReason::Alloc, "OOM: LIRGenerator::lowerWasmCall");
5364 return;
5367 for (unsigned i = 0; i < ins->numArgs(); i++) {
5368 lir->setOperand(
5369 i, useFixedAtStart(ins->getOperand(i), ins->registerForArg(i)));
5372 if (ins->callee().isTable()) {
5373 MDefinition* index = ins->getOperand(ins->numArgs());
5374 lir->setOperand(ins->numArgs(),
5375 useFixedAtStart(index, WasmTableCallIndexReg));
5378 add(lir, ins);
5380 assignWasmSafepoint(lir, ins);
5383 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty* ins) {
5384 MDefinition* val = ins->value();
5386 Register cxReg, objReg, privReg, valueReg;
5387 GetTempRegForIntArg(0, 0, &cxReg);
5388 GetTempRegForIntArg(1, 0, &objReg);
5389 GetTempRegForIntArg(2, 0, &privReg);
5390 GetTempRegForIntArg(3, 0, &valueReg);
5392 // Keep using GetTempRegForIntArg, since we want to make sure we
5393 // don't clobber registers we're already using.
5394 Register tempReg1, tempReg2;
5395 GetTempRegForIntArg(4, 0, &tempReg1);
5396 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
5397 MOZ_ASSERT(ok, "How can we not have six temp registers?");
5399 LSetDOMProperty* lir = new (alloc())
5400 LSetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
5401 useBoxFixedAtStart(val, tempReg1, tempReg2),
5402 tempFixed(privReg), tempFixed(valueReg));
5403 add(lir, ins);
5404 assignSafepoint(lir, ins);
5407 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins) {
5408 Register cxReg, objReg, privReg, valueReg;
5409 GetTempRegForIntArg(0, 0, &cxReg);
5410 GetTempRegForIntArg(1, 0, &objReg);
5411 GetTempRegForIntArg(2, 0, &privReg);
5412 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
5413 MOZ_ASSERT(ok, "How can we not have four temp registers?");
5414 LGetDOMProperty* lir = new (alloc())
5415 LGetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
5416 tempFixed(privReg), tempFixed(valueReg));
5418 defineReturn(lir, ins);
5419 assignSafepoint(lir, ins);
5422 void LIRGenerator::visitGetDOMMember(MGetDOMMember* ins) {
5423 MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
5424 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
5425 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
5426 // value can in fact change as a result of DOM setters and method calls.
5427 MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
5428 "Member gets had better not alias the world");
5430 MDefinition* obj = ins->object();
5431 MOZ_ASSERT(obj->type() == MIRType::Object);
5433 MIRType type = ins->type();
5435 if (type == MIRType::Value) {
5436 LGetDOMMemberV* lir = new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj));
5437 defineBox(lir, ins);
5438 } else {
5439 LGetDOMMemberT* lir =
5440 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj, type));
5441 define(lir, ins);
5445 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue* ins) {
5446 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5447 auto* lir =
5448 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins->proxy()));
5449 defineBox(lir, ins);
5452 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration(
5453 MLoadDOMExpandoValueGuardGeneration* ins) {
5454 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5455 auto* lir = new (alloc())
5456 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins->proxy()));
5457 assignSnapshot(lir, ins->bailoutKind());
5458 defineBox(lir, ins);
5461 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration(
5462 MLoadDOMExpandoValueIgnoreGeneration* ins) {
5463 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5464 auto* lir = new (alloc())
5465 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins->proxy()));
5466 defineBox(lir, ins);
5469 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape(
5470 MGuardDOMExpandoMissingOrGuardShape* ins) {
5471 MOZ_ASSERT(ins->expando()->type() == MIRType::Value);
5472 auto* lir = new (alloc())
5473 LGuardDOMExpandoMissingOrGuardShape(useBox(ins->expando()), temp());
5474 assignSnapshot(lir, ins->bailoutKind());
5475 add(lir, ins);
5476 redefine(ins, ins->expando());
5479 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter* ins) {
5480 LIncrementWarmUpCounter* lir = new (alloc()) LIncrementWarmUpCounter(temp());
5481 add(lir, ins);
5484 void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) {
5485 MDefinition* input = ins->input();
5486 MOZ_ASSERT(input->type() == MIRType::Value);
5487 LLexicalCheck* lir = new (alloc()) LLexicalCheck(useBox(input));
5488 assignSnapshot(lir, ins->bailoutKind());
5489 add(lir, ins);
5490 redefine(ins, input);
5493 void LIRGenerator::visitThrowRuntimeLexicalError(
5494 MThrowRuntimeLexicalError* ins) {
5495 LThrowRuntimeLexicalError* lir = new (alloc()) LThrowRuntimeLexicalError();
5496 add(lir, ins);
5497 assignSafepoint(lir, ins);
5500 void LIRGenerator::visitThrowMsg(MThrowMsg* ins) {
5501 LThrowMsg* lir = new (alloc()) LThrowMsg();
5502 add(lir, ins);
5503 assignSafepoint(lir, ins);
5506 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation* ins) {
5507 LGlobalDeclInstantiation* lir = new (alloc()) LGlobalDeclInstantiation();
5508 add(lir, ins);
5509 assignSafepoint(lir, ins);
5512 void LIRGenerator::visitDebugger(MDebugger* ins) {
5513 LDebugger* lir =
5514 new (alloc()) LDebugger(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
5515 assignSnapshot(lir, ins->bailoutKind());
5516 add(lir, ins);
5519 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins) {
5520 define(new (alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
5523 void LIRGenerator::visitCheckReturn(MCheckReturn* ins) {
5524 MDefinition* retVal = ins->returnValue();
5525 MDefinition* thisVal = ins->thisValue();
5526 MOZ_ASSERT(retVal->type() == MIRType::Value);
5527 MOZ_ASSERT(thisVal->type() == MIRType::Value);
5529 auto* lir =
5530 new (alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal));
5531 defineBox(lir, ins);
5532 assignSafepoint(lir, ins);
5535 void LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) {
5536 MDefinition* input = ins->input();
5537 MOZ_ASSERT(input->type() == MIRType::Value);
5539 LCheckIsObj* lir = new (alloc()) LCheckIsObj(useBox(input));
5540 define(lir, ins);
5541 assignSafepoint(lir, ins);
5544 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) {
5545 MDefinition* checkVal = ins->checkValue();
5546 MOZ_ASSERT(checkVal->type() == MIRType::Value);
5548 auto* lir = new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal));
5549 redefine(ins, checkVal);
5550 add(lir, ins);
5551 assignSafepoint(lir, ins);
5554 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage* ins) {
5555 MDefinition* heritage = ins->heritage();
5556 MOZ_ASSERT(heritage->type() == MIRType::Value);
5558 auto* lir =
5559 new (alloc()) LCheckClassHeritage(useBox(heritage), temp(), temp());
5560 redefine(ins, heritage);
5561 add(lir, ins);
5562 assignSafepoint(lir, ins);
5565 void LIRGenerator::visitCheckThis(MCheckThis* ins) {
5566 MDefinition* thisValue = ins->thisValue();
5567 MOZ_ASSERT(thisValue->type() == MIRType::Value);
5569 auto* lir = new (alloc()) LCheckThis(useBoxAtStart(thisValue));
5570 redefine(ins, thisValue);
5571 add(lir, ins);
5572 assignSafepoint(lir, ins);
5575 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit* ins) {
5576 MDefinition* thisValue = ins->thisValue();
5577 MOZ_ASSERT(thisValue->type() == MIRType::Value);
5579 auto* lir = new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue));
5580 redefine(ins, thisValue);
5581 add(lir, ins);
5582 assignSafepoint(lir, ins);
5585 void LIRGenerator::visitGenerator(MGenerator* ins) {
5586 auto* lir =
5587 new (alloc()) LGenerator(useRegisterAtStart(ins->callee()),
5588 useRegisterAtStart(ins->environmentChain()),
5589 useRegisterAtStart(ins->argsObject()));
5590 defineReturn(lir, ins);
5591 assignSafepoint(lir, ins);
5594 void LIRGenerator::visitAsyncResolve(MAsyncResolve* ins) {
5595 auto* lir = new (alloc()) LAsyncResolve(useRegisterAtStart(ins->generator()),
5596 useBoxAtStart(ins->valueOrReason()));
5597 defineReturn(lir, ins);
5598 assignSafepoint(lir, ins);
5601 void LIRGenerator::visitAsyncAwait(MAsyncAwait* ins) {
5602 MOZ_ASSERT(ins->generator()->type() == MIRType::Object);
5603 auto* lir = new (alloc()) LAsyncAwait(useBoxAtStart(ins->value()),
5604 useRegisterAtStart(ins->generator()));
5605 defineReturn(lir, ins);
5606 assignSafepoint(lir, ins);
5609 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait* ins) {
5610 auto* lir = new (alloc()) LCanSkipAwait(useBoxAtStart(ins->value()));
5611 defineReturn(lir, ins);
5612 assignSafepoint(lir, ins);
5615 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue* ins) {
5616 auto* lir = new (alloc()) LMaybeExtractAwaitValue(
5617 useBoxAtStart(ins->value()), useRegisterAtStart(ins->canSkip()));
5618 defineReturn(lir, ins);
5619 assignSafepoint(lir, ins);
5622 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) {
5623 MDefinition* checkVal = ins->checkValue();
5624 MOZ_ASSERT(checkVal->type() == MIRType::Value);
5626 LDebugCheckSelfHosted* lir =
5627 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal));
5628 redefine(ins, checkVal);
5629 add(lir, ins);
5630 assignSafepoint(lir, ins);
5633 void LIRGenerator::visitFinishBoundFunctionInit(MFinishBoundFunctionInit* ins) {
5634 auto lir = new (alloc()) LFinishBoundFunctionInit(
5635 useRegister(ins->bound()), useRegister(ins->target()),
5636 useRegister(ins->argCount()), temp(), temp());
5637 add(lir, ins);
5638 assignSafepoint(lir, ins);
5641 void LIRGenerator::visitIsPackedArray(MIsPackedArray* ins) {
5642 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5643 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5645 auto lir = new (alloc()) LIsPackedArray(useRegister(ins->object()), temp());
5646 define(lir, ins);
5649 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked* ins) {
5650 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
5652 auto* lir = new (alloc())
5653 LGuardArrayIsPacked(useRegister(ins->array()), temp(), temp());
5654 assignSnapshot(lir, ins->bailoutKind());
5655 add(lir, ins);
5656 redefine(ins, ins->array());
5659 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf* ins) {
5660 MOZ_ASSERT(ins->target()->type() == MIRType::Object);
5661 MOZ_ASSERT(ins->type() == MIRType::Value);
5663 auto lir = new (alloc()) LGetPrototypeOf(useRegister(ins->target()));
5664 defineBox(lir, ins);
5665 assignSafepoint(lir, ins);
5668 void LIRGenerator::visitObjectWithProto(MObjectWithProto* ins) {
5669 MOZ_ASSERT(ins->prototype()->type() == MIRType::Value);
5670 MOZ_ASSERT(ins->type() == MIRType::Object);
5672 auto* lir = new (alloc()) LObjectWithProto(useBoxAtStart(ins->prototype()));
5673 defineReturn(lir, ins);
5674 assignSafepoint(lir, ins);
5677 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto* ins) {
5678 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5679 MOZ_ASSERT(ins->type() == MIRType::Object);
5681 auto* lir =
5682 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins->object()));
5683 define(lir, ins);
5686 void LIRGenerator::visitBuiltinObject(MBuiltinObject* ins) {
5687 MOZ_ASSERT(ins->type() == MIRType::Object);
5689 auto* lir = new (alloc()) LBuiltinObject();
5690 defineReturn(lir, ins);
5691 assignSafepoint(lir, ins);
5694 void LIRGenerator::visitReturn(MReturn* ret) {
5695 return visitReturnImpl(ret->getOperand(0));
5698 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn* ret) {
5699 return visitReturnImpl(ret->getOperand(0), true);
5702 void LIRGenerator::visitSuperFunction(MSuperFunction* ins) {
5703 MOZ_ASSERT(ins->callee()->type() == MIRType::Object);
5704 MOZ_ASSERT(ins->type() == MIRType::Value);
5706 auto* lir = new (alloc()) LSuperFunction(useRegister(ins->callee()), temp());
5707 defineBox(lir, ins);
5710 void LIRGenerator::visitInitHomeObject(MInitHomeObject* ins) {
5711 MDefinition* function = ins->function();
5712 MOZ_ASSERT(function->type() == MIRType::Object);
5714 MDefinition* homeObject = ins->homeObject();
5715 MOZ_ASSERT(homeObject->type() == MIRType::Value);
5717 MOZ_ASSERT(ins->type() == MIRType::Object);
5719 auto* lir = new (alloc())
5720 LInitHomeObject(useRegisterAtStart(function), useBoxAtStart(homeObject));
5721 redefine(ins, function);
5722 add(lir, ins);
5725 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor* ins) {
5726 MDefinition* object = ins->object();
5727 MOZ_ASSERT(object->type() == MIRType::Object);
5729 auto* lir = new (alloc()) LIsTypedArrayConstructor(useRegister(object));
5730 define(lir, ins);
5733 void LIRGenerator::visitLoadValueTag(MLoadValueTag* ins) {
5734 MDefinition* value = ins->value();
5735 MOZ_ASSERT(value->type() == MIRType::Value);
5737 define(new (alloc()) LLoadValueTag(useBoxAtStart(value)), ins);
5740 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual* ins) {
5741 MDefinition* lhs = ins->lhs();
5742 MOZ_ASSERT(lhs->type() == MIRType::Int32);
5744 MDefinition* rhs = ins->rhs();
5745 MOZ_ASSERT(rhs->type() == MIRType::Int32);
5747 auto* guard =
5748 new (alloc()) LGuardTagNotEqual(useRegister(lhs), useRegister(rhs));
5749 assignSnapshot(guard, ins->bailoutKind());
5750 add(guard, ins);
5753 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget* ins) {
5754 MDefinition* object = ins->object();
5755 MOZ_ASSERT(object->type() == MIRType::Object);
5757 define(new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object)), ins);
5760 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter* ins) {
5761 MDefinition* object = ins->object();
5762 MOZ_ASSERT(object->type() == MIRType::Object);
5764 auto* guard = new (alloc())
5765 LGuardHasGetterSetter(useRegisterAtStart(object), tempFixed(CallTempReg0),
5766 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5767 assignSnapshot(guard, ins->bailoutKind());
5768 add(guard, ins);
5769 redefine(ins, object);
5772 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible* ins) {
5773 MDefinition* object = ins->object();
5774 MOZ_ASSERT(object->type() == MIRType::Object);
5776 auto* guard = new (alloc()) LGuardIsExtensible(useRegister(object), temp());
5777 assignSnapshot(guard, ins->bailoutKind());
5778 add(guard, ins);
5779 redefine(ins, object);
5782 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative* ins) {
5783 MDefinition* index = ins->index();
5784 MOZ_ASSERT(index->type() == MIRType::Int32);
5786 auto* guard = new (alloc()) LGuardInt32IsNonNegative(useRegister(index));
5787 assignSnapshot(guard, ins->bailoutKind());
5788 add(guard, ins);
5789 redefine(ins, index);
5792 void LIRGenerator::visitGuardIndexGreaterThanDenseInitLength(
5793 MGuardIndexGreaterThanDenseInitLength* ins) {
5794 MDefinition* object = ins->object();
5795 MOZ_ASSERT(object->type() == MIRType::Object);
5797 MDefinition* index = ins->index();
5798 MOZ_ASSERT(index->type() == MIRType::Int32);
5800 LDefinition spectreTemp =
5801 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5803 auto* guard = new (alloc()) LGuardIndexGreaterThanDenseInitLength(
5804 useRegister(object), useRegister(index), temp(), spectreTemp);
5805 assignSnapshot(guard, ins->bailoutKind());
5806 add(guard, ins);
5807 redefine(ins, index);
5810 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd(
5811 MGuardIndexIsValidUpdateOrAdd* ins) {
5812 MDefinition* object = ins->object();
5813 MOZ_ASSERT(object->type() == MIRType::Object);
5815 MDefinition* index = ins->index();
5816 MOZ_ASSERT(index->type() == MIRType::Int32);
5818 LDefinition spectreTemp =
5819 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5821 auto* guard = new (alloc()) LGuardIndexIsValidUpdateOrAdd(
5822 useRegister(object), useRegister(index), temp(), spectreTemp);
5823 assignSnapshot(guard, ins->bailoutKind());
5824 add(guard, ins);
5825 redefine(ins, index);
5828 void LIRGenerator::visitCallAddOrUpdateSparseElement(
5829 MCallAddOrUpdateSparseElement* ins) {
5830 MDefinition* object = ins->object();
5831 MOZ_ASSERT(object->type() == MIRType::Object);
5833 MDefinition* index = ins->index();
5834 MOZ_ASSERT(index->type() == MIRType::Int32);
5836 MDefinition* value = ins->value();
5837 MOZ_ASSERT(value->type() == MIRType::Value);
5839 auto* lir = new (alloc()) LCallAddOrUpdateSparseElement(
5840 useRegisterAtStart(object), useRegisterAtStart(index),
5841 useBoxAtStart(value));
5842 add(lir, ins);
5843 assignSafepoint(lir, ins);
5846 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement* ins) {
5847 MDefinition* object = ins->object();
5848 MOZ_ASSERT(object->type() == MIRType::Object);
5850 MDefinition* index = ins->index();
5851 MOZ_ASSERT(index->type() == MIRType::Int32);
5853 auto* lir = new (alloc()) LCallGetSparseElement(useRegisterAtStart(object),
5854 useRegisterAtStart(index));
5855 defineReturn(lir, ins);
5856 assignSafepoint(lir, ins);
5859 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement* ins) {
5860 MDefinition* object = ins->object();
5861 MOZ_ASSERT(object->type() == MIRType::Object);
5863 MDefinition* index = ins->index();
5864 MOZ_ASSERT(index->type() == MIRType::Int32);
5866 auto* lir = new (alloc()) LCallNativeGetElement(useRegisterAtStart(object),
5867 useRegisterAtStart(index));
5868 defineReturn(lir, ins);
5869 assignSafepoint(lir, ins);
5872 void LIRGenerator::visitCallObjectHasSparseElement(
5873 MCallObjectHasSparseElement* ins) {
5874 MDefinition* object = ins->object();
5875 MOZ_ASSERT(object->type() == MIRType::Object);
5877 MDefinition* index = ins->index();
5878 MOZ_ASSERT(index->type() == MIRType::Int32);
5880 auto* lir = new (alloc()) LCallObjectHasSparseElement(
5881 useRegisterAtStart(object), useRegisterAtStart(index),
5882 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
5883 assignSnapshot(lir, ins->bailoutKind());
5884 defineReturn(lir, ins);
5887 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN* ins) {
5888 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
5889 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
5891 if (ins->bits()->isConstant()) {
5892 int32_t bits = ins->bits()->toConstant()->toInt32();
5893 if (bits == 64) {
5894 auto* lir = new (alloc())
5895 LBigIntAsIntN64(useRegister(ins->input()), temp(), tempInt64());
5896 define(lir, ins);
5897 assignSafepoint(lir, ins);
5898 return;
5900 if (bits == 32) {
5901 auto* lir = new (alloc())
5902 LBigIntAsIntN32(useRegister(ins->input()), temp(), tempInt64());
5903 define(lir, ins);
5904 assignSafepoint(lir, ins);
5905 return;
5909 auto* lir = new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins->bits()),
5910 useRegisterAtStart(ins->input()));
5911 defineReturn(lir, ins);
5912 assignSafepoint(lir, ins);
5915 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN* ins) {
5916 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
5917 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
5919 if (ins->bits()->isConstant()) {
5920 int32_t bits = ins->bits()->toConstant()->toInt32();
5921 if (bits == 64) {
5922 auto* lir = new (alloc())
5923 LBigIntAsUintN64(useRegister(ins->input()), temp(), tempInt64());
5924 define(lir, ins);
5925 assignSafepoint(lir, ins);
5926 return;
5928 if (bits == 32) {
5929 auto* lir = new (alloc())
5930 LBigIntAsUintN32(useRegister(ins->input()), temp(), tempInt64());
5931 define(lir, ins);
5932 assignSafepoint(lir, ins);
5933 return;
5937 auto* lir = new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins->bits()),
5938 useRegisterAtStart(ins->input()));
5939 defineReturn(lir, ins);
5940 assignSafepoint(lir, ins);
5943 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing* ins) {
5944 MDefinition* input = ins->input();
5946 auto* guard = new (alloc()) LGuardNonGCThing(useBox(input));
5947 assignSnapshot(guard, ins->bailoutKind());
5948 add(guard, ins);
5949 redefine(ins, input);
5952 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing* ins) {
5953 auto* lir =
5954 new (alloc()) LToHashableNonGCThing(useBox(ins->input()), tempDouble());
5955 defineBox(lir, ins);
5958 void LIRGenerator::visitToHashableString(MToHashableString* ins) {
5959 auto* lir = new (alloc()) LToHashableString(useRegister(ins->input()));
5960 define(lir, ins);
5961 assignSafepoint(lir, ins);
5964 void LIRGenerator::visitToHashableValue(MToHashableValue* ins) {
5965 auto* lir =
5966 new (alloc()) LToHashableValue(useBox(ins->input()), tempDouble());
5967 defineBox(lir, ins);
5968 assignSafepoint(lir, ins);
5971 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing* ins) {
5972 auto* lir = new (alloc()) LHashNonGCThing(useBox(ins->input()), temp());
5973 define(lir, ins);
5976 void LIRGenerator::visitHashString(MHashString* ins) {
5977 auto* lir = new (alloc()) LHashString(useRegister(ins->input()), temp());
5978 define(lir, ins);
5981 void LIRGenerator::visitHashSymbol(MHashSymbol* ins) {
5982 auto* lir = new (alloc()) LHashSymbol(useRegister(ins->input()));
5983 define(lir, ins);
5986 void LIRGenerator::visitHashBigInt(MHashBigInt* ins) {
5987 auto* lir = new (alloc())
5988 LHashBigInt(useRegister(ins->input()), temp(), temp(), temp());
5989 define(lir, ins);
5992 void LIRGenerator::visitHashObject(MHashObject* ins) {
5993 auto* lir =
5994 new (alloc()) LHashObject(useRegister(ins->set()), useBox(ins->input()),
5995 temp(), temp(), temp(), temp());
5996 define(lir, ins);
5999 void LIRGenerator::visitHashValue(MHashValue* ins) {
6000 auto* lir =
6001 new (alloc()) LHashValue(useRegister(ins->set()), useBox(ins->input()),
6002 temp(), temp(), temp(), temp());
6003 define(lir, ins);
6006 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt* ins) {
6007 auto* lir = new (alloc())
6008 LSetObjectHasNonBigInt(useRegister(ins->set()), useBox(ins->value()),
6009 useRegister(ins->hash()), temp(), temp());
6010 define(lir, ins);
6013 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt* ins) {
6014 auto* lir = new (alloc()) LSetObjectHasBigInt(
6015 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
6016 temp(), temp(), temp(), temp());
6017 define(lir, ins);
6020 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue* ins) {
6021 auto* lir = new (alloc()) LSetObjectHasValue(
6022 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
6023 temp(), temp(), temp(), temp());
6024 define(lir, ins);
6027 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall* ins) {
6028 auto* lir = new (alloc()) LSetObjectHasValueVMCall(
6029 useRegisterAtStart(ins->set()), useBoxAtStart(ins->value()));
6030 defineReturn(lir, ins);
6031 assignSafepoint(lir, ins);
6034 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt* ins) {
6035 auto* lir = new (alloc())
6036 LMapObjectHasNonBigInt(useRegister(ins->map()), useBox(ins->value()),
6037 useRegister(ins->hash()), temp(), temp());
6038 define(lir, ins);
6041 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt* ins) {
6042 auto* lir = new (alloc()) LMapObjectHasBigInt(
6043 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6044 temp(), temp(), temp(), temp());
6045 define(lir, ins);
6048 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue* ins) {
6049 auto* lir = new (alloc()) LMapObjectHasValue(
6050 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6051 temp(), temp(), temp(), temp());
6052 define(lir, ins);
6055 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall* ins) {
6056 auto* lir = new (alloc()) LMapObjectHasValueVMCall(
6057 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
6058 defineReturn(lir, ins);
6059 assignSafepoint(lir, ins);
6062 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt* ins) {
6063 auto* lir = new (alloc())
6064 LMapObjectGetNonBigInt(useRegister(ins->map()), useBox(ins->value()),
6065 useRegister(ins->hash()), temp(), temp());
6066 defineBox(lir, ins);
6069 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt* ins) {
6070 auto* lir = new (alloc()) LMapObjectGetBigInt(
6071 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6072 temp(), temp(), temp(), temp());
6073 defineBox(lir, ins);
6076 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue* ins) {
6077 auto* lir = new (alloc()) LMapObjectGetValue(
6078 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6079 temp(), temp(), temp(), temp());
6080 defineBox(lir, ins);
6083 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall* ins) {
6084 auto* lir = new (alloc()) LMapObjectGetValueVMCall(
6085 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
6086 defineReturn(lir, ins);
6087 assignSafepoint(lir, ins);
6090 void LIRGenerator::visitConstant(MConstant* ins) {
6091 if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
6092 emitAtUses(ins);
6093 return;
6096 switch (ins->type()) {
6097 case MIRType::Double:
6098 define(new (alloc()) LDouble(ins->toDouble()), ins);
6099 break;
6100 case MIRType::Float32:
6101 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
6102 break;
6103 case MIRType::Boolean:
6104 define(new (alloc()) LInteger(ins->toBoolean()), ins);
6105 break;
6106 case MIRType::Int32:
6107 define(new (alloc()) LInteger(ins->toInt32()), ins);
6108 break;
6109 case MIRType::Int64:
6110 defineInt64(new (alloc()) LInteger64(ins->toInt64()), ins);
6111 break;
6112 case MIRType::IntPtr:
6113 #ifdef JS_64BIT
6114 defineInt64(new (alloc()) LInteger64(ins->toIntPtr()), ins);
6115 #else
6116 define(new (alloc()) LInteger(ins->toIntPtr()), ins);
6117 #endif
6118 break;
6119 case MIRType::String:
6120 define(new (alloc()) LPointer(ins->toString()), ins);
6121 break;
6122 case MIRType::Symbol:
6123 define(new (alloc()) LPointer(ins->toSymbol()), ins);
6124 break;
6125 case MIRType::BigInt:
6126 define(new (alloc()) LPointer(ins->toBigInt()), ins);
6127 break;
6128 case MIRType::Object:
6129 define(new (alloc()) LPointer(&ins->toObject()), ins);
6130 break;
6131 case MIRType::Shape:
6132 MOZ_ASSERT(ins->isEmittedAtUses());
6133 break;
6134 default:
6135 // Constants of special types (undefined, null) should never flow into
6136 // here directly. Operations blindly consuming them require a Box.
6137 MOZ_CRASH("unexpected constant type");
6141 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant* ins) {
6142 define(new (alloc()) LWasmNullConstant(), ins);
6145 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant* ins) {
6146 switch (ins->type()) {
6147 case MIRType::Double:
6148 define(new (alloc()) LDouble(ins->toDouble()), ins);
6149 break;
6150 case MIRType::Float32:
6151 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
6152 break;
6153 #ifdef ENABLE_WASM_SIMD
6154 case MIRType::Simd128:
6155 define(new (alloc()) LSimd128(ins->toSimd128()), ins);
6156 break;
6157 #endif
6158 default:
6159 MOZ_CRASH("unexpected constant type");
6163 #ifdef JS_JITSPEW
6164 static void SpewResumePoint(MBasicBlock* block, MInstruction* ins,
6165 MResumePoint* resumePoint) {
6166 Fprinter& out = JitSpewPrinter();
6167 out.printf("Current resume point %p details:\n", (void*)resumePoint);
6168 out.printf(" frame count: %u\n", resumePoint->frameCount());
6170 if (ins) {
6171 out.printf(" taken after: ");
6172 ins->printName(out);
6173 } else {
6174 out.printf(" taken at block %u entry", block->id());
6176 out.printf("\n");
6178 out.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint->pc(),
6179 (void*)resumePoint->block()->info().script(),
6180 int(resumePoint->block()->info().script()->pcToOffset(
6181 resumePoint->pc())));
6183 for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
6184 MDefinition* in = resumePoint->getOperand(i);
6185 out.printf(" slot%u: ", (unsigned)i);
6186 in->printName(out);
6187 out.printf("\n");
6190 #endif
6192 void LIRGenerator::visitInstructionDispatch(MInstruction* ins) {
6193 #ifdef JS_CODEGEN_NONE
6194 // Don't compile the switch-statement below so that we don't have to define
6195 // the platform-specific visit* methods for the none-backend.
6196 MOZ_CRASH();
6197 #else
6198 switch (ins->op()) {
6199 # define MIR_OP(op) \
6200 case MDefinition::Opcode::op: \
6201 visit##op(ins->to##op()); \
6202 break;
6203 MIR_OPCODE_LIST(MIR_OP)
6204 # undef MIR_OP
6205 default:
6206 MOZ_CRASH("Invalid instruction");
6208 #endif
6211 void LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins) {
6212 static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins);
6215 bool LIRGenerator::visitInstruction(MInstruction* ins) {
6216 MOZ_ASSERT(!errored());
6218 if (ins->isRecoveredOnBailout()) {
6219 MOZ_ASSERT(!JitOptions.disableRecoverIns);
6220 return true;
6223 if (!gen->ensureBallast()) {
6224 return false;
6226 visitInstructionDispatch(ins);
6228 if (ins->resumePoint()) {
6229 updateResumeState(ins);
6232 #ifdef DEBUG
6233 ins->setInWorklistUnchecked();
6234 #endif
6236 // If no safepoint was created, there's no need for an OSI point.
6237 if (LOsiPoint* osiPoint = popOsiPoint()) {
6238 add(osiPoint);
6241 return !errored();
6244 void LIRGenerator::definePhis() {
6245 size_t lirIndex = 0;
6246 MBasicBlock* block = current->mir();
6247 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
6248 if (phi->type() == MIRType::Value) {
6249 defineUntypedPhi(*phi, lirIndex);
6250 lirIndex += BOX_PIECES;
6251 } else if (phi->type() == MIRType::Int64) {
6252 defineInt64Phi(*phi, lirIndex);
6253 lirIndex += INT64_PIECES;
6254 } else {
6255 defineTypedPhi(*phi, lirIndex);
6256 lirIndex += 1;
6261 void LIRGenerator::updateResumeState(MInstruction* ins) {
6262 lastResumePoint_ = ins->resumePoint();
6263 #ifdef JS_JITSPEW
6264 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
6265 SpewResumePoint(nullptr, ins, lastResumePoint_);
6267 #endif
6270 void LIRGenerator::updateResumeState(MBasicBlock* block) {
6271 // Note: RangeAnalysis can flag blocks as unreachable, but they are only
6272 // removed iff GVN (including UCE) is enabled.
6273 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(),
6274 block->entryResumePoint());
6275 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
6276 lastResumePoint_ = block->entryResumePoint();
6277 #ifdef JS_JITSPEW
6278 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
6279 SpewResumePoint(block, nullptr, lastResumePoint_);
6281 #endif
6284 bool LIRGenerator::visitBlock(MBasicBlock* block) {
6285 current = block->lir();
6286 updateResumeState(block);
6288 definePhis();
6290 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
6291 for (MInstructionIterator iter = block->begin(); *iter != block->lastIns();
6292 iter++) {
6293 if (!visitInstruction(*iter)) {
6294 return false;
6298 if (block->successorWithPhis()) {
6299 // If we have a successor with phis, lower the phi input now that we
6300 // are approaching the join point.
6301 MBasicBlock* successor = block->successorWithPhis();
6302 uint32_t position = block->positionInPhiSuccessor();
6303 size_t lirIndex = 0;
6304 for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd();
6305 phi++) {
6306 if (!gen->ensureBallast()) {
6307 return false;
6310 MDefinition* opd = phi->getOperand(position);
6311 ensureDefined(opd);
6313 MOZ_ASSERT(opd->type() == phi->type());
6315 if (phi->type() == MIRType::Value) {
6316 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
6317 lirIndex += BOX_PIECES;
6318 } else if (phi->type() == MIRType::Int64) {
6319 lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex);
6320 lirIndex += INT64_PIECES;
6321 } else {
6322 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
6323 lirIndex += 1;
6328 // Now emit the last instruction, which is some form of branch.
6329 if (!visitInstruction(block->lastIns())) {
6330 return false;
6333 return true;
6336 void LIRGenerator::visitNaNToZero(MNaNToZero* ins) {
6337 MDefinition* input = ins->input();
6339 if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) {
6340 redefine(ins, input);
6341 return;
6343 LNaNToZero* lir =
6344 new (alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble());
6345 defineReuseInput(lir, ins, 0);
6348 bool LIRGenerator::generate() {
6349 // Create all blocks and prep all phis beforehand.
6350 for (ReversePostorderIterator block(graph.rpoBegin());
6351 block != graph.rpoEnd(); block++) {
6352 if (gen->shouldCancel("Lowering (preparation loop)")) {
6353 return false;
6356 if (!lirGraph_.initBlock(*block)) {
6357 return false;
6361 for (ReversePostorderIterator block(graph.rpoBegin());
6362 block != graph.rpoEnd(); block++) {
6363 if (gen->shouldCancel("Lowering (main loop)")) {
6364 return false;
6367 if (!visitBlock(*block)) {
6368 return false;
6372 lirGraph_.setArgumentSlotCount(maxargslots_);
6373 return true;
6376 void LIRGenerator::visitPhi(MPhi* phi) {
6377 // Phi nodes are not lowered because they are only meaningful for the register
6378 // allocator.
6379 MOZ_CRASH("Unexpected Phi node during Lowering.");
6382 void LIRGenerator::visitBeta(MBeta* beta) {
6383 // Beta nodes are supposed to be removed before because they are
6384 // only used to carry the range information for Range analysis
6385 MOZ_CRASH("Unexpected Beta node during Lowering.");
6388 void LIRGenerator::visitObjectState(MObjectState* objState) {
6389 // ObjectState nodes are always recovered on bailouts
6390 MOZ_CRASH("Unexpected ObjectState node during Lowering.");
6393 void LIRGenerator::visitArrayState(MArrayState* objState) {
6394 // ArrayState nodes are always recovered on bailouts
6395 MOZ_CRASH("Unexpected ArrayState node during Lowering.");
6398 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall* ins) {
6399 // The instruction needs a temp register:
6400 // - that's not the FramePointer, since wasm is going to use it in the
6401 // function.
6402 // - that's not aliasing an input register.
6403 LDefinition scratch = tempFixed(ABINonArgReg0);
6405 // Also prevent register allocation from using wasm's FramePointer, in
6406 // non-profiling mode.
6407 LDefinition fp = gen->isProfilerInstrumentationEnabled()
6408 ? LDefinition::BogusTemp()
6409 : tempFixed(FramePointer);
6411 // Note that since this is a LIR call instruction, regalloc will prevent
6412 // the use*AtStart below from reusing any of the temporaries.
6414 LInstruction* lir;
6415 if (ins->type() == MIRType::Value) {
6416 lir = allocateVariadic<LIonToWasmCallV>(ins->numOperands(), scratch, fp);
6417 } else if (ins->type() == MIRType::Int64) {
6418 lir = allocateVariadic<LIonToWasmCallI64>(ins->numOperands(), scratch, fp);
6419 } else {
6420 lir = allocateVariadic<LIonToWasmCall>(ins->numOperands(), scratch, fp);
6422 if (!lir) {
6423 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitIonToWasmCall");
6424 return;
6427 ABIArgGenerator abi;
6428 for (unsigned i = 0; i < ins->numOperands(); i++) {
6429 MDefinition* argDef = ins->getOperand(i);
6430 ABIArg arg = abi.next(ToMIRType(argDef->type()));
6431 switch (arg.kind()) {
6432 case ABIArg::GPR:
6433 case ABIArg::FPU:
6434 lir->setOperand(i, useFixedAtStart(argDef, arg.reg()));
6435 break;
6436 case ABIArg::Stack:
6437 lir->setOperand(i, useAtStart(argDef));
6438 break;
6439 #ifdef JS_CODEGEN_REGISTER_PAIR
6440 case ABIArg::GPR_PAIR:
6441 MOZ_CRASH(
6442 "no way to pass i64, and wasm uses hardfp for function calls");
6443 #endif
6444 case ABIArg::Uninitialized:
6445 MOZ_CRASH("Uninitialized ABIArg kind");
6449 defineReturn(lir, ins);
6450 assignSafepoint(lir, ins);
6453 void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
6454 MDefinition* condExpr = ins->condExpr();
6456 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid
6457 // generating a boolean that we then have to test again.
6458 if (condExpr->isCompare() && condExpr->isEmittedAtUses()) {
6459 MCompare* comp = condExpr->toCompare();
6460 MCompare::CompareType compTy = comp->compareType();
6461 if (canSpecializeWasmCompareAndSelect(compTy, ins->type())) {
6462 JSOp jsop = comp->jsop();
6463 // We don't currently generate any other JSOPs for the comparison, and if
6464 // that changes, we want to know about it. Hence this assertion.
6465 MOZ_ASSERT(jsop == JSOp::Eq || jsop == JSOp::Ne || jsop == JSOp::Lt ||
6466 jsop == JSOp::Gt || jsop == JSOp::Le || jsop == JSOp::Ge);
6467 MDefinition* lhs = comp->lhs();
6468 MDefinition* rhs = comp->rhs();
6469 jsop = ReorderComparison(jsop, &lhs, &rhs);
6470 lowerWasmCompareAndSelect(ins, lhs, rhs, compTy, jsop);
6471 return;
6474 // Fall through to code that generates a boolean and selects on that.
6476 if (ins->type() == MIRType::Int64) {
6477 lowerWasmSelectI64(ins);
6478 return;
6481 lowerWasmSelectI(ins);
6484 void LIRGenerator::visitWasmFence(MWasmFence* ins) {
6485 add(new (alloc()) LWasmFence, ins);
6488 // Wasm Exception Handling
6490 void LIRGenerator::visitWasmExceptionDataPointer(
6491 MWasmExceptionDataPointer* ins) {
6492 MOZ_ASSERT(ins->type() == MIRType::Pointer);
6493 auto* lir = new (alloc()) LWasmExceptionDataPointer(useRegister(ins->exn()));
6494 define(lir, ins);
6497 void LIRGenerator::visitWasmLoadExceptionDataValue(
6498 MWasmLoadExceptionDataValue* ins) {
6499 size_t offs = ins->offset();
6500 MDefinition* exnDataPtr = ins->exnDataPtr();
6501 LAllocation dataPtr = useRegister(exnDataPtr);
6503 if (ins->type() == MIRType::Int64) {
6504 defineInt64(new (alloc()) LWasmLoadSlotI64(dataPtr, offs), ins);
6505 } else {
6506 define(new (alloc()) LWasmLoadSlot(dataPtr, offs, ins->type()), ins);
6510 void LIRGenerator::visitWasmStoreExceptionDataValue(
6511 MWasmStoreExceptionDataValue* ins) {
6512 MDefinition* exnDataPtr = ins->exnDataPtr();
6513 MDefinition* value = ins->value();
6514 size_t offs = ins->offset();
6515 LInstruction* lir;
6517 if (value->type() == MIRType::Int64) {
6518 lir = new (alloc()) LWasmStoreSlotI64(useInt64Register(value),
6519 useRegister(exnDataPtr), offs);
6520 } else {
6521 lir = new (alloc()) LWasmStoreSlot(
6522 useRegister(value), useRegister(exnDataPtr), offs, value->type());
6524 add(lir, ins);
6527 void LIRGenerator::visitWasmExceptionRefsPointer(
6528 MWasmExceptionRefsPointer* ins) {
6529 MOZ_ASSERT(ins->type() == MIRType::Pointer);
6530 LAllocation exn = useRegister(ins->exn());
6531 auto* lir = new (alloc()) LWasmExceptionRefsPointer(exn, temp());
6532 define(lir, ins);
6535 void LIRGenerator::visitWasmLoadExceptionRefsValue(
6536 MWasmLoadExceptionRefsValue* ins) {
6537 LAllocation refsPtr = useRegister(ins->exnRefsPtr());
6538 define(new (alloc()) LWasmLoadExceptionRefsValue(refsPtr), ins);
6541 // End Wasm Exception Handling
6543 static_assert(!std::is_polymorphic_v<LIRGenerator>,
6544 "LIRGenerator should not have any virtual methods");
6546 #ifdef JS_CODEGEN_NONE
6547 void LIRGenerator::visitReturnImpl(MDefinition*, bool) { MOZ_CRASH(); }
6548 #endif