Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / jit / Lowering.cpp
blobca3fe7a2f6f70dd0c21a72594b10d92820bed5f7
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/IonGenericCallStub.h"
18 #include "jit/IonOptimizationLevels.h"
19 #include "jit/JitSpewer.h"
20 #include "jit/LIR.h"
21 #include "jit/MacroAssembler.h"
22 #include "jit/MIR.h"
23 #include "jit/MIRGraph.h"
24 #include "jit/SharedICRegisters.h"
25 #include "js/experimental/JitInfo.h" // JSJitInfo
26 #include "util/Memory.h"
27 #include "wasm/WasmCodegenTypes.h"
28 #include "wasm/WasmFeatures.h" // for wasm::ReportSimdAnalysis
29 #include "wasm/WasmInstanceData.h"
31 #include "jit/shared/Lowering-shared-inl.h"
32 #include "vm/BytecodeUtil-inl.h"
34 using namespace js;
35 using namespace jit;
37 using JS::GenericNaN;
38 using mozilla::DebugOnly;
40 LBoxAllocation LIRGenerator::useBoxFixedAtStart(MDefinition* mir,
41 ValueOperand op) {
42 #if defined(JS_NUNBOX32)
43 return useBoxFixed(mir, op.typeReg(), op.payloadReg(), true);
44 #elif defined(JS_PUNBOX64)
45 return useBoxFixed(mir, op.valueReg(), op.scratchReg(), true);
46 #endif
49 LBoxAllocation LIRGenerator::useBoxAtStart(MDefinition* mir,
50 LUse::Policy policy) {
51 return useBox(mir, policy, /* useAtStart = */ true);
54 void LIRGenerator::visitParameter(MParameter* param) {
55 ptrdiff_t offset;
56 if (param->index() == MParameter::THIS_SLOT) {
57 offset = THIS_FRAME_ARGSLOT;
58 } else {
59 offset = 1 + param->index();
62 LParameter* ins = new (alloc()) LParameter;
63 defineBox(ins, param, LDefinition::FIXED);
65 offset *= sizeof(Value);
66 #if defined(JS_NUNBOX32)
67 # if MOZ_BIG_ENDIAN()
68 ins->getDef(0)->setOutput(LArgument(offset));
69 ins->getDef(1)->setOutput(LArgument(offset + 4));
70 # else
71 ins->getDef(0)->setOutput(LArgument(offset + 4));
72 ins->getDef(1)->setOutput(LArgument(offset));
73 # endif
74 #elif defined(JS_PUNBOX64)
75 ins->getDef(0)->setOutput(LArgument(offset));
76 #endif
79 void LIRGenerator::visitCallee(MCallee* ins) {
80 define(new (alloc()) LCallee(), ins);
83 void LIRGenerator::visitIsConstructing(MIsConstructing* ins) {
84 define(new (alloc()) LIsConstructing(), ins);
87 void LIRGenerator::visitGoto(MGoto* ins) {
88 add(new (alloc()) LGoto(ins->target()));
91 void LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch) {
92 MDefinition* opd = tableswitch->getOperand(0);
94 // There should be at least 1 successor. The default case!
95 MOZ_ASSERT(tableswitch->numSuccessors() > 0);
97 // If there are no cases, the default case is always taken.
98 if (tableswitch->numSuccessors() == 1) {
99 add(new (alloc()) LGoto(tableswitch->getDefault()));
100 return;
103 // If we don't know the type.
104 if (opd->type() == MIRType::Value) {
105 LTableSwitchV* lir = newLTableSwitchV(tableswitch);
106 add(lir);
107 return;
110 // Case indices are numeric, so other types will always go to the default
111 // case.
112 if (opd->type() != MIRType::Int32 && opd->type() != MIRType::Double) {
113 add(new (alloc()) LGoto(tableswitch->getDefault()));
114 return;
117 // Return an LTableSwitch, capable of handling either an integer or
118 // floating-point index.
119 LAllocation index;
120 LDefinition tempInt;
121 if (opd->type() == MIRType::Int32) {
122 index = useRegisterAtStart(opd);
123 tempInt = tempCopy(opd, 0);
124 } else {
125 index = useRegister(opd);
126 tempInt = temp(LDefinition::GENERAL);
128 add(newLTableSwitch(index, tempInt, tableswitch));
131 void LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed* ins) {
132 LCheckOverRecursed* lir = new (alloc()) LCheckOverRecursed();
133 add(lir, ins);
134 assignSafepoint(lir, ins);
137 void LIRGenerator::visitNewArray(MNewArray* ins) {
138 LNewArray* lir = new (alloc()) LNewArray(temp());
139 define(lir, ins);
140 assignSafepoint(lir, ins);
143 void LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength* ins) {
144 MDefinition* length = ins->length();
145 MOZ_ASSERT(length->type() == MIRType::Int32);
147 LNewArrayDynamicLength* lir =
148 new (alloc()) LNewArrayDynamicLength(useRegister(length), temp());
149 define(lir, ins);
150 assignSafepoint(lir, ins);
153 void LIRGenerator::visitNewIterator(MNewIterator* ins) {
154 LNewIterator* lir = new (alloc()) LNewIterator(temp());
155 define(lir, ins);
156 assignSafepoint(lir, ins);
159 void LIRGenerator::visitNewTypedArray(MNewTypedArray* ins) {
160 LNewTypedArray* lir = new (alloc()) LNewTypedArray(temp(), temp());
161 define(lir, ins);
162 assignSafepoint(lir, ins);
165 void LIRGenerator::visitNewTypedArrayDynamicLength(
166 MNewTypedArrayDynamicLength* ins) {
167 MDefinition* length = ins->length();
168 MOZ_ASSERT(length->type() == MIRType::Int32);
170 LNewTypedArrayDynamicLength* lir =
171 new (alloc()) LNewTypedArrayDynamicLength(useRegister(length), temp());
172 define(lir, ins);
173 assignSafepoint(lir, ins);
176 void LIRGenerator::visitNewTypedArrayFromArray(MNewTypedArrayFromArray* ins) {
177 MDefinition* array = ins->array();
178 MOZ_ASSERT(array->type() == MIRType::Object);
180 auto* lir = new (alloc()) LNewTypedArrayFromArray(useRegisterAtStart(array));
181 defineReturn(lir, ins);
182 assignSafepoint(lir, ins);
185 void LIRGenerator::visitNewTypedArrayFromArrayBuffer(
186 MNewTypedArrayFromArrayBuffer* ins) {
187 MDefinition* arrayBuffer = ins->arrayBuffer();
188 MDefinition* byteOffset = ins->byteOffset();
189 MDefinition* length = ins->length();
190 MOZ_ASSERT(arrayBuffer->type() == MIRType::Object);
191 MOZ_ASSERT(byteOffset->type() == MIRType::Value);
192 MOZ_ASSERT(length->type() == MIRType::Value);
194 auto* lir = new (alloc()) LNewTypedArrayFromArrayBuffer(
195 useRegisterAtStart(arrayBuffer), useBoxAtStart(byteOffset),
196 useBoxAtStart(length));
197 defineReturn(lir, ins);
198 assignSafepoint(lir, ins);
201 void LIRGenerator::visitNewObject(MNewObject* ins) {
202 LNewObject* lir = new (alloc()) LNewObject(temp());
203 define(lir, ins);
204 assignSafepoint(lir, ins);
207 void LIRGenerator::visitBindFunction(MBindFunction* ins) {
208 MDefinition* target = ins->target();
209 MOZ_ASSERT(target->type() == MIRType::Object);
211 if (!lowerCallArguments(ins)) {
212 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitBindFunction");
213 return;
216 auto* lir = new (alloc())
217 LBindFunction(useFixedAtStart(target, CallTempReg0),
218 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
219 defineReturn(lir, ins);
220 assignSafepoint(lir, ins);
223 void LIRGenerator::visitNewBoundFunction(MNewBoundFunction* ins) {
224 auto* lir = new (alloc()) LNewBoundFunction(temp());
225 define(lir, ins);
226 assignSafepoint(lir, ins);
229 void LIRGenerator::visitNewPlainObject(MNewPlainObject* ins) {
230 LNewPlainObject* lir = new (alloc()) LNewPlainObject(temp(), temp(), temp());
231 define(lir, ins);
232 assignSafepoint(lir, ins);
235 void LIRGenerator::visitNewArrayObject(MNewArrayObject* ins) {
236 LNewArrayObject* lir = new (alloc()) LNewArrayObject(temp(), temp());
237 define(lir, ins);
238 assignSafepoint(lir, ins);
241 void LIRGenerator::visitNewNamedLambdaObject(MNewNamedLambdaObject* ins) {
242 LNewNamedLambdaObject* lir = new (alloc()) LNewNamedLambdaObject(temp());
243 define(lir, ins);
244 assignSafepoint(lir, ins);
247 void LIRGenerator::visitNewCallObject(MNewCallObject* ins) {
248 LNewCallObject* lir = new (alloc()) LNewCallObject(temp());
249 define(lir, ins);
250 assignSafepoint(lir, ins);
253 void LIRGenerator::visitNewStringObject(MNewStringObject* ins) {
254 MOZ_ASSERT(ins->input()->type() == MIRType::String);
256 LNewStringObject* lir =
257 new (alloc()) LNewStringObject(useRegister(ins->input()), temp());
258 define(lir, ins);
259 assignSafepoint(lir, ins);
262 void LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter* ins) {
263 LInitElemGetterSetter* lir = new (alloc()) LInitElemGetterSetter(
264 useRegisterAtStart(ins->object()), useBoxAtStart(ins->id()),
265 useRegisterAtStart(ins->value()));
266 add(lir, ins);
267 assignSafepoint(lir, ins);
270 void LIRGenerator::visitMutateProto(MMutateProto* ins) {
271 LMutateProto* lir = new (alloc()) LMutateProto(
272 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
273 add(lir, ins);
274 assignSafepoint(lir, ins);
277 void LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter* ins) {
278 LInitPropGetterSetter* lir = new (alloc()) LInitPropGetterSetter(
279 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->value()));
280 add(lir, ins);
281 assignSafepoint(lir, ins);
284 void LIRGenerator::visitCreateThis(MCreateThis* ins) {
285 LCreateThis* lir =
286 new (alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->callee()),
287 useRegisterOrConstantAtStart(ins->newTarget()));
288 defineReturn(lir, ins);
289 assignSafepoint(lir, ins);
292 void LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject* ins) {
293 LAllocation callObj = useRegisterAtStart(ins->getCallObject());
294 LCreateArgumentsObject* lir = new (alloc())
295 LCreateArgumentsObject(callObj, tempFixed(CallTempReg0),
296 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
297 defineReturn(lir, ins);
298 assignSafepoint(lir, ins);
301 void LIRGenerator::visitCreateInlinedArgumentsObject(
302 MCreateInlinedArgumentsObject* ins) {
303 LAllocation callObj = useRegisterAtStart(ins->getCallObject());
304 LAllocation callee = useRegisterAtStart(ins->getCallee());
305 uint32_t numActuals = ins->numActuals();
306 uint32_t numOperands = numActuals * BOX_PIECES +
307 LCreateInlinedArgumentsObject::NumNonArgumentOperands;
309 auto* lir = allocateVariadic<LCreateInlinedArgumentsObject>(
310 numOperands, tempFixed(CallTempReg0), tempFixed(CallTempReg1));
311 if (!lir) {
312 abort(AbortReason::Alloc,
313 "OOM: LIRGenerator::visitCreateInlinedArgumentsObject");
314 return;
317 lir->setOperand(LCreateInlinedArgumentsObject::CallObj, callObj);
318 lir->setOperand(LCreateInlinedArgumentsObject::Callee, callee);
319 for (uint32_t i = 0; i < numActuals; i++) {
320 MDefinition* arg = ins->getArg(i);
321 uint32_t index = LCreateInlinedArgumentsObject::ArgIndex(i);
322 lir->setBoxOperand(index, useBoxOrTypedOrConstant(arg,
323 /*useConstant = */ true,
324 /*useAtStart = */ true));
327 defineReturn(lir, ins);
328 assignSafepoint(lir, ins);
331 void LIRGenerator::visitGetInlinedArgument(MGetInlinedArgument* ins) {
332 #if defined(JS_PUNBOX64)
333 // On 64-bit architectures, we don't support boxing a typed register
334 // in-place without using a scratch register, so the result register
335 // can't be the same as any of the inputs. Fortunately, those
336 // architectures have registers to spare.
337 const bool useAtStart = false;
338 #else
339 const bool useAtStart = true;
340 #endif
342 LAllocation index =
343 useAtStart ? useRegisterAtStart(ins->index()) : useRegister(ins->index());
344 uint32_t numActuals = ins->numActuals();
345 uint32_t numOperands =
346 numActuals * BOX_PIECES + LGetInlinedArgument::NumNonArgumentOperands;
348 auto* lir = allocateVariadic<LGetInlinedArgument>(numOperands);
349 if (!lir) {
350 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgument");
351 return;
354 lir->setOperand(LGetInlinedArgument::Index, index);
355 for (uint32_t i = 0; i < numActuals; i++) {
356 MDefinition* arg = ins->getArg(i);
357 uint32_t index = LGetInlinedArgument::ArgIndex(i);
358 lir->setBoxOperand(
359 index, useBoxOrTypedOrConstant(arg,
360 /*useConstant = */ true, useAtStart));
362 defineBox(lir, ins);
365 void LIRGenerator::visitGetInlinedArgumentHole(MGetInlinedArgumentHole* ins) {
366 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_MIPS64)
367 // On some 64-bit architectures, we don't support boxing a typed
368 // register in-place without using a scratch register, so the result
369 // register can't be the same as any of the inputs. Fortunately,
370 // those architectures have registers to spare.
371 const bool useAtStart = false;
372 #else
373 const bool useAtStart = true;
374 #endif
376 LAllocation index =
377 useAtStart ? useRegisterAtStart(ins->index()) : useRegister(ins->index());
378 uint32_t numActuals = ins->numActuals();
379 uint32_t numOperands =
380 numActuals * BOX_PIECES + LGetInlinedArgumentHole::NumNonArgumentOperands;
382 auto* lir = allocateVariadic<LGetInlinedArgumentHole>(numOperands);
383 if (!lir) {
384 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgumentHole");
385 return;
388 lir->setOperand(LGetInlinedArgumentHole::Index, index);
389 for (uint32_t i = 0; i < numActuals; i++) {
390 MDefinition* arg = ins->getArg(i);
391 uint32_t index = LGetInlinedArgumentHole::ArgIndex(i);
392 lir->setBoxOperand(
393 index, useBoxOrTypedOrConstant(arg,
394 /*useConstant = */ true, useAtStart));
396 assignSnapshot(lir, ins->bailoutKind());
397 defineBox(lir, ins);
400 void LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins) {
401 LAllocation argsObj = useRegister(ins->argsObject());
402 LGetArgumentsObjectArg* lir =
403 new (alloc()) LGetArgumentsObjectArg(argsObj, temp());
404 defineBox(lir, ins);
407 void LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins) {
408 LAllocation argsObj = useRegister(ins->argsObject());
409 LSetArgumentsObjectArg* lir = new (alloc())
410 LSetArgumentsObjectArg(argsObj, useBox(ins->value()), temp());
411 add(lir, ins);
414 void LIRGenerator::visitLoadArgumentsObjectArg(MLoadArgumentsObjectArg* ins) {
415 MDefinition* argsObj = ins->argsObject();
416 MOZ_ASSERT(argsObj->type() == MIRType::Object);
418 MDefinition* index = ins->index();
419 MOZ_ASSERT(index->type() == MIRType::Int32);
421 auto* lir = new (alloc())
422 LLoadArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp());
423 assignSnapshot(lir, ins->bailoutKind());
424 defineBox(lir, ins);
427 void LIRGenerator::visitLoadArgumentsObjectArgHole(
428 MLoadArgumentsObjectArgHole* ins) {
429 MDefinition* argsObj = ins->argsObject();
430 MOZ_ASSERT(argsObj->type() == MIRType::Object);
432 MDefinition* index = ins->index();
433 MOZ_ASSERT(index->type() == MIRType::Int32);
435 auto* lir = new (alloc()) LLoadArgumentsObjectArgHole(
436 useRegister(argsObj), useRegister(index), temp());
437 assignSnapshot(lir, ins->bailoutKind());
438 defineBox(lir, ins);
441 void LIRGenerator::visitInArgumentsObjectArg(MInArgumentsObjectArg* ins) {
442 MDefinition* argsObj = ins->argsObject();
443 MOZ_ASSERT(argsObj->type() == MIRType::Object);
445 MDefinition* index = ins->index();
446 MOZ_ASSERT(index->type() == MIRType::Int32);
448 auto* lir = new (alloc())
449 LInArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp());
450 assignSnapshot(lir, ins->bailoutKind());
451 define(lir, ins);
454 void LIRGenerator::visitArgumentsObjectLength(MArgumentsObjectLength* ins) {
455 MDefinition* argsObj = ins->argsObject();
456 MOZ_ASSERT(argsObj->type() == MIRType::Object);
458 auto* lir = new (alloc()) LArgumentsObjectLength(useRegister(argsObj));
459 assignSnapshot(lir, ins->bailoutKind());
460 define(lir, ins);
463 void LIRGenerator::visitArrayFromArgumentsObject(
464 MArrayFromArgumentsObject* ins) {
465 MDefinition* argsObj = ins->argsObject();
466 MOZ_ASSERT(argsObj->type() == MIRType::Object);
468 auto* lir =
469 new (alloc()) LArrayFromArgumentsObject(useRegisterAtStart(argsObj));
470 defineReturn(lir, ins);
471 assignSafepoint(lir, ins);
474 void LIRGenerator::visitGuardArgumentsObjectFlags(
475 MGuardArgumentsObjectFlags* ins) {
476 MDefinition* argsObj = ins->argsObject();
477 MOZ_ASSERT(argsObj->type() == MIRType::Object);
479 auto* lir =
480 new (alloc()) LGuardArgumentsObjectFlags(useRegister(argsObj), temp());
481 assignSnapshot(lir, ins->bailoutKind());
482 add(lir, ins);
483 redefine(ins, argsObj);
486 void LIRGenerator::visitBoundFunctionNumArgs(MBoundFunctionNumArgs* ins) {
487 MDefinition* obj = ins->object();
488 MOZ_ASSERT(obj->type() == MIRType::Object);
490 auto* lir = new (alloc()) LBoundFunctionNumArgs(useRegisterAtStart(obj));
491 define(lir, ins);
494 void LIRGenerator::visitGuardBoundFunctionIsConstructor(
495 MGuardBoundFunctionIsConstructor* ins) {
496 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
498 auto* lir = new (alloc())
499 LGuardBoundFunctionIsConstructor(useRegister(ins->object()));
500 assignSnapshot(lir, ins->bailoutKind());
501 add(lir, ins);
502 redefine(ins, ins->object());
505 void LIRGenerator::visitReturnFromCtor(MReturnFromCtor* ins) {
506 LReturnFromCtor* lir = new (alloc())
507 LReturnFromCtor(useBox(ins->value()), useRegister(ins->object()));
508 define(lir, ins);
511 void LIRGenerator::visitBoxNonStrictThis(MBoxNonStrictThis* ins) {
512 MOZ_ASSERT(ins->type() == MIRType::Object);
513 MOZ_ASSERT(ins->input()->type() == MIRType::Value);
515 auto* lir = new (alloc()) LBoxNonStrictThis(useBox(ins->input()));
516 define(lir, ins);
517 assignSafepoint(lir, ins);
520 void LIRGenerator::visitImplicitThis(MImplicitThis* ins) {
521 MDefinition* env = ins->envChain();
522 MOZ_ASSERT(env->type() == MIRType::Object);
524 LImplicitThis* lir = new (alloc()) LImplicitThis(useRegisterAtStart(env));
525 defineReturn(lir, ins);
526 assignSafepoint(lir, ins);
529 template <typename T>
530 bool LIRGenerator::lowerCallArguments(T* call) {
531 uint32_t argc = call->numStackArgs();
533 // Align the arguments of a call such that the callee would keep the same
534 // alignment as the caller.
535 uint32_t baseSlot = 0;
536 if (JitStackValueAlignment > 1) {
537 baseSlot = AlignBytes(argc, JitStackValueAlignment);
538 } else {
539 baseSlot = argc;
542 // Save the maximum number of argument, such that we can have one unique
543 // frame size.
544 if (baseSlot > maxargslots_) {
545 maxargslots_ = baseSlot;
548 for (size_t i = 0; i < argc; i++) {
549 MDefinition* arg = call->getArg(i);
550 uint32_t argslot = baseSlot - i;
552 // Values take a slow path.
553 if (arg->type() == MIRType::Value) {
554 LStackArgV* stack = new (alloc()) LStackArgV(useBox(arg), argslot);
555 add(stack);
556 } else {
557 // Known types can move constant types and/or payloads.
558 LStackArgT* stack = new (alloc())
559 LStackArgT(useRegisterOrConstant(arg), argslot, arg->type());
560 add(stack);
563 if (!alloc().ensureBallast()) {
564 return false;
567 return true;
570 void LIRGenerator::visitCall(MCall* call) {
571 MOZ_ASSERT(call->getCallee()->type() == MIRType::Object);
573 // In case of oom, skip the rest of the allocations.
574 if (!lowerCallArguments(call)) {
575 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCall");
576 return;
579 WrappedFunction* target = call->getSingleTarget();
581 LInstruction* lir;
583 if (call->isCallDOMNative()) {
584 // Call DOM functions.
585 MOZ_ASSERT(target && target->isNativeWithoutJitEntry());
586 Register cxReg, objReg, privReg, argsReg;
587 GetTempRegForIntArg(0, 0, &cxReg);
588 GetTempRegForIntArg(1, 0, &objReg);
589 GetTempRegForIntArg(2, 0, &privReg);
590 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &argsReg);
591 MOZ_ASSERT(ok, "How can we not have four temp registers?");
592 lir = new (alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg),
593 tempFixed(privReg), tempFixed(argsReg));
594 } else if (target) {
595 // Call known functions.
596 if (target->isNativeWithoutJitEntry()) {
597 Register cxReg, numReg, vpReg, tmpReg;
598 GetTempRegForIntArg(0, 0, &cxReg);
599 GetTempRegForIntArg(1, 0, &numReg);
600 GetTempRegForIntArg(2, 0, &vpReg);
602 // Even though this is just a temp reg, use the same API to avoid
603 // register collisions.
604 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
605 MOZ_ASSERT(ok, "How can we not have four temp registers?");
607 lir = new (alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
608 tempFixed(vpReg), tempFixed(tmpReg));
609 } else {
610 lir = new (alloc()) LCallKnown(useRegisterAtStart(call->getCallee()),
611 tempFixed(CallTempReg0));
613 } else {
614 // Call anything, using the most generic code.
615 lir = new (alloc()) LCallGeneric(
616 useFixedAtStart(call->getCallee(), IonGenericCallCalleeReg),
617 tempFixed(IonGenericCallArgcReg));
619 defineReturn(lir, call);
620 assignSafepoint(lir, call);
623 void LIRGenerator::visitCallClassHook(MCallClassHook* call) {
624 MDefinition* callee = call->getCallee();
625 MOZ_ASSERT(callee->type() == MIRType::Object);
627 // In case of oom, skip the rest of the allocations.
628 if (!lowerCallArguments(call)) {
629 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCallClassHook");
630 return;
633 Register cxReg, numReg, vpReg, tmpReg;
634 GetTempRegForIntArg(0, 0, &cxReg);
635 GetTempRegForIntArg(1, 0, &numReg);
636 GetTempRegForIntArg(2, 0, &vpReg);
638 // Even though this is just a temp reg, use the same API to avoid
639 // register collisions.
640 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
641 MOZ_ASSERT(ok, "How can we not have four temp registers?");
643 auto* lir = new (alloc())
644 LCallClassHook(useRegisterAtStart(callee), tempFixed(cxReg),
645 tempFixed(numReg), tempFixed(vpReg), tempFixed(tmpReg));
646 defineReturn(lir, call);
647 assignSafepoint(lir, call);
650 void LIRGenerator::visitApplyArgs(MApplyArgs* apply) {
651 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
653 // Assert if the return value is already erased.
654 static_assert(CallTempReg2 != JSReturnReg_Type);
655 static_assert(CallTempReg2 != JSReturnReg_Data);
657 LApplyArgsGeneric* lir = new (alloc()) LApplyArgsGeneric(
658 useFixedAtStart(apply->getFunction(), CallTempReg3),
659 useFixedAtStart(apply->getArgc(), CallTempReg0),
660 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
661 tempFixed(CallTempReg1), // object register
662 tempFixed(CallTempReg2)); // stack counter register
664 // Bailout is needed in the case of too many values in the arguments array.
665 assignSnapshot(lir, apply->bailoutKind());
667 defineReturn(lir, apply);
668 assignSafepoint(lir, apply);
671 void LIRGenerator::visitApplyArgsObj(MApplyArgsObj* apply) {
672 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
674 // Assert if the return value is already erased.
675 static_assert(CallTempReg2 != JSReturnReg_Type);
676 static_assert(CallTempReg2 != JSReturnReg_Data);
678 LApplyArgsObj* lir = new (alloc()) LApplyArgsObj(
679 useFixedAtStart(apply->getFunction(), CallTempReg3),
680 useFixedAtStart(apply->getArgsObj(), CallTempReg0),
681 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
682 tempFixed(CallTempReg1), // object register
683 tempFixed(CallTempReg2)); // stack counter register
685 // Bailout is needed in the case of too many values in the arguments array.
686 assignSnapshot(lir, apply->bailoutKind());
688 defineReturn(lir, apply);
689 assignSafepoint(lir, apply);
692 void LIRGenerator::visitApplyArray(MApplyArray* apply) {
693 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
695 // Assert if the return value is already erased.
696 static_assert(CallTempReg2 != JSReturnReg_Type);
697 static_assert(CallTempReg2 != JSReturnReg_Data);
699 LApplyArrayGeneric* lir = new (alloc()) LApplyArrayGeneric(
700 useFixedAtStart(apply->getFunction(), CallTempReg3),
701 useFixedAtStart(apply->getElements(), CallTempReg0),
702 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
703 tempFixed(CallTempReg1), // object register
704 tempFixed(CallTempReg2)); // stack counter register
706 // Bailout is needed in the case of too many values in the array, or empty
707 // space at the end of the array.
708 assignSnapshot(lir, apply->bailoutKind());
710 defineReturn(lir, apply);
711 assignSafepoint(lir, apply);
714 void LIRGenerator::visitConstructArgs(MConstructArgs* mir) {
715 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
716 MOZ_ASSERT(mir->getArgc()->type() == MIRType::Int32);
717 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
718 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
720 // Assert if the return value is already erased.
721 static_assert(CallTempReg2 != JSReturnReg_Type);
722 static_assert(CallTempReg2 != JSReturnReg_Data);
724 auto* lir = new (alloc()) LConstructArgsGeneric(
725 useFixedAtStart(mir->getFunction(), CallTempReg3),
726 useFixedAtStart(mir->getArgc(), CallTempReg0),
727 useFixedAtStart(mir->getNewTarget(), CallTempReg1),
728 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5),
729 tempFixed(CallTempReg2));
731 // Bailout is needed in the case of too many values in the arguments array.
732 assignSnapshot(lir, mir->bailoutKind());
734 defineReturn(lir, mir);
735 assignSafepoint(lir, mir);
738 void LIRGenerator::visitConstructArray(MConstructArray* mir) {
739 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
740 MOZ_ASSERT(mir->getElements()->type() == MIRType::Elements);
741 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
742 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
744 // Assert if the return value is already erased.
745 static_assert(CallTempReg2 != JSReturnReg_Type);
746 static_assert(CallTempReg2 != JSReturnReg_Data);
748 auto* lir = new (alloc()) LConstructArrayGeneric(
749 useFixedAtStart(mir->getFunction(), CallTempReg3),
750 useFixedAtStart(mir->getElements(), CallTempReg0),
751 useFixedAtStart(mir->getNewTarget(), CallTempReg1),
752 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5),
753 tempFixed(CallTempReg2));
755 // Bailout is needed in the case of too many values in the array, or empty
756 // space at the end of the array.
757 assignSnapshot(lir, mir->bailoutKind());
759 defineReturn(lir, mir);
760 assignSafepoint(lir, mir);
763 void LIRGenerator::visitBail(MBail* bail) {
764 LBail* lir = new (alloc()) LBail();
765 assignSnapshot(lir, bail->bailoutKind());
766 add(lir, bail);
769 void LIRGenerator::visitUnreachable(MUnreachable* unreachable) {
770 LUnreachable* lir = new (alloc()) LUnreachable();
771 add(lir, unreachable);
774 void LIRGenerator::visitEncodeSnapshot(MEncodeSnapshot* mir) {
775 LEncodeSnapshot* lir = new (alloc()) LEncodeSnapshot();
776 assignSnapshot(lir, mir->bailoutKind());
777 add(lir, mir);
780 void LIRGenerator::visitUnreachableResult(MUnreachableResult* mir) {
781 if (mir->type() == MIRType::Value) {
782 auto* lir = new (alloc()) LUnreachableResultV();
783 defineBox(lir, mir);
784 } else {
785 auto* lir = new (alloc()) LUnreachableResultT();
786 define(lir, mir);
790 void LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion) {
791 MIRType type = assertion->input()->type();
792 DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
794 if (type != MIRType::Value && !JitOptions.eagerIonCompilation()) {
795 MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32);
796 MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32);
800 void LIRGenerator::visitAssertRecoveredOnBailout(
801 MAssertRecoveredOnBailout* assertion) {
802 MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
805 [[nodiscard]] static JSOp ReorderComparison(JSOp op, MDefinition** lhsp,
806 MDefinition** rhsp) {
807 MDefinition* lhs = *lhsp;
808 MDefinition* rhs = *rhsp;
810 if (lhs->maybeConstantValue()) {
811 *rhsp = lhs;
812 *lhsp = rhs;
813 return ReverseCompareOp(op);
815 return op;
818 void LIRGenerator::visitTest(MTest* test) {
819 MDefinition* opd = test->getOperand(0);
820 MBasicBlock* ifTrue = test->ifTrue();
821 MBasicBlock* ifFalse = test->ifFalse();
823 // String is converted to length of string in the type analysis phase (see
824 // TestPolicy).
825 MOZ_ASSERT(opd->type() != MIRType::String);
827 // Testing a constant.
828 if (MConstant* constant = opd->maybeConstantValue()) {
829 bool b;
830 if (constant->valueToBoolean(&b)) {
831 add(new (alloc()) LGoto(b ? ifTrue : ifFalse));
832 return;
836 if (opd->type() == MIRType::Value) {
837 auto* lir = new (alloc()) LTestVAndBranch(
838 ifTrue, ifFalse, useBox(opd), tempDouble(), tempToUnbox(), temp());
839 add(lir, test);
840 return;
843 // Objects are truthy, except if it might emulate undefined.
844 if (opd->type() == MIRType::Object) {
845 add(new (alloc())
846 LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()),
847 test);
848 return;
851 // These must be explicitly sniffed out since they are constants and have
852 // no payload.
853 if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) {
854 add(new (alloc()) LGoto(ifFalse));
855 return;
858 // All symbols are truthy.
859 if (opd->type() == MIRType::Symbol) {
860 add(new (alloc()) LGoto(ifTrue));
861 return;
864 // Try to match the pattern
865 // test=MTest(
866 // comp=MCompare(
867 // {EQ,NE} for {Int,UInt}{32,64},
868 // bitAnd={MBitAnd,MWasmBinaryBitwise(And{32,64})}(x, y),
869 // MConstant(0)
870 // )
871 // )
872 // and produce a single LBitAndAndBranch node. This requires both `comp`
873 // and `bitAnd` to be marked emit-at-uses. Since we can't use
874 // LBitAndAndBranch to represent a 64-bit AND on a 32-bit target, the 64-bit
875 // case is restricted to 64-bit targets.
876 if (opd->isCompare() && opd->isEmittedAtUses()) {
877 #ifdef JS_64BIT
878 constexpr bool targetIs64 = true;
879 #else
880 constexpr bool targetIs64 = false;
881 #endif
882 MCompare* comp = opd->toCompare();
883 Assembler::Condition compCond =
884 JSOpToCondition(comp->compareType(), comp->jsop());
885 MDefinition* compL = comp->getOperand(0);
886 MDefinition* compR = comp->getOperand(1);
887 if ((comp->compareType() == MCompare::Compare_Int32 ||
888 comp->compareType() == MCompare::Compare_UInt32 ||
889 (targetIs64 && comp->compareType() == MCompare::Compare_Int64) ||
890 (targetIs64 && comp->compareType() == MCompare::Compare_UInt64)) &&
891 (compCond == Assembler::Equal || compCond == Assembler::NotEqual) &&
892 compR->isConstant() &&
893 (compR->toConstant()->isInt32(0) ||
894 (targetIs64 && compR->toConstant()->isInt64(0))) &&
895 (compL->isBitAnd() || (compL->isWasmBinaryBitwise() &&
896 compL->toWasmBinaryBitwise()->subOpcode() ==
897 MWasmBinaryBitwise::SubOpcode::And))) {
898 // The MCompare is OK; now check its first operand (the and-ish node).
899 MDefinition* bitAnd = compL;
900 MDefinition* bitAndL = bitAnd->getOperand(0);
901 MDefinition* bitAndR = bitAnd->getOperand(1);
902 MIRType bitAndLTy = bitAndL->type();
903 MIRType bitAndRTy = bitAndR->type();
904 if (bitAnd->isEmittedAtUses() && bitAndLTy == bitAndRTy &&
905 (bitAndLTy == MIRType::Int32 ||
906 (targetIs64 && bitAndLTy == MIRType::Int64))) {
907 // Pattern match succeeded.
908 ReorderCommutative(&bitAndL, &bitAndR, test);
909 if (compCond == Assembler::Equal) {
910 compCond = Assembler::Zero;
911 } else if (compCond == Assembler::NotEqual) {
912 compCond = Assembler::NonZero;
913 } else {
914 MOZ_ASSERT_UNREACHABLE("inequality operators cannot be folded");
916 MOZ_ASSERT_IF(!targetIs64, bitAndLTy == MIRType::Int32);
917 lowerForBitAndAndBranch(
918 new (alloc()) LBitAndAndBranch(
919 ifTrue, ifFalse, bitAndLTy == MIRType::Int64, compCond),
920 test, bitAndL, bitAndR);
921 return;
926 // Check if the operand for this test is a compare operation. If it is, we
927 // want to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse
928 // the compare and jump instructions.
929 if (opd->isCompare() && opd->isEmittedAtUses()) {
930 MCompare* comp = opd->toCompare();
931 MDefinition* left = comp->lhs();
932 MDefinition* right = comp->rhs();
934 // Try to fold the comparison so that we don't have to handle all cases.
935 bool result;
936 if (comp->tryFold(&result)) {
937 add(new (alloc()) LGoto(result ? ifTrue : ifFalse));
938 return;
941 // Emit LCompare*AndBranch.
943 // Compare and branch null/undefined.
944 // The second operand has known null/undefined type,
945 // so just test the first operand.
946 if (comp->compareType() == MCompare::Compare_Null ||
947 comp->compareType() == MCompare::Compare_Undefined) {
948 if (left->type() == MIRType::Object) {
949 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchT(
950 comp, useRegister(left), ifTrue, ifFalse, temp());
951 add(lir, test);
952 return;
955 if (IsLooseEqualityOp(comp->jsop())) {
956 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchV(
957 comp, ifTrue, ifFalse, useBox(left), temp(), tempToUnbox());
958 add(lir, test);
959 return;
962 if (comp->compareType() == MCompare::Compare_Null) {
963 auto* lir =
964 new (alloc()) LIsNullAndBranch(comp, ifTrue, ifFalse, useBox(left));
965 add(lir, test);
966 return;
969 auto* lir = new (alloc())
970 LIsUndefinedAndBranch(comp, ifTrue, ifFalse, useBox(left));
971 add(lir, test);
972 return;
975 // Compare and branch Int32, Symbol, Object, or WasmAnyRef pointers.
976 if (comp->isInt32Comparison() ||
977 comp->compareType() == MCompare::Compare_UInt32 ||
978 comp->compareType() == MCompare::Compare_UIntPtr ||
979 comp->compareType() == MCompare::Compare_Object ||
980 comp->compareType() == MCompare::Compare_Symbol ||
981 comp->compareType() == MCompare::Compare_WasmAnyRef) {
982 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
983 LAllocation lhs = useRegister(left);
984 LAllocation rhs;
985 if (comp->isInt32Comparison() ||
986 comp->compareType() == MCompare::Compare_UInt32 ||
987 comp->compareType() == MCompare::Compare_UIntPtr) {
988 rhs = useAnyOrInt32Constant(right);
989 } else {
990 rhs = useAny(right);
992 LCompareAndBranch* lir =
993 new (alloc()) LCompareAndBranch(comp, op, lhs, rhs, ifTrue, ifFalse);
994 add(lir, test);
995 return;
998 // Compare and branch Int64.
999 if (comp->compareType() == MCompare::Compare_Int64 ||
1000 comp->compareType() == MCompare::Compare_UInt64) {
1001 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1002 lowerForCompareI64AndBranch(test, comp, op, left, right, ifTrue, ifFalse);
1003 return;
1006 // Compare and branch doubles.
1007 if (comp->isDoubleComparison()) {
1008 LAllocation lhs = useRegister(left);
1009 LAllocation rhs = useRegister(right);
1010 LCompareDAndBranch* lir =
1011 new (alloc()) LCompareDAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
1012 add(lir, test);
1013 return;
1016 // Compare and branch floats.
1017 if (comp->isFloat32Comparison()) {
1018 LAllocation lhs = useRegister(left);
1019 LAllocation rhs = useRegister(right);
1020 LCompareFAndBranch* lir =
1021 new (alloc()) LCompareFAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
1022 add(lir, test);
1023 return;
1027 // Check if the operand for this test is a bitand operation. If it is, we want
1028 // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
1029 if (opd->isBitAnd() && opd->isEmittedAtUses()) {
1030 MDefinition* lhs = opd->getOperand(0);
1031 MDefinition* rhs = opd->getOperand(1);
1032 if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32) {
1033 ReorderCommutative(&lhs, &rhs, test);
1034 lowerForBitAndAndBranch(new (alloc()) LBitAndAndBranch(ifTrue, ifFalse,
1035 /*is64=*/false),
1036 test, lhs, rhs);
1037 return;
1041 #if defined(ENABLE_WASM_SIMD) && \
1042 (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || \
1043 defined(JS_CODEGEN_ARM64))
1044 // Check if the operand for this test is an any_true/all_true SIMD operation.
1045 // If it is, we want to emit an LWasmReduceAndBranchSimd128 node to avoid
1046 // generating an intermediate boolean result.
1047 if (opd->isWasmReduceSimd128() && opd->isEmittedAtUses()) {
1048 MWasmReduceSimd128* node = opd->toWasmReduceSimd128();
1049 if (canFoldReduceSimd128AndBranch(node->simdOp())) {
1050 # ifdef DEBUG
1051 js::wasm::ReportSimdAnalysis("simd128-to-scalar-and-branch -> folded");
1052 # endif
1053 auto* lir = new (alloc()) LWasmReduceAndBranchSimd128(
1054 useRegister(node->input()), node->simdOp(), ifTrue, ifFalse);
1055 add(lir, test);
1056 return;
1059 #endif
1061 if (opd->isIsObject() && opd->isEmittedAtUses()) {
1062 MDefinition* input = opd->toIsObject()->input();
1063 MOZ_ASSERT(input->type() == MIRType::Value);
1065 LIsObjectAndBranch* lir =
1066 new (alloc()) LIsObjectAndBranch(ifTrue, ifFalse, useBoxAtStart(input));
1067 add(lir, test);
1068 return;
1071 if (opd->isWasmRefIsSubtypeOfAbstract() && opd->isEmittedAtUses()) {
1072 MWasmRefIsSubtypeOfAbstract* isSubTypeOf =
1073 opd->toWasmRefIsSubtypeOfAbstract();
1074 LAllocation ref = useRegister(isSubTypeOf->ref());
1075 LDefinition scratch1 = LDefinition();
1076 if (isSubTypeOf->destType().isAnyHierarchy()) {
1077 // As in visitWasmRefIsSubtypeOfAbstract, we know we do not need
1078 // scratch2 and superSTV because we know this is not a
1079 // concrete type.
1080 scratch1 = MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
1081 isSubTypeOf->destType())
1082 ? temp()
1083 : LDefinition();
1084 } else if (isSubTypeOf->destType().isFuncHierarchy() ||
1085 isSubTypeOf->destType().isExternHierarchy()) {
1086 // scratch1 is not necessary for abstract casts in other hierarchies
1087 } else {
1088 MOZ_CRASH("unknown type hierarchy when folding abstract casts");
1091 add(new (alloc()) LWasmRefIsSubtypeOfAbstractAndBranch(
1092 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1093 ref, scratch1),
1094 test);
1095 return;
1098 if (opd->isWasmRefIsSubtypeOfConcrete() && opd->isEmittedAtUses()) {
1099 MWasmRefIsSubtypeOfConcrete* isSubTypeOf =
1100 opd->toWasmRefIsSubtypeOfConcrete();
1101 LAllocation ref = useRegister(isSubTypeOf->ref());
1102 LAllocation superSTV = useRegister(isSubTypeOf->superSTV());
1103 LDefinition scratch1 = LDefinition();
1104 LDefinition scratch2 = LDefinition();
1105 if (isSubTypeOf->destType().isAnyHierarchy()) {
1106 // As in visitWasmRefIsSubtypeOfConcrete, we know we need scratch1 because
1107 // we know this is a concrete type.
1108 scratch1 = temp();
1109 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
1110 isSubTypeOf->destType())
1111 ? temp()
1112 : LDefinition();
1113 } else if (isSubTypeOf->destType().isFuncHierarchy()) {
1114 // As in visitWasmRefIsSubtypeOfConcrete again...
1115 scratch1 = temp();
1116 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
1117 isSubTypeOf->destType())
1118 ? temp()
1119 : LDefinition();
1120 } else if (isSubTypeOf->destType().isExternHierarchy()) {
1121 MOZ_CRASH("concrete casts are not possible in the extern hierarchy");
1122 } else {
1123 MOZ_CRASH("unknown type hierarchy when folding abstract casts");
1126 add(new (alloc()) LWasmRefIsSubtypeOfConcreteAndBranch(
1127 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1128 ref, superSTV, scratch1, scratch2),
1129 test);
1130 return;
1133 if (opd->isIsNullOrUndefined() && opd->isEmittedAtUses()) {
1134 MIsNullOrUndefined* isNullOrUndefined = opd->toIsNullOrUndefined();
1135 MDefinition* input = isNullOrUndefined->value();
1137 if (input->type() == MIRType::Value) {
1138 auto* lir = new (alloc()) LIsNullOrUndefinedAndBranch(
1139 isNullOrUndefined, ifTrue, ifFalse, useBoxAtStart(input));
1140 add(lir, test);
1141 } else {
1142 auto* target = IsNullOrUndefined(input->type()) ? ifTrue : ifFalse;
1143 add(new (alloc()) LGoto(target));
1145 return;
1148 if (opd->isIsNoIter()) {
1149 MOZ_ASSERT(opd->isEmittedAtUses());
1151 MDefinition* input = opd->toIsNoIter()->input();
1152 MOZ_ASSERT(input->type() == MIRType::Value);
1154 LIsNoIterAndBranch* lir =
1155 new (alloc()) LIsNoIterAndBranch(ifTrue, ifFalse, useBox(input));
1156 add(lir, test);
1157 return;
1160 if (opd->isIteratorHasIndices()) {
1161 MOZ_ASSERT(opd->isEmittedAtUses());
1163 MDefinition* object = opd->toIteratorHasIndices()->object();
1164 MDefinition* iterator = opd->toIteratorHasIndices()->iterator();
1165 LIteratorHasIndicesAndBranch* lir = new (alloc())
1166 LIteratorHasIndicesAndBranch(ifTrue, ifFalse, useRegister(object),
1167 useRegister(iterator), temp(), temp());
1168 add(lir, test);
1169 return;
1172 switch (opd->type()) {
1173 case MIRType::Double:
1174 add(new (alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
1175 break;
1176 case MIRType::Float32:
1177 add(new (alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
1178 break;
1179 case MIRType::Int32:
1180 case MIRType::Boolean:
1181 add(new (alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
1182 break;
1183 case MIRType::Int64:
1184 add(new (alloc())
1185 LTestI64AndBranch(useInt64Register(opd), ifTrue, ifFalse));
1186 break;
1187 case MIRType::BigInt:
1188 add(new (alloc()) LTestBIAndBranch(useRegister(opd), ifTrue, ifFalse));
1189 break;
1190 default:
1191 MOZ_CRASH("Bad type");
1195 static inline bool CanEmitCompareAtUses(MInstruction* ins) {
1196 if (!ins->canEmitAtUses()) {
1197 return false;
1200 // If the result is never used, we can usefully defer emission to the use
1201 // point, since that will never happen.
1202 MUseIterator iter(ins->usesBegin());
1203 if (iter == ins->usesEnd()) {
1204 return true;
1207 // If the first use isn't of the expected form, the answer is No.
1208 MNode* node = iter->consumer();
1209 if (!node->isDefinition()) {
1210 return false;
1213 MDefinition* use = node->toDefinition();
1214 if (!use->isTest() && !use->isWasmSelect()) {
1215 return false;
1218 // Emission can be deferred to the first use point, but only if there are no
1219 // other use points.
1220 iter++;
1221 return iter == ins->usesEnd();
1224 void LIRGenerator::visitCompare(MCompare* comp) {
1225 MDefinition* left = comp->lhs();
1226 MDefinition* right = comp->rhs();
1228 // Try to fold the comparison so that we don't have to handle all cases.
1229 bool result;
1230 if (comp->tryFold(&result)) {
1231 define(new (alloc()) LInteger(result), comp);
1232 return;
1235 // Move below the emitAtUses call if we ever implement
1236 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
1237 // make sense and avoids confusion.
1238 if (comp->compareType() == MCompare::Compare_String) {
1239 MConstant* constant = nullptr;
1240 MDefinition* input = nullptr;
1241 if (left->isConstant()) {
1242 constant = left->toConstant();
1243 input = right;
1244 } else if (right->isConstant()) {
1245 constant = right->toConstant();
1246 input = left;
1249 if (constant) {
1250 JSLinearString* linear = &constant->toString()->asLinear();
1252 if (IsEqualityOp(comp->jsop())) {
1253 if (MacroAssembler::canCompareStringCharsInline(linear)) {
1254 auto* lir = new (alloc()) LCompareSInline(useRegister(input), linear);
1255 define(lir, comp);
1256 assignSafepoint(lir, comp);
1257 return;
1259 } else {
1260 MOZ_ASSERT(IsRelationalOp(comp->jsop()));
1262 if (linear->length() == 1) {
1263 // Move the constant value into the right-hand side operand.
1264 JSOp op = comp->jsop();
1265 if (left == constant) {
1266 op = ReverseCompareOp(op);
1269 auto* lir = new (alloc())
1270 LCompareSSingle(useRegister(input), temp(), op, linear);
1271 define(lir, comp);
1272 return;
1277 LCompareS* lir =
1278 new (alloc()) LCompareS(useRegister(left), useRegister(right));
1279 define(lir, comp);
1280 assignSafepoint(lir, comp);
1281 return;
1284 // Compare two BigInts.
1285 if (comp->compareType() == MCompare::Compare_BigInt) {
1286 auto* lir = new (alloc()) LCompareBigInt(
1287 useRegister(left), useRegister(right), temp(), temp(), temp());
1288 define(lir, comp);
1289 return;
1292 // Compare BigInt with Int32.
1293 if (comp->compareType() == MCompare::Compare_BigInt_Int32) {
1294 auto* lir = new (alloc()) LCompareBigIntInt32(
1295 useRegister(left), useRegister(right), temp(), temp());
1296 define(lir, comp);
1297 return;
1300 // Compare BigInt with Double.
1301 if (comp->compareType() == MCompare::Compare_BigInt_Double) {
1302 auto* lir = new (alloc()) LCompareBigIntDouble(useRegisterAtStart(left),
1303 useRegisterAtStart(right));
1304 defineReturn(lir, comp);
1305 return;
1308 // Compare BigInt with String.
1309 if (comp->compareType() == MCompare::Compare_BigInt_String) {
1310 auto* lir = new (alloc()) LCompareBigIntString(useRegisterAtStart(left),
1311 useRegisterAtStart(right));
1312 defineReturn(lir, comp);
1313 assignSafepoint(lir, comp);
1314 return;
1317 // Sniff out if the output of this compare is used only for a branching.
1318 // If it is, then we will emit an LCompare*AndBranch instruction in place
1319 // of this compare and any test that uses this compare. Thus, we can
1320 // ignore this Compare.
1321 if (CanEmitCompareAtUses(comp)) {
1322 emitAtUses(comp);
1323 return;
1326 // Compare Null and Undefined.
1327 if (comp->compareType() == MCompare::Compare_Null ||
1328 comp->compareType() == MCompare::Compare_Undefined) {
1329 if (left->type() == MIRType::Object) {
1330 define(new (alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp);
1331 return;
1334 if (IsLooseEqualityOp(comp->jsop())) {
1335 auto* lir =
1336 new (alloc()) LIsNullOrLikeUndefinedV(useBox(left), tempToUnbox());
1337 define(lir, comp);
1338 return;
1341 if (comp->compareType() == MCompare::Compare_Null) {
1342 auto* lir = new (alloc()) LIsNull(useBox(left));
1343 define(lir, comp);
1344 return;
1347 auto* lir = new (alloc()) LIsUndefined(useBox(left));
1348 define(lir, comp);
1349 return;
1352 // Compare Int32, Symbol, Object or Wasm pointers.
1353 if (comp->isInt32Comparison() ||
1354 comp->compareType() == MCompare::Compare_UInt32 ||
1355 comp->compareType() == MCompare::Compare_UIntPtr ||
1356 comp->compareType() == MCompare::Compare_Object ||
1357 comp->compareType() == MCompare::Compare_Symbol ||
1358 comp->compareType() == MCompare::Compare_WasmAnyRef) {
1359 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1360 LAllocation lhs = useRegister(left);
1361 LAllocation rhs;
1362 if (comp->isInt32Comparison() ||
1363 comp->compareType() == MCompare::Compare_UInt32 ||
1364 comp->compareType() == MCompare::Compare_UIntPtr) {
1365 rhs = useAnyOrInt32Constant(right);
1366 } else {
1367 rhs = useAny(right);
1369 define(new (alloc()) LCompare(op, lhs, rhs), comp);
1370 return;
1373 // Compare Int64.
1374 if (comp->compareType() == MCompare::Compare_Int64 ||
1375 comp->compareType() == MCompare::Compare_UInt64) {
1376 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1377 define(new (alloc()) LCompareI64(op, useInt64Register(left),
1378 useInt64OrConstant(right)),
1379 comp);
1380 return;
1383 // Compare doubles.
1384 if (comp->isDoubleComparison()) {
1385 define(new (alloc()) LCompareD(useRegister(left), useRegister(right)),
1386 comp);
1387 return;
1390 // Compare float32.
1391 if (comp->isFloat32Comparison()) {
1392 define(new (alloc()) LCompareF(useRegister(left), useRegister(right)),
1393 comp);
1394 return;
1397 MOZ_CRASH("Unrecognized compare type.");
1400 void LIRGenerator::visitSameValueDouble(MSameValueDouble* ins) {
1401 MDefinition* lhs = ins->lhs();
1402 MDefinition* rhs = ins->rhs();
1404 MOZ_ASSERT(lhs->type() == MIRType::Double);
1405 MOZ_ASSERT(rhs->type() == MIRType::Double);
1407 auto* lir = new (alloc())
1408 LSameValueDouble(useRegister(lhs), useRegister(rhs), tempDouble());
1409 define(lir, ins);
1412 void LIRGenerator::visitSameValue(MSameValue* ins) {
1413 MDefinition* lhs = ins->lhs();
1414 MDefinition* rhs = ins->rhs();
1416 MOZ_ASSERT(lhs->type() == MIRType::Value);
1417 MOZ_ASSERT(rhs->type() == MIRType::Value);
1419 auto* lir = new (alloc()) LSameValue(useBox(lhs), useBox(rhs));
1420 define(lir, ins);
1421 assignSafepoint(lir, ins);
1424 void LIRGenerator::lowerBitOp(JSOp op, MBinaryInstruction* ins) {
1425 MDefinition* lhs = ins->getOperand(0);
1426 MDefinition* rhs = ins->getOperand(1);
1427 MOZ_ASSERT(IsIntType(ins->type()));
1429 if (ins->type() == MIRType::Int32) {
1430 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1431 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1432 ReorderCommutative(&lhs, &rhs, ins);
1433 lowerForALU(new (alloc()) LBitOpI(op), ins, lhs, rhs);
1434 return;
1437 if (ins->type() == MIRType::Int64) {
1438 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1439 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1440 ReorderCommutative(&lhs, &rhs, ins);
1441 lowerForALUInt64(new (alloc()) LBitOpI64(op), ins, lhs, rhs);
1442 return;
1445 MOZ_CRASH("Unhandled integer specialization");
1448 void LIRGenerator::visitTypeOf(MTypeOf* ins) {
1449 MDefinition* opd = ins->input();
1451 if (opd->type() == MIRType::Object) {
1452 auto* lir = new (alloc()) LTypeOfO(useRegister(opd));
1453 define(lir, ins);
1454 return;
1457 MOZ_ASSERT(opd->type() == MIRType::Value);
1459 LTypeOfV* lir = new (alloc()) LTypeOfV(useBox(opd), tempToUnbox());
1460 define(lir, ins);
1463 void LIRGenerator::visitTypeOfName(MTypeOfName* ins) {
1464 MDefinition* input = ins->input();
1465 MOZ_ASSERT(input->type() == MIRType::Int32);
1467 auto* lir = new (alloc()) LTypeOfName(useRegister(input));
1468 define(lir, ins);
1471 void LIRGenerator::visitTypeOfIs(MTypeOfIs* ins) {
1472 MDefinition* input = ins->input();
1474 MOZ_ASSERT(input->type() == MIRType::Object ||
1475 input->type() == MIRType::Value);
1477 switch (ins->jstype()) {
1478 case JSTYPE_UNDEFINED:
1479 case JSTYPE_OBJECT:
1480 case JSTYPE_FUNCTION: {
1481 if (input->type() == MIRType::Object) {
1482 auto* lir = new (alloc()) LTypeOfIsNonPrimitiveO(useRegister(input));
1483 define(lir, ins);
1484 } else {
1485 auto* lir =
1486 new (alloc()) LTypeOfIsNonPrimitiveV(useBox(input), tempToUnbox());
1487 define(lir, ins);
1489 return;
1492 case JSTYPE_STRING:
1493 case JSTYPE_NUMBER:
1494 case JSTYPE_BOOLEAN:
1495 case JSTYPE_SYMBOL:
1496 case JSTYPE_BIGINT: {
1497 MOZ_ASSERT(input->type() == MIRType::Value);
1499 auto* lir = new (alloc()) LTypeOfIsPrimitive(useBoxAtStart(input));
1500 define(lir, ins);
1501 return;
1504 #ifdef ENABLE_RECORD_TUPLE
1505 case JSTYPE_RECORD:
1506 case JSTYPE_TUPLE:
1507 #endif
1508 case JSTYPE_LIMIT:
1509 break;
1511 MOZ_CRASH("Unhandled JSType");
1514 void LIRGenerator::visitToAsyncIter(MToAsyncIter* ins) {
1515 LToAsyncIter* lir = new (alloc()) LToAsyncIter(
1516 useRegisterAtStart(ins->iterator()), useBoxAtStart(ins->nextMethod()));
1517 defineReturn(lir, ins);
1518 assignSafepoint(lir, ins);
1521 void LIRGenerator::visitToPropertyKeyCache(MToPropertyKeyCache* ins) {
1522 MDefinition* input = ins->getOperand(0);
1523 MOZ_ASSERT(ins->type() == MIRType::Value);
1525 auto* lir = new (alloc()) LToPropertyKeyCache(useBox(input));
1526 defineBox(lir, ins);
1527 assignSafepoint(lir, ins);
1530 void LIRGenerator::visitBitNot(MBitNot* ins) {
1531 MDefinition* input = ins->getOperand(0);
1533 if (ins->type() == MIRType::Int32) {
1534 MOZ_ASSERT(input->type() == MIRType::Int32);
1535 lowerForALU(new (alloc()) LBitNotI(), ins, input);
1536 return;
1539 if (ins->type() == MIRType::Int64) {
1540 MOZ_ASSERT(input->type() == MIRType::Int64);
1541 lowerForALUInt64(new (alloc()) LBitNotI64(), ins, input);
1542 return;
1545 MOZ_CRASH("Unhandled integer specialization");
1548 static bool CanEmitBitAndAtUses(MInstruction* ins) {
1549 if (!ins->canEmitAtUses()) {
1550 return false;
1553 MIRType tyL = ins->getOperand(0)->type();
1554 MIRType tyR = ins->getOperand(1)->type();
1555 if (tyL != tyR || (tyL != MIRType::Int32 && tyL != MIRType::Int64)) {
1556 return false;
1559 MUseIterator iter(ins->usesBegin());
1560 if (iter == ins->usesEnd()) {
1561 return false;
1564 MNode* node = iter->consumer();
1565 if (!node->isDefinition() || !node->toDefinition()->isInstruction()) {
1566 return false;
1569 MInstruction* use = node->toDefinition()->toInstruction();
1570 if (!use->isTest() && !(use->isCompare() && CanEmitCompareAtUses(use))) {
1571 return false;
1574 iter++;
1575 return iter == ins->usesEnd();
1578 void LIRGenerator::visitBitAnd(MBitAnd* ins) {
1579 // Sniff out if the output of this bitand is used only for a branching.
1580 // If it is, then we will emit an LBitAndAndBranch instruction in place
1581 // of this bitand and any test that uses this bitand. Thus, we can
1582 // ignore this BitAnd.
1583 if (CanEmitBitAndAtUses(ins)) {
1584 emitAtUses(ins);
1585 } else {
1586 lowerBitOp(JSOp::BitAnd, ins);
1590 void LIRGenerator::visitBitOr(MBitOr* ins) { lowerBitOp(JSOp::BitOr, ins); }
1592 void LIRGenerator::visitBitXor(MBitXor* ins) { lowerBitOp(JSOp::BitXor, ins); }
1594 void LIRGenerator::visitWasmBinaryBitwise(MWasmBinaryBitwise* ins) {
1595 switch (ins->subOpcode()) {
1596 case MWasmBinaryBitwise::SubOpcode::And:
1597 if (CanEmitBitAndAtUses(ins)) {
1598 emitAtUses(ins);
1599 } else {
1600 lowerBitOp(JSOp::BitAnd, ins);
1602 break;
1603 case MWasmBinaryBitwise::SubOpcode::Or:
1604 lowerBitOp(JSOp::BitOr, ins);
1605 break;
1606 case MWasmBinaryBitwise::SubOpcode::Xor:
1607 lowerBitOp(JSOp::BitXor, ins);
1608 break;
1609 default:
1610 MOZ_CRASH();
1614 void LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) {
1615 MDefinition* lhs = ins->getOperand(0);
1616 MDefinition* rhs = ins->getOperand(1);
1618 if (op == JSOp::Ursh && ins->type() == MIRType::Double) {
1619 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1620 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1621 lowerUrshD(ins->toUrsh());
1622 return;
1625 MOZ_ASSERT(IsIntType(ins->type()));
1627 if (ins->type() == MIRType::Int32) {
1628 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1629 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1631 LShiftI* lir = new (alloc()) LShiftI(op);
1632 if (op == JSOp::Ursh) {
1633 if (ins->toUrsh()->fallible()) {
1634 assignSnapshot(lir, ins->bailoutKind());
1637 lowerForShift(lir, ins, lhs, rhs);
1638 return;
1641 if (ins->type() == MIRType::Int64) {
1642 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1643 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1644 lowerForShiftInt64(new (alloc()) LShiftI64(op), ins, lhs, rhs);
1645 return;
1648 MOZ_CRASH("Unhandled integer specialization");
1651 void LIRGenerator::visitLsh(MLsh* ins) { lowerShiftOp(JSOp::Lsh, ins); }
1653 void LIRGenerator::visitRsh(MRsh* ins) { lowerShiftOp(JSOp::Rsh, ins); }
1655 void LIRGenerator::visitUrsh(MUrsh* ins) { lowerShiftOp(JSOp::Ursh, ins); }
1657 void LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins) {
1658 LInstructionHelper<1, 1, 0>* lir;
1660 if (ins->mode() == MSignExtendInt32::Byte) {
1661 lir = new (alloc())
1662 LSignExtendInt32(useByteOpRegisterAtStart(ins->input()), ins->mode());
1663 } else {
1664 lir = new (alloc())
1665 LSignExtendInt32(useRegisterAtStart(ins->input()), ins->mode());
1668 define(lir, ins);
1671 void LIRGenerator::visitRotate(MRotate* ins) {
1672 MDefinition* input = ins->input();
1673 MDefinition* count = ins->count();
1675 if (ins->type() == MIRType::Int32) {
1676 auto* lir = new (alloc()) LRotate();
1677 lowerForShift(lir, ins, input, count);
1678 } else if (ins->type() == MIRType::Int64) {
1679 auto* lir = new (alloc()) LRotateI64();
1680 lowerForShiftInt64(lir, ins, input, count);
1681 } else {
1682 MOZ_CRASH("unexpected type in visitRotate");
1686 void LIRGenerator::visitFloor(MFloor* ins) {
1687 MIRType type = ins->input()->type();
1688 MOZ_ASSERT(IsFloatingPointType(type));
1690 LInstructionHelper<1, 1, 0>* lir;
1691 if (type == MIRType::Double) {
1692 lir = new (alloc()) LFloor(useRegister(ins->input()));
1693 } else {
1694 lir = new (alloc()) LFloorF(useRegister(ins->input()));
1697 assignSnapshot(lir, ins->bailoutKind());
1698 define(lir, ins);
1701 void LIRGenerator::visitCeil(MCeil* ins) {
1702 MIRType type = ins->input()->type();
1703 MOZ_ASSERT(IsFloatingPointType(type));
1705 LInstructionHelper<1, 1, 0>* lir;
1706 if (type == MIRType::Double) {
1707 lir = new (alloc()) LCeil(useRegister(ins->input()));
1708 } else {
1709 lir = new (alloc()) LCeilF(useRegister(ins->input()));
1712 assignSnapshot(lir, ins->bailoutKind());
1713 define(lir, ins);
1716 void LIRGenerator::visitRound(MRound* ins) {
1717 MIRType type = ins->input()->type();
1718 MOZ_ASSERT(IsFloatingPointType(type));
1720 LInstructionHelper<1, 1, 1>* lir;
1721 if (type == MIRType::Double) {
1722 lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble());
1723 } else {
1724 lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32());
1727 assignSnapshot(lir, ins->bailoutKind());
1728 define(lir, ins);
1731 void LIRGenerator::visitTrunc(MTrunc* ins) {
1732 MIRType type = ins->input()->type();
1733 MOZ_ASSERT(IsFloatingPointType(type));
1735 LInstructionHelper<1, 1, 0>* lir;
1736 if (type == MIRType::Double) {
1737 lir = new (alloc()) LTrunc(useRegister(ins->input()));
1738 } else {
1739 lir = new (alloc()) LTruncF(useRegister(ins->input()));
1742 assignSnapshot(lir, ins->bailoutKind());
1743 define(lir, ins);
1746 void LIRGenerator::visitNearbyInt(MNearbyInt* ins) {
1747 MIRType inputType = ins->input()->type();
1748 MOZ_ASSERT(IsFloatingPointType(inputType));
1749 MOZ_ASSERT(ins->type() == inputType);
1751 LInstructionHelper<1, 1, 0>* lir;
1752 if (inputType == MIRType::Double) {
1753 lir = new (alloc()) LNearbyInt(useRegisterAtStart(ins->input()));
1754 } else {
1755 lir = new (alloc()) LNearbyIntF(useRegisterAtStart(ins->input()));
1758 define(lir, ins);
1761 void LIRGenerator::visitMinMax(MMinMax* ins) {
1762 MDefinition* first = ins->getOperand(0);
1763 MDefinition* second = ins->getOperand(1);
1765 ReorderCommutative(&first, &second, ins);
1767 LMinMaxBase* lir;
1768 switch (ins->type()) {
1769 case MIRType::Int32:
1770 lir = new (alloc())
1771 LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
1772 break;
1773 case MIRType::Float32:
1774 lir = new (alloc())
1775 LMinMaxF(useRegisterAtStart(first), useRegister(second));
1776 break;
1777 case MIRType::Double:
1778 lir = new (alloc())
1779 LMinMaxD(useRegisterAtStart(first), useRegister(second));
1780 break;
1781 default:
1782 MOZ_CRASH();
1785 // Input reuse is OK (for now) even on ARM64: floating min/max are fairly
1786 // expensive due to SNaN -> QNaN conversion, and int min/max is for asm.js.
1787 defineReuseInput(lir, ins, 0);
1790 void LIRGenerator::visitMinMaxArray(MMinMaxArray* ins) {
1791 LInstructionHelper<1, 1, 3>* lir;
1792 if (ins->type() == MIRType::Int32) {
1793 lir = new (alloc())
1794 LMinMaxArrayI(useRegisterAtStart(ins->array()), temp(), temp(), temp());
1795 } else {
1796 MOZ_ASSERT(ins->type() == MIRType::Double);
1797 lir = new (alloc()) LMinMaxArrayD(useRegisterAtStart(ins->array()),
1798 tempDouble(), temp(), temp());
1800 assignSnapshot(lir, ins->bailoutKind());
1801 define(lir, ins);
1804 LInstructionHelper<1, 1, 0>* LIRGenerator::allocateAbs(MAbs* ins,
1805 LAllocation input) {
1806 MDefinition* num = ins->input();
1807 MOZ_ASSERT(IsNumberType(num->type()));
1809 LInstructionHelper<1, 1, 0>* lir;
1810 switch (num->type()) {
1811 case MIRType::Int32:
1812 lir = new (alloc()) LAbsI(input);
1813 // needed to handle abs(INT32_MIN)
1814 if (ins->fallible()) {
1815 assignSnapshot(lir, ins->bailoutKind());
1817 break;
1818 case MIRType::Float32:
1819 lir = new (alloc()) LAbsF(input);
1820 break;
1821 case MIRType::Double:
1822 lir = new (alloc()) LAbsD(input);
1823 break;
1824 default:
1825 MOZ_CRASH();
1827 return lir;
1830 void LIRGenerator::visitClz(MClz* ins) {
1831 MDefinition* num = ins->num();
1833 MOZ_ASSERT(IsIntType(ins->type()));
1835 if (ins->type() == MIRType::Int32) {
1836 LClzI* lir = new (alloc()) LClzI(useRegisterAtStart(num));
1837 define(lir, ins);
1838 return;
1841 auto* lir = new (alloc()) LClzI64(useInt64RegisterAtStart(num));
1842 defineInt64(lir, ins);
1845 void LIRGenerator::visitCtz(MCtz* ins) {
1846 MDefinition* num = ins->num();
1848 MOZ_ASSERT(IsIntType(ins->type()));
1850 if (ins->type() == MIRType::Int32) {
1851 LCtzI* lir = new (alloc()) LCtzI(useRegisterAtStart(num));
1852 define(lir, ins);
1853 return;
1856 auto* lir = new (alloc()) LCtzI64(useInt64RegisterAtStart(num));
1857 defineInt64(lir, ins);
1860 void LIRGenerator::visitPopcnt(MPopcnt* ins) {
1861 MDefinition* num = ins->num();
1863 MOZ_ASSERT(IsIntType(ins->type()));
1865 if (ins->type() == MIRType::Int32) {
1866 LPopcntI* lir = new (alloc()) LPopcntI(useRegisterAtStart(num), temp());
1867 define(lir, ins);
1868 return;
1871 auto* lir = new (alloc()) LPopcntI64(useInt64RegisterAtStart(num), temp());
1872 defineInt64(lir, ins);
1875 void LIRGenerator::visitSqrt(MSqrt* ins) {
1876 MDefinition* num = ins->input();
1877 MOZ_ASSERT(IsFloatingPointType(num->type()));
1879 LInstructionHelper<1, 1, 0>* lir;
1880 if (num->type() == MIRType::Double) {
1881 lir = new (alloc()) LSqrtD(useRegisterAtStart(num));
1882 } else {
1883 lir = new (alloc()) LSqrtF(useRegisterAtStart(num));
1885 define(lir, ins);
1888 void LIRGenerator::visitAtan2(MAtan2* ins) {
1889 MDefinition* y = ins->y();
1890 MOZ_ASSERT(y->type() == MIRType::Double);
1892 MDefinition* x = ins->x();
1893 MOZ_ASSERT(x->type() == MIRType::Double);
1895 LAtan2D* lir =
1896 new (alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x));
1897 defineReturn(lir, ins);
1900 void LIRGenerator::visitHypot(MHypot* ins) {
1901 LHypot* lir = nullptr;
1902 uint32_t length = ins->numOperands();
1903 for (uint32_t i = 0; i < length; ++i) {
1904 MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double);
1907 switch (length) {
1908 case 2:
1909 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1910 useRegisterAtStart(ins->getOperand(1)));
1911 break;
1912 case 3:
1913 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1914 useRegisterAtStart(ins->getOperand(1)),
1915 useRegisterAtStart(ins->getOperand(2)));
1916 break;
1917 case 4:
1918 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1919 useRegisterAtStart(ins->getOperand(1)),
1920 useRegisterAtStart(ins->getOperand(2)),
1921 useRegisterAtStart(ins->getOperand(3)));
1922 break;
1923 default:
1924 MOZ_CRASH("Unexpected number of arguments to LHypot.");
1927 defineReturn(lir, ins);
1930 void LIRGenerator::visitPow(MPow* ins) {
1931 MDefinition* input = ins->input();
1932 MDefinition* power = ins->power();
1934 if (ins->type() == MIRType::Int32) {
1935 MOZ_ASSERT(input->type() == MIRType::Int32);
1936 MOZ_ASSERT(power->type() == MIRType::Int32);
1938 if (input->isConstant()) {
1939 // Restrict this optimization to |base <= 256| to avoid generating too
1940 // many consecutive shift instructions.
1941 int32_t base = input->toConstant()->toInt32();
1942 if (2 <= base && base <= 256 && mozilla::IsPowerOfTwo(uint32_t(base))) {
1943 lowerPowOfTwoI(ins);
1944 return;
1948 auto* lir = new (alloc())
1949 LPowII(useRegister(input), useRegister(power), temp(), temp());
1950 assignSnapshot(lir, ins->bailoutKind());
1951 define(lir, ins);
1952 return;
1955 MOZ_ASSERT(ins->type() == MIRType::Double);
1956 MOZ_ASSERT(input->type() == MIRType::Double);
1957 MOZ_ASSERT(power->type() == MIRType::Int32 ||
1958 power->type() == MIRType::Double);
1960 LInstruction* lir;
1961 if (power->type() == MIRType::Int32) {
1962 lir = new (alloc())
1963 LPowI(useRegisterAtStart(input), useRegisterAtStart(power));
1964 } else {
1965 lir = new (alloc())
1966 LPowD(useRegisterAtStart(input), useRegisterAtStart(power));
1968 defineReturn(lir, ins);
1971 void LIRGenerator::visitSign(MSign* ins) {
1972 if (ins->type() == ins->input()->type()) {
1973 LInstructionHelper<1, 1, 0>* lir;
1974 if (ins->type() == MIRType::Int32) {
1975 lir = new (alloc()) LSignI(useRegister(ins->input()));
1976 } else {
1977 MOZ_ASSERT(ins->type() == MIRType::Double);
1978 lir = new (alloc()) LSignD(useRegister(ins->input()));
1980 define(lir, ins);
1981 } else {
1982 MOZ_ASSERT(ins->type() == MIRType::Int32);
1983 MOZ_ASSERT(ins->input()->type() == MIRType::Double);
1985 auto* lir = new (alloc()) LSignDI(useRegister(ins->input()), tempDouble());
1986 assignSnapshot(lir, ins->bailoutKind());
1987 define(lir, ins);
1991 void LIRGenerator::visitMathFunction(MMathFunction* ins) {
1992 MOZ_ASSERT(IsFloatingPointType(ins->type()));
1993 MOZ_ASSERT(ins->type() == ins->input()->type());
1995 LInstruction* lir;
1996 if (ins->type() == MIRType::Double) {
1997 lir = new (alloc()) LMathFunctionD(useRegisterAtStart(ins->input()));
1998 } else {
1999 lir = new (alloc()) LMathFunctionF(useRegisterAtStart(ins->input()));
2001 defineReturn(lir, ins);
2004 void LIRGenerator::visitRandom(MRandom* ins) {
2005 auto* lir = new (alloc()) LRandom(temp(), tempInt64(), tempInt64());
2006 define(lir, ins);
2009 // Try to mark an add or sub instruction as able to recover its input when
2010 // bailing out.
2011 template <typename S, typename T>
2012 static void MaybeSetRecoversInput(S* mir, T* lir) {
2013 MOZ_ASSERT(lir->mirRaw() == mir);
2014 if (!mir->fallible() || !lir->snapshot()) {
2015 return;
2018 if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT) {
2019 return;
2022 // The original operands to an add or sub can't be recovered if they both
2023 // use the same register.
2024 if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
2025 lir->lhs()->toUse()->virtualRegister() ==
2026 lir->rhs()->toUse()->virtualRegister()) {
2027 return;
2030 // Add instructions that are on two different values can recover
2031 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
2032 // of that input does not need to be kept alive in the snapshot
2033 // for the instruction.
2035 lir->setRecoversInput();
2037 const LUse* input = lir->getOperand(lir->output()->getReusedInput())->toUse();
2038 lir->snapshot()->rewriteRecoveredInput(*input);
2041 void LIRGenerator::visitAdd(MAdd* ins) {
2042 MDefinition* lhs = ins->getOperand(0);
2043 MDefinition* rhs = ins->getOperand(1);
2045 MOZ_ASSERT(lhs->type() == rhs->type());
2046 MOZ_ASSERT(IsNumberType(ins->type()));
2048 if (ins->type() == MIRType::Int32) {
2049 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2050 ReorderCommutative(&lhs, &rhs, ins);
2051 LAddI* lir = new (alloc()) LAddI;
2053 if (ins->fallible()) {
2054 assignSnapshot(lir, ins->bailoutKind());
2057 lowerForALU(lir, ins, lhs, rhs);
2058 MaybeSetRecoversInput(ins, lir);
2059 return;
2062 if (ins->type() == MIRType::Int64) {
2063 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2064 ReorderCommutative(&lhs, &rhs, ins);
2065 LAddI64* lir = new (alloc()) LAddI64;
2066 lowerForALUInt64(lir, ins, lhs, rhs);
2067 return;
2070 if (ins->type() == MIRType::Double) {
2071 MOZ_ASSERT(lhs->type() == MIRType::Double);
2072 ReorderCommutative(&lhs, &rhs, ins);
2073 lowerForFPU(new (alloc()) LMathD(JSOp::Add), ins, lhs, rhs);
2074 return;
2077 if (ins->type() == MIRType::Float32) {
2078 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2079 ReorderCommutative(&lhs, &rhs, ins);
2080 lowerForFPU(new (alloc()) LMathF(JSOp::Add), ins, lhs, rhs);
2081 return;
2084 MOZ_CRASH("Unhandled number specialization");
2087 void LIRGenerator::visitSub(MSub* ins) {
2088 MDefinition* lhs = ins->lhs();
2089 MDefinition* rhs = ins->rhs();
2091 MOZ_ASSERT(lhs->type() == rhs->type());
2092 MOZ_ASSERT(IsNumberType(ins->type()));
2094 if (ins->type() == MIRType::Int32) {
2095 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2097 LSubI* lir = new (alloc()) LSubI;
2098 if (ins->fallible()) {
2099 assignSnapshot(lir, ins->bailoutKind());
2102 // If our LHS is a constant 0 and we don't have to worry about results that
2103 // can't be represented as an int32, we can optimize to an LNegI.
2104 if (!ins->fallible() && lhs->isConstant() &&
2105 lhs->toConstant()->toInt32() == 0) {
2106 lowerNegI(ins, rhs);
2107 return;
2110 lowerForALU(lir, ins, lhs, rhs);
2111 MaybeSetRecoversInput(ins, lir);
2112 return;
2115 if (ins->type() == MIRType::Int64) {
2116 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2118 // If our LHS is a constant 0, we can optimize to an LNegI64.
2119 if (lhs->isConstant() && lhs->toConstant()->toInt64() == 0) {
2120 lowerNegI64(ins, rhs);
2121 return;
2124 LSubI64* lir = new (alloc()) LSubI64;
2125 lowerForALUInt64(lir, ins, lhs, rhs);
2126 return;
2129 if (ins->type() == MIRType::Double) {
2130 MOZ_ASSERT(lhs->type() == MIRType::Double);
2131 lowerForFPU(new (alloc()) LMathD(JSOp::Sub), ins, lhs, rhs);
2132 return;
2135 if (ins->type() == MIRType::Float32) {
2136 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2137 lowerForFPU(new (alloc()) LMathF(JSOp::Sub), ins, lhs, rhs);
2138 return;
2141 MOZ_CRASH("Unhandled number specialization");
2144 void LIRGenerator::visitMul(MMul* ins) {
2145 MDefinition* lhs = ins->lhs();
2146 MDefinition* rhs = ins->rhs();
2147 MOZ_ASSERT(lhs->type() == rhs->type());
2148 MOZ_ASSERT(IsNumberType(ins->type()));
2150 if (ins->type() == MIRType::Int32) {
2151 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2152 ReorderCommutative(&lhs, &rhs, ins);
2154 // If our RHS is a constant -1 and we don't have to worry about results that
2155 // can't be represented as an int32, we can optimize to an LNegI.
2156 if (!ins->fallible() && rhs->isConstant() &&
2157 rhs->toConstant()->toInt32() == -1) {
2158 lowerNegI(ins, lhs);
2159 return;
2162 lowerMulI(ins, lhs, rhs);
2163 return;
2166 if (ins->type() == MIRType::Int64) {
2167 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2168 ReorderCommutative(&lhs, &rhs, ins);
2170 // If our RHS is a constant -1, we can optimize to an LNegI64.
2171 if (rhs->isConstant() && rhs->toConstant()->toInt64() == -1) {
2172 lowerNegI64(ins, lhs);
2173 return;
2176 LMulI64* lir = new (alloc()) LMulI64;
2177 lowerForMulInt64(lir, ins, lhs, rhs);
2178 return;
2181 if (ins->type() == MIRType::Double) {
2182 MOZ_ASSERT(lhs->type() == MIRType::Double);
2183 ReorderCommutative(&lhs, &rhs, ins);
2185 // If our RHS is a constant -1.0, we can optimize to an LNegD.
2186 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2187 rhs->toConstant()->toDouble() == -1.0) {
2188 defineReuseInput(new (alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
2189 return;
2192 lowerForFPU(new (alloc()) LMathD(JSOp::Mul), ins, lhs, rhs);
2193 return;
2196 if (ins->type() == MIRType::Float32) {
2197 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2198 ReorderCommutative(&lhs, &rhs, ins);
2200 // We apply the same optimizations as for doubles
2201 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2202 rhs->toConstant()->toFloat32() == -1.0f) {
2203 defineReuseInput(new (alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
2204 return;
2207 lowerForFPU(new (alloc()) LMathF(JSOp::Mul), ins, lhs, rhs);
2208 return;
2211 MOZ_CRASH("Unhandled number specialization");
2214 void LIRGenerator::visitDiv(MDiv* ins) {
2215 MDefinition* lhs = ins->lhs();
2216 MDefinition* rhs = ins->rhs();
2217 MOZ_ASSERT(lhs->type() == rhs->type());
2218 MOZ_ASSERT(IsNumberType(ins->type()));
2220 if (ins->type() == MIRType::Int32) {
2221 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2222 lowerDivI(ins);
2223 return;
2226 if (ins->type() == MIRType::Int64) {
2227 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2228 lowerDivI64(ins);
2229 return;
2232 if (ins->type() == MIRType::Double) {
2233 MOZ_ASSERT(lhs->type() == MIRType::Double);
2234 lowerForFPU(new (alloc()) LMathD(JSOp::Div), ins, lhs, rhs);
2235 return;
2238 if (ins->type() == MIRType::Float32) {
2239 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2240 lowerForFPU(new (alloc()) LMathF(JSOp::Div), ins, lhs, rhs);
2241 return;
2244 MOZ_CRASH("Unhandled number specialization");
2247 void LIRGenerator::visitWasmBuiltinDivI64(MWasmBuiltinDivI64* div) {
2248 lowerWasmBuiltinDivI64(div);
2251 void LIRGenerator::visitWasmBuiltinModI64(MWasmBuiltinModI64* mod) {
2252 lowerWasmBuiltinModI64(mod);
2255 void LIRGenerator::visitBuiltinInt64ToFloatingPoint(
2256 MBuiltinInt64ToFloatingPoint* ins) {
2257 lowerBuiltinInt64ToFloatingPoint(ins);
2260 void LIRGenerator::visitWasmBuiltinTruncateToInt64(
2261 MWasmBuiltinTruncateToInt64* ins) {
2262 lowerWasmBuiltinTruncateToInt64(ins);
2265 void LIRGenerator::visitWasmBuiltinModD(MWasmBuiltinModD* ins) {
2266 MOZ_ASSERT(gen->compilingWasm());
2267 LWasmBuiltinModD* lir = new (alloc()) LWasmBuiltinModD(
2268 useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
2269 useFixedAtStart(ins->instance(), InstanceReg));
2270 defineReturn(lir, ins);
2273 void LIRGenerator::visitMod(MMod* ins) {
2274 MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type());
2275 MOZ_ASSERT(IsNumberType(ins->type()));
2277 if (ins->type() == MIRType::Int32) {
2278 MOZ_ASSERT(ins->type() == MIRType::Int32);
2279 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32);
2280 lowerModI(ins);
2281 return;
2284 if (ins->type() == MIRType::Int64) {
2285 MOZ_ASSERT(ins->type() == MIRType::Int64);
2286 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64);
2287 lowerModI64(ins);
2288 return;
2291 if (ins->type() == MIRType::Double) {
2292 MOZ_ASSERT(ins->lhs()->type() == MIRType::Double);
2293 MOZ_ASSERT(ins->rhs()->type() == MIRType::Double);
2295 MOZ_ASSERT(!gen->compilingWasm());
2297 if (Assembler::HasRoundInstruction(RoundingMode::TowardsZero)) {
2298 if (ins->rhs()->isConstant()) {
2299 double d = ins->rhs()->toConstant()->toDouble();
2300 int32_t div;
2301 if (mozilla::NumberIsInt32(d, &div) && div > 0 &&
2302 mozilla::IsPowerOfTwo(uint32_t(div))) {
2303 auto* lir = new (alloc()) LModPowTwoD(useRegister(ins->lhs()), div);
2304 define(lir, ins);
2305 return;
2310 LModD* lir = new (alloc())
2311 LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()));
2312 defineReturn(lir, ins);
2313 return;
2316 MOZ_CRASH("Unhandled number specialization");
2319 void LIRGenerator::visitBigIntAdd(MBigIntAdd* ins) {
2320 auto* lir = new (alloc()) LBigIntAdd(useRegister(ins->lhs()),
2321 useRegister(ins->rhs()), temp(), temp());
2322 define(lir, ins);
2323 assignSafepoint(lir, ins);
2326 void LIRGenerator::visitBigIntSub(MBigIntSub* ins) {
2327 auto* lir = new (alloc()) LBigIntSub(useRegister(ins->lhs()),
2328 useRegister(ins->rhs()), temp(), temp());
2329 define(lir, ins);
2330 assignSafepoint(lir, ins);
2333 void LIRGenerator::visitBigIntMul(MBigIntMul* ins) {
2334 auto* lir = new (alloc()) LBigIntMul(useRegister(ins->lhs()),
2335 useRegister(ins->rhs()), temp(), temp());
2336 define(lir, ins);
2337 assignSafepoint(lir, ins);
2340 void LIRGenerator::visitBigIntDiv(MBigIntDiv* ins) { lowerBigIntDiv(ins); }
2342 void LIRGenerator::visitBigIntMod(MBigIntMod* ins) { lowerBigIntMod(ins); }
2344 void LIRGenerator::visitBigIntPow(MBigIntPow* ins) {
2345 auto* lir = new (alloc()) LBigIntPow(useRegister(ins->lhs()),
2346 useRegister(ins->rhs()), temp(), temp());
2347 define(lir, ins);
2348 assignSafepoint(lir, ins);
2351 void LIRGenerator::visitBigIntBitAnd(MBigIntBitAnd* ins) {
2352 auto* lir = new (alloc()) LBigIntBitAnd(
2353 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2354 define(lir, ins);
2355 assignSafepoint(lir, ins);
2358 void LIRGenerator::visitBigIntBitOr(MBigIntBitOr* ins) {
2359 auto* lir = new (alloc()) LBigIntBitOr(
2360 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2361 define(lir, ins);
2362 assignSafepoint(lir, ins);
2365 void LIRGenerator::visitBigIntBitXor(MBigIntBitXor* ins) {
2366 auto* lir = new (alloc()) LBigIntBitXor(
2367 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2368 define(lir, ins);
2369 assignSafepoint(lir, ins);
2372 void LIRGenerator::visitBigIntLsh(MBigIntLsh* ins) { lowerBigIntLsh(ins); }
2374 void LIRGenerator::visitBigIntRsh(MBigIntRsh* ins) { lowerBigIntRsh(ins); }
2376 void LIRGenerator::visitBigIntIncrement(MBigIntIncrement* ins) {
2377 auto* lir =
2378 new (alloc()) LBigIntIncrement(useRegister(ins->input()), temp(), temp());
2379 define(lir, ins);
2380 assignSafepoint(lir, ins);
2383 void LIRGenerator::visitBigIntDecrement(MBigIntDecrement* ins) {
2384 auto* lir =
2385 new (alloc()) LBigIntDecrement(useRegister(ins->input()), temp(), temp());
2386 define(lir, ins);
2387 assignSafepoint(lir, ins);
2390 void LIRGenerator::visitBigIntNegate(MBigIntNegate* ins) {
2391 auto* lir = new (alloc()) LBigIntNegate(useRegister(ins->input()), temp());
2392 define(lir, ins);
2393 assignSafepoint(lir, ins);
2396 void LIRGenerator::visitBigIntBitNot(MBigIntBitNot* ins) {
2397 auto* lir =
2398 new (alloc()) LBigIntBitNot(useRegister(ins->input()), temp(), temp());
2399 define(lir, ins);
2400 assignSafepoint(lir, ins);
2403 void LIRGenerator::visitInt32ToStringWithBase(MInt32ToStringWithBase* ins) {
2404 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2405 MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
2407 int32_t baseInt =
2408 ins->base()->isConstant() ? ins->base()->toConstant()->toInt32() : 0;
2410 LAllocation base;
2411 if (2 <= baseInt && baseInt <= 36) {
2412 base = useRegisterOrConstant(ins->base());
2413 } else {
2414 base = useRegister(ins->base());
2417 auto* lir = new (alloc())
2418 LInt32ToStringWithBase(useRegister(ins->input()), base, temp(), temp());
2419 define(lir, ins);
2420 assignSafepoint(lir, ins);
2423 void LIRGenerator::visitNumberParseInt(MNumberParseInt* ins) {
2424 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2425 MOZ_ASSERT(ins->radix()->type() == MIRType::Int32);
2427 auto* lir = new (alloc()) LNumberParseInt(useRegisterAtStart(ins->string()),
2428 useRegisterAtStart(ins->radix()),
2429 tempFixed(CallTempReg0));
2430 defineReturn(lir, ins);
2431 assignSafepoint(lir, ins);
2434 void LIRGenerator::visitDoubleParseInt(MDoubleParseInt* ins) {
2435 MOZ_ASSERT(ins->number()->type() == MIRType::Double);
2437 auto* lir =
2438 new (alloc()) LDoubleParseInt(useRegister(ins->number()), tempDouble());
2439 assignSnapshot(lir, ins->bailoutKind());
2440 define(lir, ins);
2443 void LIRGenerator::visitConcat(MConcat* ins) {
2444 MDefinition* lhs = ins->getOperand(0);
2445 MDefinition* rhs = ins->getOperand(1);
2447 MOZ_ASSERT(lhs->type() == MIRType::String);
2448 MOZ_ASSERT(rhs->type() == MIRType::String);
2449 MOZ_ASSERT(ins->type() == MIRType::String);
2451 LConcat* lir = new (alloc()) LConcat(
2452 useFixedAtStart(lhs, CallTempReg0), useFixedAtStart(rhs, CallTempReg1),
2453 tempFixed(CallTempReg0), tempFixed(CallTempReg1), tempFixed(CallTempReg2),
2454 tempFixed(CallTempReg3), tempFixed(CallTempReg4));
2455 defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
2456 assignSafepoint(lir, ins);
2459 void LIRGenerator::visitLinearizeString(MLinearizeString* ins) {
2460 MDefinition* str = ins->string();
2461 MOZ_ASSERT(str->type() == MIRType::String);
2463 auto* lir = new (alloc()) LLinearizeString(useRegister(str));
2464 define(lir, ins);
2465 assignSafepoint(lir, ins);
2468 void LIRGenerator::visitLinearizeForCharAccess(MLinearizeForCharAccess* ins) {
2469 MDefinition* str = ins->string();
2470 MDefinition* idx = ins->index();
2472 MOZ_ASSERT(str->type() == MIRType::String);
2473 MOZ_ASSERT(idx->type() == MIRType::Int32);
2475 auto* lir =
2476 new (alloc()) LLinearizeForCharAccess(useRegister(str), useRegister(idx));
2477 define(lir, ins);
2478 assignSafepoint(lir, ins);
2481 void LIRGenerator::visitLinearizeForCodePointAccess(
2482 MLinearizeForCodePointAccess* ins) {
2483 MDefinition* str = ins->string();
2484 MDefinition* idx = ins->index();
2486 MOZ_ASSERT(str->type() == MIRType::String);
2487 MOZ_ASSERT(idx->type() == MIRType::Int32);
2489 auto* lir = new (alloc())
2490 LLinearizeForCodePointAccess(useRegister(str), useRegister(idx), temp());
2491 define(lir, ins);
2492 assignSafepoint(lir, ins);
2495 void LIRGenerator::visitToRelativeStringIndex(MToRelativeStringIndex* ins) {
2496 MDefinition* index = ins->index();
2497 MDefinition* length = ins->length();
2499 MOZ_ASSERT(index->type() == MIRType::Int32);
2500 MOZ_ASSERT(length->type() == MIRType::Int32);
2502 auto* lir = new (alloc())
2503 LToRelativeStringIndex(useRegister(index), useRegister(length));
2504 define(lir, ins);
2507 void LIRGenerator::visitCharCodeAt(MCharCodeAt* ins) {
2508 MDefinition* str = ins->string();
2509 MDefinition* idx = ins->index();
2511 MOZ_ASSERT(str->type() == MIRType::String);
2512 MOZ_ASSERT(idx->type() == MIRType::Int32);
2514 auto* lir = new (alloc())
2515 LCharCodeAt(useRegister(str), useRegisterOrZero(idx), temp(), temp());
2516 define(lir, ins);
2517 assignSafepoint(lir, ins);
2520 void LIRGenerator::visitCharCodeAtOrNegative(MCharCodeAtOrNegative* ins) {
2521 MDefinition* str = ins->string();
2522 MDefinition* idx = ins->index();
2524 MOZ_ASSERT(str->type() == MIRType::String);
2525 MOZ_ASSERT(idx->type() == MIRType::Int32);
2527 auto* lir = new (alloc()) LCharCodeAtOrNegative(
2528 useRegister(str), useRegisterOrZero(idx), temp(), temp());
2529 define(lir, ins);
2530 assignSafepoint(lir, ins);
2533 void LIRGenerator::visitCodePointAt(MCodePointAt* ins) {
2534 MDefinition* str = ins->string();
2535 MDefinition* idx = ins->index();
2537 MOZ_ASSERT(str->type() == MIRType::String);
2538 MOZ_ASSERT(idx->type() == MIRType::Int32);
2540 auto* lir = new (alloc())
2541 LCodePointAt(useRegister(str), useRegister(idx), temp(), temp());
2542 define(lir, ins);
2543 assignSafepoint(lir, ins);
2546 void LIRGenerator::visitCodePointAtOrNegative(MCodePointAtOrNegative* ins) {
2547 MDefinition* str = ins->string();
2548 MDefinition* idx = ins->index();
2550 MOZ_ASSERT(str->type() == MIRType::String);
2551 MOZ_ASSERT(idx->type() == MIRType::Int32);
2553 auto* lir = new (alloc()) LCodePointAtOrNegative(
2554 useRegister(str), useRegister(idx), temp(), temp());
2555 define(lir, ins);
2556 assignSafepoint(lir, ins);
2559 void LIRGenerator::visitNegativeToNaN(MNegativeToNaN* ins) {
2560 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2562 auto* lir = new (alloc()) LNegativeToNaN(useRegister(ins->input()));
2563 defineBox(lir, ins);
2566 void LIRGenerator::visitNegativeToUndefined(MNegativeToUndefined* ins) {
2567 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2569 auto* lir = new (alloc()) LNegativeToUndefined(useRegister(ins->input()));
2570 defineBox(lir, ins);
2573 void LIRGenerator::visitFromCharCode(MFromCharCode* ins) {
2574 MDefinition* code = ins->code();
2576 MOZ_ASSERT(code->type() == MIRType::Int32);
2578 LFromCharCode* lir = new (alloc()) LFromCharCode(useRegister(code));
2579 define(lir, ins);
2580 assignSafepoint(lir, ins);
2583 void LIRGenerator::visitFromCharCodeEmptyIfNegative(
2584 MFromCharCodeEmptyIfNegative* ins) {
2585 MDefinition* code = ins->code();
2587 MOZ_ASSERT(code->type() == MIRType::Int32);
2589 auto* lir = new (alloc()) LFromCharCodeEmptyIfNegative(useRegister(code));
2590 define(lir, ins);
2591 assignSafepoint(lir, ins);
2594 void LIRGenerator::visitFromCharCodeUndefinedIfNegative(
2595 MFromCharCodeUndefinedIfNegative* ins) {
2596 MDefinition* code = ins->code();
2598 MOZ_ASSERT(code->type() == MIRType::Int32);
2600 auto* lir = new (alloc()) LFromCharCodeUndefinedIfNegative(useRegister(code));
2601 defineBox(lir, ins);
2602 assignSafepoint(lir, ins);
2605 void LIRGenerator::visitFromCodePoint(MFromCodePoint* ins) {
2606 MDefinition* codePoint = ins->codePoint();
2608 MOZ_ASSERT(codePoint->type() == MIRType::Int32);
2610 LFromCodePoint* lir =
2611 new (alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp());
2612 assignSnapshot(lir, ins->bailoutKind());
2613 define(lir, ins);
2614 assignSafepoint(lir, ins);
2617 void LIRGenerator::visitStringIncludes(MStringIncludes* ins) {
2618 auto* string = ins->string();
2619 MOZ_ASSERT(string->type() == MIRType::String);
2621 auto* searchStr = ins->searchString();
2622 MOZ_ASSERT(searchStr->type() == MIRType::String);
2624 if (searchStr->isConstant()) {
2625 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2626 size_t length = linear->length();
2627 if (length == 1 || length == 2) {
2628 LDefinition tempDef = LDefinition::BogusTemp();
2629 if (length > 1) {
2630 tempDef = temp();
2633 auto* lir = new (alloc()) LStringIncludesSIMD(useRegister(string), temp(),
2634 temp(), tempDef, linear);
2635 define(lir, ins);
2636 assignSafepoint(lir, ins);
2637 return;
2641 auto* lir = new (alloc()) LStringIncludes(useRegisterAtStart(string),
2642 useRegisterAtStart(searchStr));
2643 defineReturn(lir, ins);
2644 assignSafepoint(lir, ins);
2647 void LIRGenerator::visitStringIndexOf(MStringIndexOf* ins) {
2648 auto* string = ins->string();
2649 MOZ_ASSERT(string->type() == MIRType::String);
2651 auto* searchStr = ins->searchString();
2652 MOZ_ASSERT(searchStr->type() == MIRType::String);
2654 if (searchStr->isConstant()) {
2655 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2656 size_t length = linear->length();
2657 if (length == 1 || length == 2) {
2658 LDefinition tempDef = LDefinition::BogusTemp();
2659 if (length > 1) {
2660 tempDef = temp();
2663 auto* lir = new (alloc()) LStringIndexOfSIMD(useRegister(string), temp(),
2664 temp(), tempDef, linear);
2665 define(lir, ins);
2666 assignSafepoint(lir, ins);
2667 return;
2671 auto* lir = new (alloc())
2672 LStringIndexOf(useRegisterAtStart(string), useRegisterAtStart(searchStr));
2673 defineReturn(lir, ins);
2674 assignSafepoint(lir, ins);
2677 void LIRGenerator::visitStringLastIndexOf(MStringLastIndexOf* ins) {
2678 auto* string = ins->string();
2679 MOZ_ASSERT(string->type() == MIRType::String);
2681 auto* searchStr = ins->searchString();
2682 MOZ_ASSERT(searchStr->type() == MIRType::String);
2684 auto* lir = new (alloc()) LStringLastIndexOf(useRegisterAtStart(string),
2685 useRegisterAtStart(searchStr));
2686 defineReturn(lir, ins);
2687 assignSafepoint(lir, ins);
2690 void LIRGenerator::visitStringStartsWith(MStringStartsWith* ins) {
2691 auto* string = ins->string();
2692 MOZ_ASSERT(string->type() == MIRType::String);
2694 auto* searchStr = ins->searchString();
2695 MOZ_ASSERT(searchStr->type() == MIRType::String);
2697 if (searchStr->isConstant()) {
2698 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2700 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2701 auto* lir = new (alloc())
2702 LStringStartsWithInline(useRegister(string), temp(), linear);
2703 define(lir, ins);
2704 assignSafepoint(lir, ins);
2705 return;
2709 auto* lir = new (alloc()) LStringStartsWith(useRegisterAtStart(string),
2710 useRegisterAtStart(searchStr));
2711 defineReturn(lir, ins);
2712 assignSafepoint(lir, ins);
2715 void LIRGenerator::visitStringEndsWith(MStringEndsWith* ins) {
2716 auto* string = ins->string();
2717 MOZ_ASSERT(string->type() == MIRType::String);
2719 auto* searchStr = ins->searchString();
2720 MOZ_ASSERT(searchStr->type() == MIRType::String);
2722 if (searchStr->isConstant()) {
2723 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2725 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2726 auto* lir = new (alloc())
2727 LStringEndsWithInline(useRegister(string), temp(), linear);
2728 define(lir, ins);
2729 assignSafepoint(lir, ins);
2730 return;
2734 auto* lir = new (alloc()) LStringEndsWith(useRegisterAtStart(string),
2735 useRegisterAtStart(searchStr));
2736 defineReturn(lir, ins);
2737 assignSafepoint(lir, ins);
2740 void LIRGenerator::visitStringConvertCase(MStringConvertCase* ins) {
2741 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2743 if (ins->mode() == MStringConvertCase::LowerCase) {
2744 #ifdef JS_CODEGEN_X86
2745 // Due to lack of registers on x86, we reuse the string register as
2746 // temporary. As a result we only need four temporary registers and take a
2747 // bogus temporary as the fifth argument.
2748 LDefinition temp4 = LDefinition::BogusTemp();
2749 #else
2750 LDefinition temp4 = temp();
2751 #endif
2752 auto* lir = new (alloc())
2753 LStringToLowerCase(useRegister(ins->string()), temp(), temp(), temp(),
2754 temp4, tempByteOpRegister());
2755 define(lir, ins);
2756 assignSafepoint(lir, ins);
2757 } else {
2758 auto* lir =
2759 new (alloc()) LStringToUpperCase(useRegisterAtStart(ins->string()));
2760 defineReturn(lir, ins);
2761 assignSafepoint(lir, ins);
2765 void LIRGenerator::visitCharCodeConvertCase(MCharCodeConvertCase* ins) {
2766 MOZ_ASSERT(ins->code()->type() == MIRType::Int32);
2768 if (ins->mode() == MCharCodeConvertCase::LowerCase) {
2769 auto* lir = new (alloc())
2770 LCharCodeToLowerCase(useRegister(ins->code()), tempByteOpRegister());
2771 define(lir, ins);
2772 assignSafepoint(lir, ins);
2773 } else {
2774 auto* lir = new (alloc())
2775 LCharCodeToUpperCase(useRegister(ins->code()), tempByteOpRegister());
2776 define(lir, ins);
2777 assignSafepoint(lir, ins);
2781 void LIRGenerator::visitStringTrimStartIndex(MStringTrimStartIndex* ins) {
2782 auto* string = ins->string();
2783 MOZ_ASSERT(string->type() == MIRType::String);
2785 auto* lir = new (alloc()) LStringTrimStartIndex(useRegister(string));
2786 define(lir, ins);
2787 assignSafepoint(lir, ins);
2790 void LIRGenerator::visitStringTrimEndIndex(MStringTrimEndIndex* ins) {
2791 auto* string = ins->string();
2792 MOZ_ASSERT(string->type() == MIRType::String);
2794 auto* start = ins->start();
2795 MOZ_ASSERT(start->type() == MIRType::Int32);
2797 auto* lir = new (alloc())
2798 LStringTrimEndIndex(useRegister(string), useRegister(start));
2799 define(lir, ins);
2800 assignSafepoint(lir, ins);
2803 void LIRGenerator::visitStart(MStart* start) {}
2805 void LIRGenerator::visitNop(MNop* nop) {}
2807 void LIRGenerator::visitLimitedTruncate(MLimitedTruncate* nop) {
2808 redefine(nop, nop->input());
2811 void LIRGenerator::visitOsrEntry(MOsrEntry* entry) {
2812 LOsrEntry* lir = new (alloc()) LOsrEntry(temp());
2813 defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
2816 void LIRGenerator::visitOsrValue(MOsrValue* value) {
2817 LOsrValue* lir = new (alloc()) LOsrValue(useRegister(value->entry()));
2818 defineBox(lir, value);
2821 void LIRGenerator::visitOsrReturnValue(MOsrReturnValue* value) {
2822 LOsrReturnValue* lir =
2823 new (alloc()) LOsrReturnValue(useRegister(value->entry()));
2824 defineBox(lir, value);
2827 void LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain* object) {
2828 LOsrEnvironmentChain* lir =
2829 new (alloc()) LOsrEnvironmentChain(useRegister(object->entry()));
2830 define(lir, object);
2833 void LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject* object) {
2834 LOsrArgumentsObject* lir =
2835 new (alloc()) LOsrArgumentsObject(useRegister(object->entry()));
2836 define(lir, object);
2839 void LIRGenerator::visitToDouble(MToDouble* convert) {
2840 MDefinition* opd = convert->input();
2841 mozilla::DebugOnly<MToFPInstruction::ConversionKind> conversion =
2842 convert->conversion();
2844 switch (opd->type()) {
2845 case MIRType::Value: {
2846 LValueToDouble* lir = new (alloc()) LValueToDouble(useBox(opd));
2847 assignSnapshot(lir, convert->bailoutKind());
2848 define(lir, convert);
2849 break;
2852 case MIRType::Null:
2853 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2854 lowerConstantDouble(0, convert);
2855 break;
2857 case MIRType::Undefined:
2858 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2859 lowerConstantDouble(GenericNaN(), convert);
2860 break;
2862 case MIRType::Boolean:
2863 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2864 [[fallthrough]];
2866 case MIRType::Int32: {
2867 LInt32ToDouble* lir =
2868 new (alloc()) LInt32ToDouble(useRegisterAtStart(opd));
2869 define(lir, convert);
2870 break;
2873 case MIRType::Float32: {
2874 LFloat32ToDouble* lir =
2875 new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
2876 define(lir, convert);
2877 break;
2880 case MIRType::Double:
2881 redefine(convert, opd);
2882 break;
2884 default:
2885 // Objects might be effectful. Symbols will throw.
2886 // Strings are complicated - we don't handle them yet.
2887 MOZ_CRASH("unexpected type");
2891 void LIRGenerator::visitToFloat32(MToFloat32* convert) {
2892 MDefinition* opd = convert->input();
2893 mozilla::DebugOnly<MToFloat32::ConversionKind> conversion =
2894 convert->conversion();
2896 switch (opd->type()) {
2897 case MIRType::Value: {
2898 LValueToFloat32* lir = new (alloc()) LValueToFloat32(useBox(opd));
2899 assignSnapshot(lir, convert->bailoutKind());
2900 define(lir, convert);
2901 break;
2904 case MIRType::Null:
2905 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2906 lowerConstantFloat32(0, convert);
2907 break;
2909 case MIRType::Undefined:
2910 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2911 lowerConstantFloat32(GenericNaN(), convert);
2912 break;
2914 case MIRType::Boolean:
2915 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2916 [[fallthrough]];
2918 case MIRType::Int32: {
2919 LInt32ToFloat32* lir =
2920 new (alloc()) LInt32ToFloat32(useRegisterAtStart(opd));
2921 define(lir, convert);
2922 break;
2925 case MIRType::Double: {
2926 LDoubleToFloat32* lir =
2927 new (alloc()) LDoubleToFloat32(useRegisterAtStart(opd));
2928 define(lir, convert);
2929 break;
2932 case MIRType::Float32:
2933 redefine(convert, opd);
2934 break;
2936 default:
2937 // Objects might be effectful. Symbols will throw.
2938 // Strings are complicated - we don't handle them yet.
2939 MOZ_CRASH("unexpected type");
2943 void LIRGenerator::visitToNumberInt32(MToNumberInt32* convert) {
2944 MDefinition* opd = convert->input();
2946 switch (opd->type()) {
2947 case MIRType::Value: {
2948 auto* lir = new (alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(),
2949 LValueToInt32::NORMAL);
2950 assignSnapshot(lir, convert->bailoutKind());
2951 define(lir, convert);
2952 if (lir->mode() == LValueToInt32::TRUNCATE) {
2953 assignSafepoint(lir, convert);
2955 break;
2958 case MIRType::Null:
2959 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any);
2960 define(new (alloc()) LInteger(0), convert);
2961 break;
2963 case MIRType::Boolean:
2964 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any ||
2965 convert->conversion() ==
2966 IntConversionInputKind::NumbersOrBoolsOnly);
2967 redefine(convert, opd);
2968 break;
2970 case MIRType::Int32:
2971 redefine(convert, opd);
2972 break;
2974 case MIRType::Float32: {
2975 LFloat32ToInt32* lir = new (alloc()) LFloat32ToInt32(useRegister(opd));
2976 assignSnapshot(lir, convert->bailoutKind());
2977 define(lir, convert);
2978 break;
2981 case MIRType::Double: {
2982 LDoubleToInt32* lir = new (alloc()) LDoubleToInt32(useRegister(opd));
2983 assignSnapshot(lir, convert->bailoutKind());
2984 define(lir, convert);
2985 break;
2988 case MIRType::String:
2989 case MIRType::Symbol:
2990 case MIRType::BigInt:
2991 case MIRType::Object:
2992 case MIRType::Undefined:
2993 // Objects might be effectful. Symbols and BigInts throw. Undefined
2994 // coerces to NaN, not int32.
2995 MOZ_CRASH("ToInt32 invalid input type");
2997 default:
2998 MOZ_CRASH("unexpected type");
3002 void LIRGenerator::visitBooleanToInt32(MBooleanToInt32* convert) {
3003 MDefinition* opd = convert->input();
3004 MOZ_ASSERT(opd->type() == MIRType::Boolean);
3005 redefine(convert, opd);
3008 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) {
3009 MDefinition* opd = truncate->input();
3011 switch (opd->type()) {
3012 case MIRType::Value: {
3013 LValueToInt32* lir = new (alloc()) LValueToInt32(
3014 useBox(opd), tempDouble(), temp(), LValueToInt32::TRUNCATE);
3015 assignSnapshot(lir, truncate->bailoutKind());
3016 define(lir, truncate);
3017 assignSafepoint(lir, truncate);
3018 break;
3021 case MIRType::Null:
3022 case MIRType::Undefined:
3023 define(new (alloc()) LInteger(0), truncate);
3024 break;
3026 case MIRType::Int32:
3027 case MIRType::Boolean:
3028 redefine(truncate, opd);
3029 break;
3031 case MIRType::Double:
3032 // May call into JS::ToInt32() on the slow OOL path.
3033 gen->setNeedsStaticStackAlignment();
3034 lowerTruncateDToInt32(truncate);
3035 break;
3037 case MIRType::Float32:
3038 // May call into JS::ToInt32() on the slow OOL path.
3039 gen->setNeedsStaticStackAlignment();
3040 lowerTruncateFToInt32(truncate);
3041 break;
3043 default:
3044 // Objects might be effectful. Symbols throw.
3045 // Strings are complicated - we don't handle them yet.
3046 MOZ_CRASH("unexpected type");
3050 void LIRGenerator::visitInt32ToIntPtr(MInt32ToIntPtr* ins) {
3051 MDefinition* input = ins->input();
3052 MOZ_ASSERT(input->type() == MIRType::Int32);
3053 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3055 #ifdef JS_64BIT
3056 // If the result is only used by instructions that expect a bounds-checked
3057 // index, we must have eliminated or hoisted a bounds check and we can assume
3058 // the index is non-negative. This lets us generate more efficient code.
3059 if (ins->canBeNegative()) {
3060 bool canBeNegative = false;
3061 for (MUseDefIterator iter(ins); iter; iter++) {
3062 if (!iter.def()->isSpectreMaskIndex() &&
3063 !iter.def()->isLoadUnboxedScalar() &&
3064 !iter.def()->isStoreUnboxedScalar() &&
3065 !iter.def()->isLoadDataViewElement() &&
3066 !iter.def()->isStoreDataViewElement()) {
3067 canBeNegative = true;
3068 break;
3071 if (!canBeNegative) {
3072 ins->setCanNotBeNegative();
3076 if (ins->canBeNegative()) {
3077 auto* lir = new (alloc()) LInt32ToIntPtr(useAnyAtStart(input));
3078 define(lir, ins);
3079 } else {
3080 redefine(ins, input);
3082 #else
3083 // On 32-bit platforms this is a no-op.
3084 redefine(ins, input);
3085 #endif
3088 void LIRGenerator::visitNonNegativeIntPtrToInt32(
3089 MNonNegativeIntPtrToInt32* ins) {
3090 MDefinition* input = ins->input();
3091 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3092 MOZ_ASSERT(ins->type() == MIRType::Int32);
3094 #ifdef JS_64BIT
3095 auto* lir =
3096 new (alloc()) LNonNegativeIntPtrToInt32(useRegisterAtStart(input));
3097 assignSnapshot(lir, ins->bailoutKind());
3098 defineReuseInput(lir, ins, 0);
3099 #else
3100 // On 32-bit platforms this is a no-op.
3101 redefine(ins, input);
3102 #endif
3105 void LIRGenerator::visitWasmExtendU32Index(MWasmExtendU32Index* ins) {
3106 #ifdef JS_64BIT
3107 // Technically this produces an Int64 register and I guess we could clean that
3108 // up, but it's a 64-bit only operation, so it doesn't actually matter.
3110 MDefinition* input = ins->input();
3111 MOZ_ASSERT(input->type() == MIRType::Int32);
3112 MOZ_ASSERT(ins->type() == MIRType::Int64);
3114 // Input reuse is OK even on ARM64 because this node *must* reuse its input in
3115 // order not to generate any code at all, as is the intent.
3116 auto* lir = new (alloc()) LWasmExtendU32Index(useRegisterAtStart(input));
3117 defineReuseInput(lir, ins, 0);
3118 #else
3119 MOZ_CRASH("64-bit only");
3120 #endif
3123 void LIRGenerator::visitWasmWrapU32Index(MWasmWrapU32Index* ins) {
3124 MDefinition* input = ins->input();
3125 MOZ_ASSERT(input->type() == MIRType::Int64);
3126 MOZ_ASSERT(ins->type() == MIRType::Int32);
3128 // Tricky: On 64-bit, this just returns its input (except on MIPS64 there may
3129 // be a sign/zero extension). On 32-bit, it returns the low register of the
3130 // input, and should generate no code.
3132 // If this assertion does not hold then using "input" unadorned as an alias
3133 // for the low register will not work.
3134 #if defined(JS_NUNBOX32)
3135 static_assert(INT64LOW_INDEX == 0);
3136 #endif
3138 auto* lir = new (alloc()) LWasmWrapU32Index(useRegisterAtStart(input));
3139 defineReuseInput(lir, ins, 0);
3142 void LIRGenerator::visitIntPtrToDouble(MIntPtrToDouble* ins) {
3143 MDefinition* input = ins->input();
3144 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3145 MOZ_ASSERT(ins->type() == MIRType::Double);
3147 auto* lir = new (alloc()) LIntPtrToDouble(useRegister(input));
3148 define(lir, ins);
3151 void LIRGenerator::visitAdjustDataViewLength(MAdjustDataViewLength* ins) {
3152 MDefinition* input = ins->input();
3153 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3155 auto* lir = new (alloc()) LAdjustDataViewLength(useRegisterAtStart(input));
3156 assignSnapshot(lir, ins->bailoutKind());
3157 defineReuseInput(lir, ins, 0);
3160 void LIRGenerator::visitToBigInt(MToBigInt* ins) {
3161 MDefinition* opd = ins->input();
3163 switch (opd->type()) {
3164 case MIRType::Value: {
3165 auto* lir = new (alloc()) LValueToBigInt(useBox(opd));
3166 assignSnapshot(lir, ins->bailoutKind());
3167 define(lir, ins);
3168 assignSafepoint(lir, ins);
3169 break;
3172 case MIRType::BigInt:
3173 redefine(ins, opd);
3174 break;
3176 default:
3177 MOZ_CRASH("unexpected type");
3181 void LIRGenerator::visitToInt64(MToInt64* ins) {
3182 MDefinition* opd = ins->input();
3184 switch (opd->type()) {
3185 case MIRType::Value: {
3186 auto* lir = new (alloc()) LValueToInt64(useBox(opd), temp());
3187 assignSnapshot(lir, ins->bailoutKind());
3188 defineInt64(lir, ins);
3189 assignSafepoint(lir, ins);
3190 break;
3193 case MIRType::Boolean: {
3194 auto* lir = new (alloc()) LBooleanToInt64(useRegisterAtStart(opd));
3195 defineInt64(lir, ins);
3196 break;
3199 case MIRType::String: {
3200 auto* lir = new (alloc()) LStringToInt64(useRegister(opd));
3201 defineInt64(lir, ins);
3202 assignSafepoint(lir, ins);
3203 break;
3206 // An Int64 may be passed here from a BigInt to Int64 conversion.
3207 case MIRType::Int64: {
3208 redefine(ins, opd);
3209 break;
3212 default:
3213 // Undefined, Null, Number, and Symbol throw.
3214 // Objects may be effectful.
3215 // BigInt operands are eliminated by the type policy.
3216 MOZ_CRASH("unexpected type");
3220 void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64* ins) {
3221 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
3222 auto* lir = new (alloc()) LTruncateBigIntToInt64(useRegister(ins->input()));
3223 defineInt64(lir, ins);
3226 void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt* ins) {
3227 MOZ_ASSERT(ins->input()->type() == MIRType::Int64);
3228 auto* lir =
3229 new (alloc()) LInt64ToBigInt(useInt64Register(ins->input()), temp());
3230 define(lir, ins);
3231 assignSafepoint(lir, ins);
3234 void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) {
3235 MDefinition* input = ins->input();
3236 switch (input->type()) {
3237 case MIRType::Double:
3238 case MIRType::Float32: {
3239 auto* lir = new (alloc()) LWasmTruncateToInt32(useRegisterAtStart(input));
3240 define(lir, ins);
3241 break;
3243 default:
3244 MOZ_CRASH("unexpected type in WasmTruncateToInt32");
3248 void LIRGenerator::visitWasmBuiltinTruncateToInt32(
3249 MWasmBuiltinTruncateToInt32* truncate) {
3250 mozilla::DebugOnly<MDefinition*> opd = truncate->input();
3251 MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
3253 // May call into JS::ToInt32() on the slow OOL path.
3254 gen->setNeedsStaticStackAlignment();
3255 lowerWasmBuiltinTruncateToInt32(truncate);
3258 void LIRGenerator::visitWasmAnyRefFromJSValue(MWasmAnyRefFromJSValue* ins) {
3259 LWasmAnyRefFromJSValue* lir =
3260 new (alloc()) LWasmAnyRefFromJSValue(useBox(ins->input()), tempDouble());
3261 define(lir, ins);
3262 assignSafepoint(lir, ins);
3265 void LIRGenerator::visitWasmAnyRefFromJSObject(MWasmAnyRefFromJSObject* ins) {
3266 LWasmAnyRefFromJSObject* lir =
3267 new (alloc()) LWasmAnyRefFromJSObject(useRegisterAtStart(ins->input()));
3268 define(lir, ins);
3271 void LIRGenerator::visitWasmAnyRefFromJSString(MWasmAnyRefFromJSString* ins) {
3272 LWasmAnyRefFromJSString* lir =
3273 new (alloc()) LWasmAnyRefFromJSString(useRegisterAtStart(ins->input()));
3274 define(lir, ins);
3277 void LIRGenerator::visitWasmNewI31Ref(MWasmNewI31Ref* ins) {
3278 LWasmNewI31Ref* lir = new (alloc()) LWasmNewI31Ref(useRegister(ins->input()));
3279 define(lir, ins);
3282 void LIRGenerator::visitWasmI31RefGet(MWasmI31RefGet* ins) {
3283 LWasmI31RefGet* lir = new (alloc()) LWasmI31RefGet(useRegister(ins->input()));
3284 define(lir, ins);
3287 void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) {
3288 define(new (alloc()) LWrapInt64ToInt32(useInt64AtStart(ins->input())), ins);
3291 void LIRGenerator::visitToString(MToString* ins) {
3292 MDefinition* opd = ins->input();
3294 switch (opd->type()) {
3295 case MIRType::Null: {
3296 const JSAtomState& names = gen->runtime->names();
3297 LPointer* lir = new (alloc()) LPointer(names.null);
3298 define(lir, ins);
3299 break;
3302 case MIRType::Undefined: {
3303 const JSAtomState& names = gen->runtime->names();
3304 LPointer* lir = new (alloc()) LPointer(names.undefined);
3305 define(lir, ins);
3306 break;
3309 case MIRType::Boolean: {
3310 LBooleanToString* lir = new (alloc()) LBooleanToString(useRegister(opd));
3311 define(lir, ins);
3312 break;
3315 case MIRType::Double: {
3316 LDoubleToString* lir =
3317 new (alloc()) LDoubleToString(useRegister(opd), temp());
3319 define(lir, ins);
3320 assignSafepoint(lir, ins);
3321 break;
3324 case MIRType::Int32: {
3325 LIntToString* lir = new (alloc()) LIntToString(useRegister(opd));
3327 define(lir, ins);
3328 assignSafepoint(lir, ins);
3329 break;
3332 case MIRType::String:
3333 redefine(ins, ins->input());
3334 break;
3336 case MIRType::Value: {
3337 LValueToString* lir =
3338 new (alloc()) LValueToString(useBox(opd), tempToUnbox());
3339 if (ins->needsSnapshot()) {
3340 assignSnapshot(lir, ins->bailoutKind());
3342 define(lir, ins);
3343 assignSafepoint(lir, ins);
3344 break;
3347 default:
3348 // Float32, symbols, bigint, and objects are not supported.
3349 MOZ_CRASH("unexpected type");
3353 void LIRGenerator::visitRegExp(MRegExp* ins) {
3354 LRegExp* lir = new (alloc()) LRegExp(temp());
3355 define(lir, ins);
3356 assignSafepoint(lir, ins);
3359 void LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) {
3360 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3361 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3362 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3364 LRegExpMatcher* lir = new (alloc()) LRegExpMatcher(
3365 useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3366 useFixedAtStart(ins->string(), RegExpMatcherStringReg),
3367 useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg));
3368 defineReturn(lir, ins);
3369 assignSafepoint(lir, ins);
3372 void LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) {
3373 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3374 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3375 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3377 LRegExpSearcher* lir = new (alloc()) LRegExpSearcher(
3378 useFixedAtStart(ins->regexp(), RegExpSearcherRegExpReg),
3379 useFixedAtStart(ins->string(), RegExpSearcherStringReg),
3380 useFixedAtStart(ins->lastIndex(), RegExpSearcherLastIndexReg));
3381 defineReturn(lir, ins);
3382 assignSafepoint(lir, ins);
3385 void LIRGenerator::visitRegExpSearcherLastLimit(MRegExpSearcherLastLimit* ins) {
3386 auto* lir = new (alloc()) LRegExpSearcherLastLimit(temp());
3387 define(lir, ins);
3390 void LIRGenerator::visitRegExpExecMatch(MRegExpExecMatch* ins) {
3391 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3392 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3394 auto* lir = new (alloc())
3395 LRegExpExecMatch(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3396 useFixedAtStart(ins->string(), RegExpMatcherStringReg));
3397 defineReturn(lir, ins);
3398 assignSafepoint(lir, ins);
3401 void LIRGenerator::visitRegExpExecTest(MRegExpExecTest* ins) {
3402 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3403 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3405 auto* lir = new (alloc())
3406 LRegExpExecTest(useFixedAtStart(ins->regexp(), RegExpExecTestRegExpReg),
3407 useFixedAtStart(ins->string(), RegExpExecTestStringReg));
3408 defineReturn(lir, ins);
3409 assignSafepoint(lir, ins);
3412 void LIRGenerator::visitRegExpHasCaptureGroups(MRegExpHasCaptureGroups* ins) {
3413 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3414 MOZ_ASSERT(ins->input()->type() == MIRType::String);
3415 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3417 auto* lir = new (alloc()) LRegExpHasCaptureGroups(useRegister(ins->regexp()),
3418 useRegister(ins->input()));
3419 define(lir, ins);
3420 assignSafepoint(lir, ins);
3423 void LIRGenerator::visitRegExpPrototypeOptimizable(
3424 MRegExpPrototypeOptimizable* ins) {
3425 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3426 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3427 LRegExpPrototypeOptimizable* lir = new (alloc())
3428 LRegExpPrototypeOptimizable(useRegister(ins->object()), temp());
3429 define(lir, ins);
3432 void LIRGenerator::visitRegExpInstanceOptimizable(
3433 MRegExpInstanceOptimizable* ins) {
3434 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3435 MOZ_ASSERT(ins->proto()->type() == MIRType::Object);
3436 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3437 LRegExpInstanceOptimizable* lir = new (alloc()) LRegExpInstanceOptimizable(
3438 useRegister(ins->object()), useRegister(ins->proto()), temp());
3439 define(lir, ins);
3442 void LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) {
3443 MOZ_ASSERT(ins->str()->type() == MIRType::String);
3444 MOZ_ASSERT(ins->type() == MIRType::Int32);
3445 LGetFirstDollarIndex* lir = new (alloc())
3446 LGetFirstDollarIndex(useRegister(ins->str()), temp(), temp(), temp());
3447 define(lir, ins);
3448 assignSafepoint(lir, ins);
3451 void LIRGenerator::visitStringReplace(MStringReplace* ins) {
3452 MOZ_ASSERT(ins->pattern()->type() == MIRType::String);
3453 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3454 MOZ_ASSERT(ins->replacement()->type() == MIRType::String);
3456 LStringReplace* lir = new (alloc())
3457 LStringReplace(useRegisterOrConstantAtStart(ins->string()),
3458 useRegisterAtStart(ins->pattern()),
3459 useRegisterOrConstantAtStart(ins->replacement()));
3460 defineReturn(lir, ins);
3461 assignSafepoint(lir, ins);
3464 void LIRGenerator::visitBinaryCache(MBinaryCache* ins) {
3465 MDefinition* lhs = ins->getOperand(0);
3466 MDefinition* rhs = ins->getOperand(1);
3468 MOZ_ASSERT(ins->type() == MIRType::Value || ins->type() == MIRType::Boolean);
3469 LInstruction* lir;
3470 if (ins->type() == MIRType::Value) {
3471 LBinaryValueCache* valueLir = new (alloc()) LBinaryValueCache(
3472 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3473 defineBox(valueLir, ins);
3474 lir = valueLir;
3475 } else {
3476 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3477 LBinaryBoolCache* boolLir = new (alloc()) LBinaryBoolCache(
3478 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3479 define(boolLir, ins);
3480 lir = boolLir;
3482 assignSafepoint(lir, ins);
3485 void LIRGenerator::visitUnaryCache(MUnaryCache* ins) {
3486 MDefinition* input = ins->getOperand(0);
3487 MOZ_ASSERT(ins->type() == MIRType::Value);
3489 LUnaryCache* lir = new (alloc()) LUnaryCache(useBox(input));
3490 defineBox(lir, ins);
3491 assignSafepoint(lir, ins);
3494 void LIRGenerator::visitModuleMetadata(MModuleMetadata* ins) {
3495 LModuleMetadata* lir = new (alloc()) LModuleMetadata();
3496 defineReturn(lir, ins);
3497 assignSafepoint(lir, ins);
3500 void LIRGenerator::visitDynamicImport(MDynamicImport* ins) {
3501 LDynamicImport* lir = new (alloc()) LDynamicImport(
3502 useBoxAtStart(ins->specifier()), useBoxAtStart(ins->options()));
3503 defineReturn(lir, ins);
3504 assignSafepoint(lir, ins);
3507 void LIRGenerator::visitLambda(MLambda* ins) {
3508 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3510 auto* lir =
3511 new (alloc()) LLambda(useRegister(ins->environmentChain()), temp());
3512 define(lir, ins);
3513 assignSafepoint(lir, ins);
3516 void LIRGenerator::visitFunctionWithProto(MFunctionWithProto* ins) {
3517 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3518 MOZ_ASSERT(ins->prototype()->type() == MIRType::Object);
3520 auto* lir = new (alloc())
3521 LFunctionWithProto(useRegisterAtStart(ins->environmentChain()),
3522 useRegisterAtStart(ins->prototype()));
3523 defineReturn(lir, ins);
3524 assignSafepoint(lir, ins);
3527 void LIRGenerator::visitSetFunName(MSetFunName* ins) {
3528 MOZ_ASSERT(ins->fun()->type() == MIRType::Object);
3529 MOZ_ASSERT(ins->name()->type() == MIRType::Value);
3531 LSetFunName* lir = new (alloc())
3532 LSetFunName(useRegisterAtStart(ins->fun()), useBoxAtStart(ins->name()));
3533 add(lir, ins);
3534 assignSafepoint(lir, ins);
3537 void LIRGenerator::visitNewLexicalEnvironmentObject(
3538 MNewLexicalEnvironmentObject* ins) {
3539 auto* lir = new (alloc()) LNewLexicalEnvironmentObject(temp());
3541 define(lir, ins);
3542 assignSafepoint(lir, ins);
3545 void LIRGenerator::visitNewClassBodyEnvironmentObject(
3546 MNewClassBodyEnvironmentObject* ins) {
3547 auto* lir = new (alloc()) LNewClassBodyEnvironmentObject(temp());
3549 define(lir, ins);
3550 assignSafepoint(lir, ins);
3553 void LIRGenerator::visitNewVarEnvironmentObject(MNewVarEnvironmentObject* ins) {
3554 auto* lir = new (alloc()) LNewVarEnvironmentObject(temp());
3556 define(lir, ins);
3557 assignSafepoint(lir, ins);
3560 void LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins) {
3561 MDefinition* obj = ins->object();
3562 MOZ_ASSERT(obj->type() == MIRType::Object);
3564 add(new (alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
3567 void LIRGenerator::visitDebugEnterGCUnsafeRegion(
3568 MDebugEnterGCUnsafeRegion* ins) {
3569 add(new (alloc()) LDebugEnterGCUnsafeRegion(temp()), ins);
3572 void LIRGenerator::visitDebugLeaveGCUnsafeRegion(
3573 MDebugLeaveGCUnsafeRegion* ins) {
3574 add(new (alloc()) LDebugLeaveGCUnsafeRegion(temp()), ins);
3577 void LIRGenerator::visitSlots(MSlots* ins) {
3578 define(new (alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
3581 void LIRGenerator::visitElements(MElements* ins) {
3582 define(new (alloc()) LElements(useRegisterAtStart(ins->object())), ins);
3585 void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot* ins) {
3586 MOZ_ASSERT(ins->type() == MIRType::Value);
3587 if (ins->usedAsPropertyKey()) {
3588 auto* lir = new (alloc())
3589 LLoadDynamicSlotAndAtomize(useRegister(ins->slots()), temp());
3590 defineBox(lir, ins);
3591 assignSafepoint(lir, ins);
3592 } else {
3593 defineBox(new (alloc()) LLoadDynamicSlotV(useRegisterAtStart(ins->slots())),
3594 ins);
3598 void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins) {
3599 define(new (alloc())
3600 LFunctionEnvironment(useRegisterAtStart(ins->function())),
3601 ins);
3604 void LIRGenerator::visitHomeObject(MHomeObject* ins) {
3605 define(new (alloc()) LHomeObject(useRegisterAtStart(ins->function())), ins);
3608 void LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase* ins) {
3609 MOZ_ASSERT(ins->homeObject()->type() == MIRType::Object);
3610 MOZ_ASSERT(ins->type() == MIRType::Value);
3612 auto lir =
3613 new (alloc()) LHomeObjectSuperBase(useRegisterAtStart(ins->homeObject()));
3614 defineBox(lir, ins);
3617 void LIRGenerator::visitInterruptCheck(MInterruptCheck* ins) {
3618 LInstruction* lir = new (alloc()) LInterruptCheck();
3619 add(lir, ins);
3620 assignSafepoint(lir, ins);
3623 void LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck* ins) {
3624 auto* lir =
3625 new (alloc()) LWasmInterruptCheck(useRegisterAtStart(ins->instance()));
3626 add(lir, ins);
3627 assignWasmSafepoint(lir);
3630 void LIRGenerator::visitWasmTrap(MWasmTrap* ins) {
3631 add(new (alloc()) LWasmTrap, ins);
3634 void LIRGenerator::visitWasmTrapIfNull(MWasmTrapIfNull* ins) {
3635 auto* lir = new (alloc()) LWasmTrapIfNull(useRegister(ins->ref()));
3636 add(lir, ins);
3639 void LIRGenerator::visitWasmReinterpret(MWasmReinterpret* ins) {
3640 if (ins->type() == MIRType::Int64) {
3641 defineInt64(new (alloc())
3642 LWasmReinterpretToI64(useRegisterAtStart(ins->input())),
3643 ins);
3644 } else if (ins->input()->type() == MIRType::Int64) {
3645 define(new (alloc())
3646 LWasmReinterpretFromI64(useInt64RegisterAtStart(ins->input())),
3647 ins);
3648 } else {
3649 define(new (alloc()) LWasmReinterpret(useRegisterAtStart(ins->input())),
3650 ins);
3654 void LIRGenerator::visitStoreDynamicSlot(MStoreDynamicSlot* ins) {
3655 LInstruction* lir;
3657 switch (ins->value()->type()) {
3658 case MIRType::Value:
3659 lir = new (alloc())
3660 LStoreDynamicSlotV(useRegister(ins->slots()), useBox(ins->value()));
3661 add(lir, ins);
3662 break;
3664 case MIRType::Double:
3665 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3666 useRegister(ins->value())),
3667 ins);
3668 break;
3670 case MIRType::Float32:
3671 MOZ_CRASH("Float32 shouldn't be stored in a slot.");
3673 default:
3674 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3675 useRegisterOrConstant(ins->value())),
3676 ins);
3677 break;
3681 // Returns true iff |def| is a constant that's either not a GC thing or is not
3682 // allocated in the nursery.
3683 static bool IsNonNurseryConstant(MDefinition* def) {
3684 if (!def->isConstant()) {
3685 return false;
3687 Value v = def->toConstant()->toJSValue();
3688 return !v.isGCThing() || !IsInsideNursery(v.toGCThing());
3691 void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) {
3692 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3694 // LPostWriteBarrier assumes that if it has a constant object then that
3695 // object is tenured, and does not need to be tested for being in the
3696 // nursery. Ensure that assumption holds by lowering constant nursery
3697 // objects to a register.
3698 bool useConstantObject = IsNonNurseryConstant(ins->object());
3700 switch (ins->value()->type()) {
3701 case MIRType::Object: {
3702 LDefinition tmp =
3703 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3704 LPostWriteBarrierO* lir = new (alloc())
3705 LPostWriteBarrierO(useConstantObject ? useOrConstant(ins->object())
3706 : useRegister(ins->object()),
3707 useRegister(ins->value()), tmp);
3708 add(lir, ins);
3709 assignSafepoint(lir, ins);
3710 break;
3712 case MIRType::String: {
3713 LDefinition tmp =
3714 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3715 LPostWriteBarrierS* lir = new (alloc())
3716 LPostWriteBarrierS(useConstantObject ? useOrConstant(ins->object())
3717 : useRegister(ins->object()),
3718 useRegister(ins->value()), tmp);
3719 add(lir, ins);
3720 assignSafepoint(lir, ins);
3721 break;
3723 case MIRType::BigInt: {
3724 LDefinition tmp =
3725 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3726 auto* lir = new (alloc())
3727 LPostWriteBarrierBI(useConstantObject ? useOrConstant(ins->object())
3728 : useRegister(ins->object()),
3729 useRegister(ins->value()), tmp);
3730 add(lir, ins);
3731 assignSafepoint(lir, ins);
3732 break;
3734 case MIRType::Value: {
3735 LDefinition tmp =
3736 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3737 LPostWriteBarrierV* lir = new (alloc())
3738 LPostWriteBarrierV(useConstantObject ? useOrConstant(ins->object())
3739 : useRegister(ins->object()),
3740 useBox(ins->value()), tmp);
3741 add(lir, ins);
3742 assignSafepoint(lir, ins);
3743 break;
3745 default:
3746 // Currently, only objects and strings can be in the nursery. Other
3747 // instruction types cannot hold nursery pointers.
3748 break;
3752 void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) {
3753 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3754 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3756 // LPostWriteElementBarrier assumes that if it has a constant object then that
3757 // object is tenured, and does not need to be tested for being in the
3758 // nursery. Ensure that assumption holds by lowering constant nursery
3759 // objects to a register.
3760 bool useConstantObject =
3761 ins->object()->isConstant() &&
3762 !IsInsideNursery(&ins->object()->toConstant()->toObject());
3764 switch (ins->value()->type()) {
3765 case MIRType::Object: {
3766 LDefinition tmp =
3767 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3768 LPostWriteElementBarrierO* lir = new (alloc()) LPostWriteElementBarrierO(
3769 useConstantObject ? useOrConstant(ins->object())
3770 : useRegister(ins->object()),
3771 useRegister(ins->value()), useRegister(ins->index()), tmp);
3772 add(lir, ins);
3773 assignSafepoint(lir, ins);
3774 break;
3776 case MIRType::String: {
3777 LDefinition tmp =
3778 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3779 LPostWriteElementBarrierS* lir = new (alloc()) LPostWriteElementBarrierS(
3780 useConstantObject ? useOrConstant(ins->object())
3781 : useRegister(ins->object()),
3782 useRegister(ins->value()), useRegister(ins->index()), tmp);
3783 add(lir, ins);
3784 assignSafepoint(lir, ins);
3785 break;
3787 case MIRType::BigInt: {
3788 LDefinition tmp =
3789 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3790 auto* lir = new (alloc()) LPostWriteElementBarrierBI(
3791 useConstantObject ? useOrConstant(ins->object())
3792 : useRegister(ins->object()),
3793 useRegister(ins->value()), useRegister(ins->index()), tmp);
3794 add(lir, ins);
3795 assignSafepoint(lir, ins);
3796 break;
3798 case MIRType::Value: {
3799 LDefinition tmp =
3800 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3801 LPostWriteElementBarrierV* lir = new (alloc()) LPostWriteElementBarrierV(
3802 useConstantObject ? useOrConstant(ins->object())
3803 : useRegister(ins->object()),
3804 useRegister(ins->index()), useBox(ins->value()), tmp);
3805 add(lir, ins);
3806 assignSafepoint(lir, ins);
3807 break;
3809 default:
3810 // Currently, only objects, strings, and bigints can be in the nursery.
3811 // Other instruction types cannot hold nursery pointers.
3812 break;
3816 void LIRGenerator::visitAssertCanElidePostWriteBarrier(
3817 MAssertCanElidePostWriteBarrier* ins) {
3818 auto* lir = new (alloc()) LAssertCanElidePostWriteBarrier(
3819 useRegister(ins->object()), useBox(ins->value()), temp());
3820 add(lir, ins);
3823 void LIRGenerator::visitArrayLength(MArrayLength* ins) {
3824 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3825 auto* lir = new (alloc()) LArrayLength(useRegisterAtStart(ins->elements()));
3826 assignSnapshot(lir, ins->bailoutKind());
3827 define(lir, ins);
3830 void LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) {
3831 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3832 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3834 MOZ_ASSERT(ins->index()->isConstant());
3835 add(new (alloc()) LSetArrayLength(useRegister(ins->elements()),
3836 useRegisterOrConstant(ins->index())),
3837 ins);
3840 void LIRGenerator::visitFunctionLength(MFunctionLength* ins) {
3841 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3843 auto* lir = new (alloc()) LFunctionLength(useRegister(ins->function()));
3844 assignSnapshot(lir, ins->bailoutKind());
3845 define(lir, ins);
3848 void LIRGenerator::visitFunctionName(MFunctionName* ins) {
3849 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3851 auto* lir = new (alloc()) LFunctionName(useRegister(ins->function()));
3852 assignSnapshot(lir, ins->bailoutKind());
3853 define(lir, ins);
3856 void LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator* ins) {
3857 MOZ_ASSERT(ins->iter()->type() == MIRType::Object);
3858 MOZ_ASSERT(ins->result()->type() == MIRType::Object);
3859 auto lir = new (alloc()) LGetNextEntryForIterator(useRegister(ins->iter()),
3860 useRegister(ins->result()),
3861 temp(), temp(), temp());
3862 define(lir, ins);
3865 void LIRGenerator::visitArrayBufferByteLength(MArrayBufferByteLength* ins) {
3866 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3867 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3869 auto* lir =
3870 new (alloc()) LArrayBufferByteLength(useRegisterAtStart(ins->object()));
3871 define(lir, ins);
3874 void LIRGenerator::visitArrayBufferViewLength(MArrayBufferViewLength* ins) {
3875 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3876 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3878 auto* lir =
3879 new (alloc()) LArrayBufferViewLength(useRegisterAtStart(ins->object()));
3880 define(lir, ins);
3883 void LIRGenerator::visitArrayBufferViewByteOffset(
3884 MArrayBufferViewByteOffset* ins) {
3885 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3886 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3888 auto* lir = new (alloc())
3889 LArrayBufferViewByteOffset(useRegisterAtStart(ins->object()));
3890 define(lir, ins);
3893 void LIRGenerator::visitArrayBufferViewElements(MArrayBufferViewElements* ins) {
3894 MOZ_ASSERT(ins->type() == MIRType::Elements);
3895 define(new (alloc())
3896 LArrayBufferViewElements(useRegisterAtStart(ins->object())),
3897 ins);
3900 void LIRGenerator::visitTypedArrayElementSize(MTypedArrayElementSize* ins) {
3901 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3902 define(new (alloc())
3903 LTypedArrayElementSize(useRegisterAtStart(ins->object())),
3904 ins);
3907 void LIRGenerator::visitGuardHasAttachedArrayBuffer(
3908 MGuardHasAttachedArrayBuffer* ins) {
3909 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3911 auto* lir = new (alloc())
3912 LGuardHasAttachedArrayBuffer(useRegister(ins->object()), temp());
3913 assignSnapshot(lir, ins->bailoutKind());
3914 add(lir, ins);
3915 redefine(ins, ins->object());
3918 void LIRGenerator::visitGuardNumberToIntPtrIndex(
3919 MGuardNumberToIntPtrIndex* ins) {
3920 MDefinition* input = ins->input();
3921 MOZ_ASSERT(input->type() == MIRType::Double);
3923 auto* lir = new (alloc()) LGuardNumberToIntPtrIndex(useRegister(input));
3924 if (!ins->supportOOB()) {
3925 assignSnapshot(lir, ins->bailoutKind());
3927 define(lir, ins);
3930 void LIRGenerator::visitInitializedLength(MInitializedLength* ins) {
3931 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3932 define(new (alloc()) LInitializedLength(useRegisterAtStart(ins->elements())),
3933 ins);
3936 void LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) {
3937 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3938 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3940 MOZ_ASSERT(ins->index()->isConstant());
3941 add(new (alloc()) LSetInitializedLength(useRegister(ins->elements()),
3942 useRegisterOrConstant(ins->index())),
3943 ins);
3946 void LIRGenerator::visitNot(MNot* ins) {
3947 MDefinition* op = ins->input();
3949 // String is converted to length of string in the type analysis phase (see
3950 // TestPolicy).
3951 MOZ_ASSERT(op->type() != MIRType::String);
3953 // - boolean: x xor 1
3954 // - int32: LCompare(x, 0)
3955 // - double: LCompare(x, 0)
3956 // - null or undefined: true
3957 // - symbol: false
3958 // - bigint: LNotBI(x)
3959 // - object: false if it never emulates undefined, else LNotO(x)
3960 switch (op->type()) {
3961 case MIRType::Boolean: {
3962 MConstant* cons = MConstant::New(alloc(), Int32Value(1));
3963 ins->block()->insertBefore(ins, cons);
3964 lowerForALU(new (alloc()) LBitOpI(JSOp::BitXor), ins, op, cons);
3965 break;
3967 case MIRType::Int32:
3968 define(new (alloc()) LNotI(useRegisterAtStart(op)), ins);
3969 break;
3970 case MIRType::Int64:
3971 define(new (alloc()) LNotI64(useInt64RegisterAtStart(op)), ins);
3972 break;
3973 case MIRType::Double:
3974 define(new (alloc()) LNotD(useRegister(op)), ins);
3975 break;
3976 case MIRType::Float32:
3977 define(new (alloc()) LNotF(useRegister(op)), ins);
3978 break;
3979 case MIRType::Undefined:
3980 case MIRType::Null:
3981 define(new (alloc()) LInteger(1), ins);
3982 break;
3983 case MIRType::Symbol:
3984 define(new (alloc()) LInteger(0), ins);
3985 break;
3986 case MIRType::BigInt:
3987 define(new (alloc()) LNotBI(useRegisterAtStart(op)), ins);
3988 break;
3989 case MIRType::Object:
3990 define(new (alloc()) LNotO(useRegister(op)), ins);
3991 break;
3992 case MIRType::Value: {
3993 auto* lir = new (alloc()) LNotV(useBox(op), tempDouble(), tempToUnbox());
3994 define(lir, ins);
3995 break;
3998 default:
3999 MOZ_CRASH("Unexpected MIRType.");
4003 void LIRGenerator::visitBoundsCheck(MBoundsCheck* ins) {
4004 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4005 MOZ_ASSERT(ins->index()->type() == ins->type());
4006 MOZ_ASSERT(ins->length()->type() == ins->type());
4008 if (!ins->fallible()) {
4009 return;
4012 LInstruction* check;
4013 if (ins->minimum() || ins->maximum()) {
4014 check = new (alloc())
4015 LBoundsCheckRange(useRegisterOrInt32Constant(ins->index()),
4016 useAny(ins->length()), temp());
4017 } else {
4018 check = new (alloc()) LBoundsCheck(useRegisterOrInt32Constant(ins->index()),
4019 useAnyOrInt32Constant(ins->length()));
4021 assignSnapshot(check, ins->bailoutKind());
4022 add(check, ins);
4025 void LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins) {
4026 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4027 MOZ_ASSERT(ins->index()->type() == ins->type());
4028 MOZ_ASSERT(ins->length()->type() == ins->type());
4030 auto* lir = new (alloc())
4031 LSpectreMaskIndex(useRegister(ins->index()), useAny(ins->length()));
4032 define(lir, ins);
4035 void LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins) {
4036 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4038 if (!ins->fallible()) {
4039 return;
4042 LInstruction* check =
4043 new (alloc()) LBoundsCheckLower(useRegister(ins->index()));
4044 assignSnapshot(check, ins->bailoutKind());
4045 add(check, ins);
4048 void LIRGenerator::visitInArray(MInArray* ins) {
4049 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4050 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4051 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4052 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4054 auto* lir = new (alloc()) LInArray(useRegister(ins->elements()),
4055 useRegisterOrConstant(ins->index()),
4056 useRegister(ins->initLength()));
4057 if (ins->needsNegativeIntCheck()) {
4058 assignSnapshot(lir, ins->bailoutKind());
4060 define(lir, ins);
4063 void LIRGenerator::visitGuardElementNotHole(MGuardElementNotHole* ins) {
4064 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4065 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4067 auto* guard = new (alloc())
4068 LGuardElementNotHole(useRegisterAtStart(ins->elements()),
4069 useRegisterOrConstantAtStart(ins->index()));
4070 assignSnapshot(guard, ins->bailoutKind());
4071 add(guard, ins);
4074 void LIRGenerator::visitLoadElement(MLoadElement* ins) {
4075 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4076 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4077 MOZ_ASSERT(ins->type() == MIRType::Value);
4079 auto* lir = new (alloc()) LLoadElementV(useRegister(ins->elements()),
4080 useRegisterOrConstant(ins->index()));
4081 assignSnapshot(lir, ins->bailoutKind());
4082 defineBox(lir, ins);
4085 void LIRGenerator::visitLoadElementHole(MLoadElementHole* ins) {
4086 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4087 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4088 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4089 MOZ_ASSERT(ins->type() == MIRType::Value);
4091 LLoadElementHole* lir = new (alloc())
4092 LLoadElementHole(useRegister(ins->elements()), useRegister(ins->index()),
4093 useRegister(ins->initLength()));
4094 if (ins->needsNegativeIntCheck()) {
4095 assignSnapshot(lir, ins->bailoutKind());
4097 defineBox(lir, ins);
4100 void LIRGenerator::visitStoreElement(MStoreElement* ins) {
4101 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4102 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4104 const LUse elements = useRegister(ins->elements());
4105 const LAllocation index = useRegisterOrConstant(ins->index());
4107 switch (ins->value()->type()) {
4108 case MIRType::Value: {
4109 LInstruction* lir =
4110 new (alloc()) LStoreElementV(elements, index, useBox(ins->value()));
4111 if (ins->fallible()) {
4112 assignSnapshot(lir, ins->bailoutKind());
4114 add(lir, ins);
4115 break;
4118 default: {
4119 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4120 LInstruction* lir = new (alloc()) LStoreElementT(elements, index, value);
4121 if (ins->fallible()) {
4122 assignSnapshot(lir, ins->bailoutKind());
4124 add(lir, ins);
4125 break;
4130 void LIRGenerator::visitStoreHoleValueElement(MStoreHoleValueElement* ins) {
4131 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4132 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4134 auto* lir = new (alloc()) LStoreHoleValueElement(useRegister(ins->elements()),
4135 useRegister(ins->index()));
4136 add(lir, ins);
4139 static bool BoundsCheckNeedsSpectreTemp() {
4140 // On x86, spectreBoundsCheck32 can emit better code if it has a scratch
4141 // register and index masking is enabled.
4142 #ifdef JS_CODEGEN_X86
4143 return JitOptions.spectreIndexMasking;
4144 #else
4145 return false;
4146 #endif
4149 void LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) {
4150 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4151 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4153 const LUse object = useRegister(ins->object());
4154 const LUse elements = useRegister(ins->elements());
4155 const LAllocation index = useRegister(ins->index());
4157 LInstruction* lir;
4158 switch (ins->value()->type()) {
4159 case MIRType::Value:
4160 lir = new (alloc()) LStoreElementHoleV(object, elements, index,
4161 useBox(ins->value()), temp());
4162 break;
4164 default: {
4165 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4166 lir = new (alloc())
4167 LStoreElementHoleT(object, elements, index, value, temp());
4168 break;
4172 assignSnapshot(lir, ins->bailoutKind());
4173 add(lir, ins);
4174 assignSafepoint(lir, ins);
4177 void LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) {
4178 define(new (alloc()) LEffectiveAddress(useRegister(ins->base()),
4179 useRegister(ins->index())),
4180 ins);
4183 void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) {
4184 MOZ_ASSERT(ins->type() == MIRType::Value);
4186 auto* lir =
4187 new (alloc()) LArrayPopShift(useRegister(ins->object()), temp(), temp());
4188 assignSnapshot(lir, ins->bailoutKind());
4189 defineBox(lir, ins);
4191 if (ins->mode() == MArrayPopShift::Shift) {
4192 assignSafepoint(lir, ins);
4196 void LIRGenerator::visitArrayPush(MArrayPush* ins) {
4197 MOZ_ASSERT(ins->type() == MIRType::Int32);
4198 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4200 LUse object = useRegister(ins->object());
4202 LDefinition spectreTemp =
4203 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4205 auto* lir = new (alloc())
4206 LArrayPush(object, useBox(ins->value()), temp(), spectreTemp);
4207 // We will bailout before pushing if the length would overflow INT32_MAX.
4208 assignSnapshot(lir, ins->bailoutKind());
4209 define(lir, ins);
4210 assignSafepoint(lir, ins);
4213 void LIRGenerator::visitArraySlice(MArraySlice* ins) {
4214 MOZ_ASSERT(ins->type() == MIRType::Object);
4215 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4216 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4217 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4219 LArraySlice* lir = new (alloc()) LArraySlice(
4220 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4221 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4222 tempFixed(CallTempReg1));
4223 assignSnapshot(lir, ins->bailoutKind());
4224 defineReturn(lir, ins);
4225 assignSafepoint(lir, ins);
4228 void LIRGenerator::visitArgumentsSlice(MArgumentsSlice* ins) {
4229 MOZ_ASSERT(ins->type() == MIRType::Object);
4230 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4231 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4232 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4234 auto* lir = new (alloc()) LArgumentsSlice(
4235 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4236 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4237 tempFixed(CallTempReg1));
4238 defineReturn(lir, ins);
4239 assignSafepoint(lir, ins);
4242 void LIRGenerator::visitFrameArgumentsSlice(MFrameArgumentsSlice* ins) {
4243 MOZ_ASSERT(ins->type() == MIRType::Object);
4244 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4245 MOZ_ASSERT(ins->count()->type() == MIRType::Int32);
4247 auto* lir = new (alloc()) LFrameArgumentsSlice(
4248 useRegister(ins->begin()), useRegister(ins->count()), temp());
4249 define(lir, ins);
4250 assignSafepoint(lir, ins);
4253 void LIRGenerator::visitInlineArgumentsSlice(MInlineArgumentsSlice* ins) {
4254 LAllocation begin = useRegisterOrConstant(ins->begin());
4255 LAllocation count = useRegisterOrConstant(ins->count());
4256 uint32_t numActuals = ins->numActuals();
4257 uint32_t numOperands =
4258 numActuals * BOX_PIECES + LInlineArgumentsSlice::NumNonArgumentOperands;
4260 auto* lir = allocateVariadic<LInlineArgumentsSlice>(numOperands, temp());
4261 if (!lir) {
4262 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitInlineArgumentsSlice");
4263 return;
4266 lir->setOperand(LInlineArgumentsSlice::Begin, begin);
4267 lir->setOperand(LInlineArgumentsSlice::Count, count);
4268 for (uint32_t i = 0; i < numActuals; i++) {
4269 MDefinition* arg = ins->getArg(i);
4270 uint32_t index = LInlineArgumentsSlice::ArgIndex(i);
4271 lir->setBoxOperand(index,
4272 useBoxOrTypedOrConstant(arg, /*useConstant = */ true));
4274 define(lir, ins);
4275 assignSafepoint(lir, ins);
4278 void LIRGenerator::visitNormalizeSliceTerm(MNormalizeSliceTerm* ins) {
4279 MOZ_ASSERT(ins->type() == MIRType::Int32);
4280 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4281 MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
4283 auto* lir = new (alloc()) LNormalizeSliceTerm(useRegister(ins->value()),
4284 useRegister(ins->length()));
4285 define(lir, ins);
4288 void LIRGenerator::visitArrayJoin(MArrayJoin* ins) {
4289 MOZ_ASSERT(ins->type() == MIRType::String);
4290 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
4291 MOZ_ASSERT(ins->sep()->type() == MIRType::String);
4293 auto* lir = new (alloc())
4294 LArrayJoin(useRegisterAtStart(ins->array()),
4295 useRegisterAtStart(ins->sep()), tempFixed(CallTempReg0));
4296 defineReturn(lir, ins);
4297 assignSafepoint(lir, ins);
4300 void LIRGenerator::visitObjectKeys(MObjectKeys* ins) {
4301 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4302 MOZ_ASSERT(ins->type() == MIRType::Object);
4304 auto* lir = new (alloc()) LObjectKeys(useRegisterAtStart(ins->object()));
4305 defineReturn(lir, ins);
4306 assignSafepoint(lir, ins);
4309 void LIRGenerator::visitObjectKeysLength(MObjectKeysLength* ins) {
4310 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4311 MOZ_ASSERT(ins->type() == MIRType::Int32);
4313 auto* lir =
4314 new (alloc()) LObjectKeysLength(useRegisterAtStart(ins->object()));
4315 defineReturn(lir, ins);
4316 assignSafepoint(lir, ins);
4319 void LIRGenerator::visitStringSplit(MStringSplit* ins) {
4320 MOZ_ASSERT(ins->type() == MIRType::Object);
4321 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4322 MOZ_ASSERT(ins->separator()->type() == MIRType::String);
4324 LStringSplit* lir = new (alloc()) LStringSplit(
4325 useRegisterAtStart(ins->string()), useRegisterAtStart(ins->separator()));
4326 defineReturn(lir, ins);
4327 assignSafepoint(lir, ins);
4330 void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) {
4331 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4332 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4333 MOZ_ASSERT(IsNumericType(ins->type()) || ins->type() == MIRType::Boolean);
4335 if (Scalar::isBigIntType(ins->storageType()) &&
4336 ins->requiresMemoryBarrier()) {
4337 lowerAtomicLoad64(ins);
4338 return;
4341 const LUse elements = useRegister(ins->elements());
4342 const LAllocation index = useRegisterOrIndexConstant(
4343 ins->index(), ins->storageType(), ins->offsetAdjustment());
4345 // NOTE: the generated code must match the assembly code in gen_load in
4346 // GenerateAtomicOperations.py
4347 Synchronization sync = Synchronization::Load();
4348 if (ins->requiresMemoryBarrier()) {
4349 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4350 add(fence, ins);
4353 if (!Scalar::isBigIntType(ins->storageType())) {
4354 // We need a temp register for Uint32Array with known double result.
4355 LDefinition tempDef = LDefinition::BogusTemp();
4356 if (ins->storageType() == Scalar::Uint32 &&
4357 IsFloatingPointType(ins->type())) {
4358 tempDef = temp();
4361 auto* lir = new (alloc()) LLoadUnboxedScalar(elements, index, tempDef);
4362 if (ins->fallible()) {
4363 assignSnapshot(lir, ins->bailoutKind());
4365 define(lir, ins);
4366 } else {
4367 MOZ_ASSERT(ins->type() == MIRType::BigInt);
4369 auto* lir =
4370 new (alloc()) LLoadUnboxedBigInt(elements, index, temp(), tempInt64());
4371 define(lir, ins);
4372 assignSafepoint(lir, ins);
4375 if (ins->requiresMemoryBarrier()) {
4376 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4377 add(fence, ins);
4381 void LIRGenerator::visitLoadDataViewElement(MLoadDataViewElement* ins) {
4382 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4383 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4385 MOZ_ASSERT(IsNumericType(ins->type()));
4387 const LUse elements = useRegister(ins->elements());
4388 const LUse index = useRegister(ins->index());
4389 const LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4391 // We need a temp register for:
4392 // - Uint32Array with known double result,
4393 // - Float32Array,
4394 // - and BigInt64Array and BigUint64Array.
4395 LDefinition tempDef = LDefinition::BogusTemp();
4396 if ((ins->storageType() == Scalar::Uint32 &&
4397 IsFloatingPointType(ins->type())) ||
4398 ins->storageType() == Scalar::Float32) {
4399 tempDef = temp();
4401 if (Scalar::isBigIntType(ins->storageType())) {
4402 #ifdef JS_CODEGEN_X86
4403 // There are not enough registers on x86.
4404 if (littleEndian.isConstant()) {
4405 tempDef = temp();
4407 #else
4408 tempDef = temp();
4409 #endif
4412 // We also need a separate 64-bit temp register for:
4413 // - Float64Array
4414 // - and BigInt64Array and BigUint64Array.
4415 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4416 if (Scalar::byteSize(ins->storageType()) == 8) {
4417 temp64Def = tempInt64();
4420 auto* lir = new (alloc())
4421 LLoadDataViewElement(elements, index, littleEndian, tempDef, temp64Def);
4422 if (ins->fallible()) {
4423 assignSnapshot(lir, ins->bailoutKind());
4425 define(lir, ins);
4426 if (Scalar::isBigIntType(ins->storageType())) {
4427 assignSafepoint(lir, ins);
4431 void LIRGenerator::visitClampToUint8(MClampToUint8* ins) {
4432 MDefinition* in = ins->input();
4434 switch (in->type()) {
4435 case MIRType::Boolean:
4436 redefine(ins, in);
4437 break;
4439 case MIRType::Int32:
4440 defineReuseInput(new (alloc()) LClampIToUint8(useRegisterAtStart(in)),
4441 ins, 0);
4442 break;
4444 case MIRType::Double:
4445 // LClampDToUint8 clobbers its input register. Making it available as
4446 // a temp copy describes this behavior to the register allocator.
4447 define(new (alloc())
4448 LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)),
4449 ins);
4450 break;
4452 case MIRType::Value: {
4453 LClampVToUint8* lir =
4454 new (alloc()) LClampVToUint8(useBox(in), tempDouble());
4455 assignSnapshot(lir, ins->bailoutKind());
4456 define(lir, ins);
4457 assignSafepoint(lir, ins);
4458 break;
4461 default:
4462 MOZ_CRASH("unexpected type");
4466 void LIRGenerator::visitLoadTypedArrayElementHole(
4467 MLoadTypedArrayElementHole* ins) {
4468 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4469 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4471 MOZ_ASSERT(ins->type() == MIRType::Value);
4473 const LUse object = useRegister(ins->object());
4474 const LAllocation index = useRegister(ins->index());
4476 if (!Scalar::isBigIntType(ins->arrayType())) {
4477 auto* lir = new (alloc()) LLoadTypedArrayElementHole(object, index, temp());
4478 if (ins->fallible()) {
4479 assignSnapshot(lir, ins->bailoutKind());
4481 defineBox(lir, ins);
4482 } else {
4483 #ifdef JS_CODEGEN_X86
4484 LDefinition tmp = LDefinition::BogusTemp();
4485 #else
4486 LDefinition tmp = temp();
4487 #endif
4489 auto* lir = new (alloc())
4490 LLoadTypedArrayElementHoleBigInt(object, index, tmp, tempInt64());
4491 defineBox(lir, ins);
4492 assignSafepoint(lir, ins);
4496 void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) {
4497 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4498 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4500 if (ins->isFloatWrite()) {
4501 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4502 ins->value()->type() == MIRType::Float32);
4503 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4504 ins->value()->type() == MIRType::Double);
4505 } else if (ins->isBigIntWrite()) {
4506 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4507 } else {
4508 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4511 if (ins->isBigIntWrite() && ins->requiresMemoryBarrier()) {
4512 lowerAtomicStore64(ins);
4513 return;
4516 LUse elements = useRegister(ins->elements());
4517 LAllocation index =
4518 useRegisterOrIndexConstant(ins->index(), ins->writeType());
4519 LAllocation value;
4521 // For byte arrays, the value has to be in a byte register on x86.
4522 if (ins->isByteWrite()) {
4523 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4524 } else if (ins->isBigIntWrite()) {
4525 value = useRegister(ins->value());
4526 } else {
4527 value = useRegisterOrNonDoubleConstant(ins->value());
4530 // Optimization opportunity for atomics: on some platforms there
4531 // is a store instruction that incorporates the necessary
4532 // barriers, and we could use that instead of separate barrier and
4533 // store instructions. See bug #1077027.
4535 // NOTE: the generated code must match the assembly code in gen_store in
4536 // GenerateAtomicOperations.py
4537 Synchronization sync = Synchronization::Store();
4538 if (ins->requiresMemoryBarrier()) {
4539 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4540 add(fence, ins);
4542 if (!ins->isBigIntWrite()) {
4543 add(new (alloc()) LStoreUnboxedScalar(elements, index, value), ins);
4544 } else {
4545 add(new (alloc()) LStoreUnboxedBigInt(elements, index, value, tempInt64()),
4546 ins);
4548 if (ins->requiresMemoryBarrier()) {
4549 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4550 add(fence, ins);
4554 void LIRGenerator::visitStoreDataViewElement(MStoreDataViewElement* ins) {
4555 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4556 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4557 MOZ_ASSERT(ins->littleEndian()->type() == MIRType::Boolean);
4559 if (ins->isFloatWrite()) {
4560 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4561 ins->value()->type() == MIRType::Float32);
4562 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4563 ins->value()->type() == MIRType::Double);
4564 } else if (ins->isBigIntWrite()) {
4565 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4566 } else {
4567 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4570 LUse elements = useRegister(ins->elements());
4571 LUse index = useRegister(ins->index());
4572 LAllocation value;
4573 if (ins->isBigIntWrite()) {
4574 value = useRegister(ins->value());
4575 } else {
4576 value = useRegisterOrNonDoubleConstant(ins->value());
4578 LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4580 LDefinition tempDef = LDefinition::BogusTemp();
4581 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4582 if (Scalar::byteSize(ins->writeType()) < 8) {
4583 tempDef = temp();
4584 } else {
4585 temp64Def = tempInt64();
4588 add(new (alloc()) LStoreDataViewElement(elements, index, value, littleEndian,
4589 tempDef, temp64Def),
4590 ins);
4593 void LIRGenerator::visitStoreTypedArrayElementHole(
4594 MStoreTypedArrayElementHole* ins) {
4595 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4596 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4597 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr);
4599 if (ins->isFloatWrite()) {
4600 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32,
4601 ins->value()->type() == MIRType::Float32);
4602 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64,
4603 ins->value()->type() == MIRType::Double);
4604 } else if (ins->isBigIntWrite()) {
4605 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4606 } else {
4607 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4610 LUse elements = useRegister(ins->elements());
4611 LAllocation length = useAny(ins->length());
4612 LAllocation index = useRegister(ins->index());
4614 // For byte arrays, the value has to be in a byte register on x86.
4615 LAllocation value;
4616 if (ins->isByteWrite()) {
4617 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4618 } else if (ins->isBigIntWrite()) {
4619 value = useRegister(ins->value());
4620 } else {
4621 value = useRegisterOrNonDoubleConstant(ins->value());
4624 if (!ins->isBigIntWrite()) {
4625 LDefinition spectreTemp =
4626 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4627 auto* lir = new (alloc()) LStoreTypedArrayElementHole(
4628 elements, length, index, value, spectreTemp);
4629 add(lir, ins);
4630 } else {
4631 auto* lir = new (alloc()) LStoreTypedArrayElementHoleBigInt(
4632 elements, length, index, value, tempInt64());
4633 add(lir, ins);
4637 void LIRGenerator::visitLoadScriptedProxyHandler(
4638 MLoadScriptedProxyHandler* ins) {
4639 LLoadScriptedProxyHandler* lir = new (alloc())
4640 LLoadScriptedProxyHandler(useRegisterAtStart(ins->object()));
4641 defineBox(lir, ins);
4644 void LIRGenerator::visitIdToStringOrSymbol(MIdToStringOrSymbol* ins) {
4645 LIdToStringOrSymbol* lir =
4646 new (alloc()) LIdToStringOrSymbol(useBoxAtStart(ins->idVal()), temp());
4647 assignSnapshot(lir, ins->bailoutKind());
4648 defineBox(lir, ins);
4649 assignSafepoint(lir, ins);
4652 void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) {
4653 MDefinition* obj = ins->object();
4654 MOZ_ASSERT(obj->type() == MIRType::Object);
4656 MIRType type = ins->type();
4658 if (type == MIRType::Value) {
4659 if (ins->usedAsPropertyKey()) {
4660 LLoadFixedSlotAndAtomize* lir =
4661 new (alloc()) LLoadFixedSlotAndAtomize(useRegister(obj), temp());
4662 defineBox(lir, ins);
4663 assignSafepoint(lir, ins);
4664 } else {
4665 LLoadFixedSlotV* lir =
4666 new (alloc()) LLoadFixedSlotV(useRegisterAtStart(obj));
4667 defineBox(lir, ins);
4669 } else {
4670 LLoadFixedSlotT* lir =
4671 new (alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type));
4672 define(lir, ins);
4676 void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) {
4677 MDefinition* obj = ins->object();
4678 MOZ_ASSERT(obj->type() == MIRType::Object);
4680 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4681 LLoadFixedSlotUnboxAndAtomize* lir =
4682 new (alloc()) LLoadFixedSlotUnboxAndAtomize(useRegister(obj));
4683 if (ins->fallible()) {
4684 assignSnapshot(lir, ins->bailoutKind());
4686 define(lir, ins);
4687 assignSafepoint(lir, ins);
4688 } else {
4689 LLoadFixedSlotAndUnbox* lir =
4690 new (alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj));
4691 if (ins->fallible()) {
4692 assignSnapshot(lir, ins->bailoutKind());
4694 define(lir, ins);
4698 void LIRGenerator::visitLoadDynamicSlotAndUnbox(MLoadDynamicSlotAndUnbox* ins) {
4699 MDefinition* slots = ins->slots();
4700 MOZ_ASSERT(slots->type() == MIRType::Slots);
4702 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4703 auto* lir =
4704 new (alloc()) LLoadDynamicSlotUnboxAndAtomize(useRegister(slots));
4705 if (ins->fallible()) {
4706 assignSnapshot(lir, ins->bailoutKind());
4708 define(lir, ins);
4709 assignSafepoint(lir, ins);
4710 } else {
4711 auto* lir =
4712 new (alloc()) LLoadDynamicSlotAndUnbox(useRegisterAtStart(slots));
4713 if (ins->fallible()) {
4714 assignSnapshot(lir, ins->bailoutKind());
4716 define(lir, ins);
4720 void LIRGenerator::visitLoadElementAndUnbox(MLoadElementAndUnbox* ins) {
4721 MDefinition* elements = ins->elements();
4722 MDefinition* index = ins->index();
4723 MOZ_ASSERT(elements->type() == MIRType::Elements);
4724 MOZ_ASSERT(index->type() == MIRType::Int32);
4726 auto* lir = new (alloc())
4727 LLoadElementAndUnbox(useRegister(elements), useRegisterOrConstant(index));
4728 if (ins->fallible()) {
4729 assignSnapshot(lir, ins->bailoutKind());
4731 define(lir, ins);
4734 void LIRGenerator::visitAddAndStoreSlot(MAddAndStoreSlot* ins) {
4735 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4737 LDefinition maybeTemp = LDefinition::BogusTemp();
4738 if (ins->kind() != MAddAndStoreSlot::Kind::FixedSlot) {
4739 maybeTemp = temp();
4742 auto* lir = new (alloc()) LAddAndStoreSlot(useRegister(ins->object()),
4743 useBox(ins->value()), maybeTemp);
4744 add(lir, ins);
4747 void LIRGenerator::visitAllocateAndStoreSlot(MAllocateAndStoreSlot* ins) {
4748 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4750 auto* lir = new (alloc()) LAllocateAndStoreSlot(
4751 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()),
4752 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4753 assignSnapshot(lir, ins->bailoutKind());
4754 add(lir, ins);
4757 void LIRGenerator::visitAddSlotAndCallAddPropHook(
4758 MAddSlotAndCallAddPropHook* ins) {
4759 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4760 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4762 auto* lir = new (alloc()) LAddSlotAndCallAddPropHook(
4763 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
4764 add(lir, ins);
4765 assignSafepoint(lir, ins);
4768 void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) {
4769 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4771 if (ins->value()->type() == MIRType::Value) {
4772 LStoreFixedSlotV* lir = new (alloc())
4773 LStoreFixedSlotV(useRegister(ins->object()), useBox(ins->value()));
4774 add(lir, ins);
4775 } else {
4776 LStoreFixedSlotT* lir = new (alloc()) LStoreFixedSlotT(
4777 useRegister(ins->object()), useRegisterOrConstant(ins->value()));
4778 add(lir, ins);
4782 void LIRGenerator::visitGetNameCache(MGetNameCache* ins) {
4783 MOZ_ASSERT(ins->envObj()->type() == MIRType::Object);
4785 // Emit an overrecursed check: this is necessary because the cache can
4786 // attach a scripted getter stub that calls this script recursively.
4787 gen->setNeedsOverrecursedCheck();
4789 LGetNameCache* lir =
4790 new (alloc()) LGetNameCache(useRegister(ins->envObj()), temp());
4791 defineBox(lir, ins);
4792 assignSafepoint(lir, ins);
4795 void LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) {
4796 LCallGetIntrinsicValue* lir = new (alloc()) LCallGetIntrinsicValue();
4797 defineReturn(lir, ins);
4798 assignSafepoint(lir, ins);
4801 void LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache* ins) {
4802 MDefinition* obj = ins->object();
4803 MDefinition* receiver = ins->receiver();
4804 MDefinition* id = ins->idval();
4806 gen->setNeedsOverrecursedCheck();
4808 bool useConstId =
4809 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4811 auto* lir = new (alloc())
4812 LGetPropSuperCache(useRegister(obj), useBoxOrTyped(receiver),
4813 useBoxOrTypedOrConstant(id, useConstId));
4814 defineBox(lir, ins);
4815 assignSafepoint(lir, ins);
4818 void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) {
4819 MDefinition* value = ins->value();
4820 MOZ_ASSERT(value->type() == MIRType::Object ||
4821 value->type() == MIRType::Value);
4823 MDefinition* id = ins->idval();
4824 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4825 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4827 // Emit an overrecursed check: this is necessary because the cache can
4828 // attach a scripted getter stub that calls this script recursively.
4829 gen->setNeedsOverrecursedCheck();
4831 // If this is a GetProp, the id is a constant string. Allow passing it as a
4832 // constant to reduce register allocation pressure.
4833 bool useConstId =
4834 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4836 auto* lir = new (alloc()) LGetPropertyCache(
4837 useBoxOrTyped(value), useBoxOrTypedOrConstant(id, useConstId));
4838 defineBox(lir, ins);
4839 assignSafepoint(lir, ins);
4842 void LIRGenerator::visitBindNameCache(MBindNameCache* ins) {
4843 MOZ_ASSERT(ins->envChain()->type() == MIRType::Object);
4844 MOZ_ASSERT(ins->type() == MIRType::Object);
4846 LBindNameCache* lir =
4847 new (alloc()) LBindNameCache(useRegister(ins->envChain()), temp());
4848 define(lir, ins);
4849 assignSafepoint(lir, ins);
4852 void LIRGenerator::visitCallBindVar(MCallBindVar* ins) {
4853 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
4854 MOZ_ASSERT(ins->type() == MIRType::Object);
4856 LCallBindVar* lir =
4857 new (alloc()) LCallBindVar(useRegister(ins->environmentChain()));
4858 define(lir, ins);
4861 void LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins) {
4862 LGuardObjectIdentity* guard = new (alloc()) LGuardObjectIdentity(
4863 useRegister(ins->object()), useRegister(ins->expected()));
4864 assignSnapshot(guard, ins->bailoutKind());
4865 add(guard, ins);
4866 redefine(ins, ins->object());
4869 void LIRGenerator::visitGuardSpecificFunction(MGuardSpecificFunction* ins) {
4870 auto* guard = new (alloc()) LGuardSpecificFunction(
4871 useRegister(ins->function()), useRegister(ins->expected()));
4872 assignSnapshot(guard, ins->bailoutKind());
4873 add(guard, ins);
4874 redefine(ins, ins->function());
4877 void LIRGenerator::visitGuardSpecificAtom(MGuardSpecificAtom* ins) {
4878 auto* guard =
4879 new (alloc()) LGuardSpecificAtom(useRegister(ins->str()), temp());
4880 assignSnapshot(guard, ins->bailoutKind());
4881 add(guard, ins);
4882 redefine(ins, ins->str());
4883 assignSafepoint(guard, ins);
4886 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol* ins) {
4887 auto* guard = new (alloc()) LGuardSpecificSymbol(useRegister(ins->symbol()));
4888 assignSnapshot(guard, ins->bailoutKind());
4889 add(guard, ins);
4890 redefine(ins, ins->symbol());
4893 void LIRGenerator::visitGuardSpecificInt32(MGuardSpecificInt32* ins) {
4894 auto* guard = new (alloc()) LGuardSpecificInt32(useRegister(ins->num()));
4895 assignSnapshot(guard, ins->bailoutKind());
4896 add(guard, ins);
4897 redefine(ins, ins->num());
4900 void LIRGenerator::visitGuardStringToIndex(MGuardStringToIndex* ins) {
4901 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4902 auto* guard = new (alloc()) LGuardStringToIndex(useRegister(ins->string()));
4903 assignSnapshot(guard, ins->bailoutKind());
4904 define(guard, ins);
4905 assignSafepoint(guard, ins);
4908 void LIRGenerator::visitGuardStringToInt32(MGuardStringToInt32* ins) {
4909 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4910 auto* guard =
4911 new (alloc()) LGuardStringToInt32(useRegister(ins->string()), temp());
4912 assignSnapshot(guard, ins->bailoutKind());
4913 define(guard, ins);
4914 assignSafepoint(guard, ins);
4917 void LIRGenerator::visitGuardStringToDouble(MGuardStringToDouble* ins) {
4918 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4919 auto* guard = new (alloc())
4920 LGuardStringToDouble(useRegister(ins->string()), temp(), temp());
4921 assignSnapshot(guard, ins->bailoutKind());
4922 define(guard, ins);
4923 assignSafepoint(guard, ins);
4926 void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements* ins) {
4927 auto* guard =
4928 new (alloc()) LGuardNoDenseElements(useRegister(ins->object()), temp());
4929 assignSnapshot(guard, ins->bailoutKind());
4930 add(guard, ins);
4931 redefine(ins, ins->object());
4934 void LIRGenerator::visitGuardShape(MGuardShape* ins) {
4935 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4937 if (JitOptions.spectreObjectMitigations) {
4938 auto* lir =
4939 new (alloc()) LGuardShape(useRegisterAtStart(ins->object()), temp());
4940 assignSnapshot(lir, ins->bailoutKind());
4941 defineReuseInput(lir, ins, 0);
4942 } else {
4943 auto* lir = new (alloc())
4944 LGuardShape(useRegister(ins->object()), LDefinition::BogusTemp());
4945 assignSnapshot(lir, ins->bailoutKind());
4946 add(lir, ins);
4947 redefine(ins, ins->object());
4951 void LIRGenerator::visitGuardMultipleShapes(MGuardMultipleShapes* ins) {
4952 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4954 if (JitOptions.spectreObjectMitigations) {
4955 auto* lir = new (alloc()) LGuardMultipleShapes(
4956 useRegisterAtStart(ins->object()), useRegister(ins->shapeList()),
4957 temp(), temp(), temp(), temp());
4958 assignSnapshot(lir, ins->bailoutKind());
4959 defineReuseInput(lir, ins, 0);
4960 } else {
4961 auto* lir = new (alloc()) LGuardMultipleShapes(
4962 useRegister(ins->object()), useRegister(ins->shapeList()), temp(),
4963 temp(), temp(), LDefinition::BogusTemp());
4964 assignSnapshot(lir, ins->bailoutKind());
4965 add(lir, ins);
4966 redefine(ins, ins->object());
4970 void LIRGenerator::visitGuardProto(MGuardProto* ins) {
4971 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4972 MOZ_ASSERT(ins->expected()->type() == MIRType::Object);
4974 auto* lir = new (alloc()) LGuardProto(useRegister(ins->object()),
4975 useRegister(ins->expected()), temp());
4976 assignSnapshot(lir, ins->bailoutKind());
4977 add(lir, ins);
4978 redefine(ins, ins->object());
4981 void LIRGenerator::visitGuardNullProto(MGuardNullProto* ins) {
4982 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4984 auto* lir = new (alloc()) LGuardNullProto(useRegister(ins->object()), temp());
4985 assignSnapshot(lir, ins->bailoutKind());
4986 add(lir, ins);
4987 redefine(ins, ins->object());
4990 void LIRGenerator::visitGuardIsNativeObject(MGuardIsNativeObject* ins) {
4991 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4993 auto* lir =
4994 new (alloc()) LGuardIsNativeObject(useRegister(ins->object()), temp());
4995 assignSnapshot(lir, ins->bailoutKind());
4996 add(lir, ins);
4997 redefine(ins, ins->object());
5000 void LIRGenerator::visitGuardGlobalGeneration(MGuardGlobalGeneration* ins) {
5001 auto* lir = new (alloc()) LGuardGlobalGeneration(temp());
5002 assignSnapshot(lir, ins->bailoutKind());
5003 add(lir, ins);
5006 void LIRGenerator::visitGuardFuse(MGuardFuse* ins) {
5007 auto* lir = new (alloc()) LGuardFuse(temp());
5008 assignSnapshot(lir, ins->bailoutKind());
5009 add(lir, ins);
5012 void LIRGenerator::visitGuardIsProxy(MGuardIsProxy* ins) {
5013 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5015 auto* lir = new (alloc()) LGuardIsProxy(useRegister(ins->object()), temp());
5016 assignSnapshot(lir, ins->bailoutKind());
5017 add(lir, ins);
5018 redefine(ins, ins->object());
5021 void LIRGenerator::visitGuardIsNotProxy(MGuardIsNotProxy* ins) {
5022 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5024 auto* lir =
5025 new (alloc()) LGuardIsNotProxy(useRegister(ins->object()), temp());
5026 assignSnapshot(lir, ins->bailoutKind());
5027 add(lir, ins);
5028 redefine(ins, ins->object());
5031 void LIRGenerator::visitGuardIsNotDOMProxy(MGuardIsNotDOMProxy* ins) {
5032 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5034 auto* lir =
5035 new (alloc()) LGuardIsNotDOMProxy(useRegister(ins->proxy()), temp());
5036 assignSnapshot(lir, ins->bailoutKind());
5037 add(lir, ins);
5038 redefine(ins, ins->proxy());
5041 void LIRGenerator::visitProxyGet(MProxyGet* ins) {
5042 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5043 auto* lir = new (alloc())
5044 LProxyGet(useRegisterAtStart(ins->proxy()), tempFixed(CallTempReg0));
5045 defineReturn(lir, ins);
5046 assignSafepoint(lir, ins);
5049 void LIRGenerator::visitProxyGetByValue(MProxyGetByValue* ins) {
5050 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5051 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5052 auto* lir = new (alloc()) LProxyGetByValue(useRegisterAtStart(ins->proxy()),
5053 useBoxAtStart(ins->idVal()));
5054 defineReturn(lir, ins);
5055 assignSafepoint(lir, ins);
5058 void LIRGenerator::visitProxyHasProp(MProxyHasProp* ins) {
5059 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5060 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5061 auto* lir = new (alloc()) LProxyHasProp(useRegisterAtStart(ins->proxy()),
5062 useBoxAtStart(ins->idVal()));
5063 defineReturn(lir, ins);
5064 assignSafepoint(lir, ins);
5067 void LIRGenerator::visitProxySet(MProxySet* ins) {
5068 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5069 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5070 auto* lir = new (alloc())
5071 LProxySet(useRegisterAtStart(ins->proxy()), useBoxAtStart(ins->rhs()),
5072 tempFixed(CallTempReg0));
5073 add(lir, ins);
5074 assignSafepoint(lir, ins);
5077 void LIRGenerator::visitProxySetByValue(MProxySetByValue* ins) {
5078 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5079 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5080 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5081 auto* lir = new (alloc())
5082 LProxySetByValue(useRegisterAtStart(ins->proxy()),
5083 useBoxAtStart(ins->idVal()), useBoxAtStart(ins->rhs()));
5084 add(lir, ins);
5085 assignSafepoint(lir, ins);
5088 void LIRGenerator::visitCallSetArrayLength(MCallSetArrayLength* ins) {
5089 MOZ_ASSERT(ins->obj()->type() == MIRType::Object);
5090 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5091 auto* lir = new (alloc()) LCallSetArrayLength(useRegisterAtStart(ins->obj()),
5092 useBoxAtStart(ins->rhs()));
5093 add(lir, ins);
5094 assignSafepoint(lir, ins);
5097 void LIRGenerator::visitMegamorphicLoadSlot(MMegamorphicLoadSlot* ins) {
5098 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5099 auto* lir = new (alloc())
5100 LMegamorphicLoadSlot(useRegisterAtStart(ins->object()),
5101 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5102 tempFixed(CallTempReg2), tempFixed(CallTempReg3));
5103 assignSnapshot(lir, ins->bailoutKind());
5104 defineReturn(lir, ins);
5107 void LIRGenerator::visitMegamorphicLoadSlotByValue(
5108 MMegamorphicLoadSlotByValue* ins) {
5109 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5110 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5111 auto* lir = new (alloc()) LMegamorphicLoadSlotByValue(
5112 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()),
5113 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5114 tempFixed(CallTempReg2));
5115 assignSnapshot(lir, ins->bailoutKind());
5116 defineReturn(lir, ins);
5119 void LIRGenerator::visitMegamorphicStoreSlot(MMegamorphicStoreSlot* ins) {
5120 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5121 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5123 #ifdef JS_CODEGEN_X86
5124 auto* lir = new (alloc()) LMegamorphicStoreSlot(
5125 useFixedAtStart(ins->object(), CallTempReg0),
5126 useBoxFixedAtStart(ins->rhs(), CallTempReg1, CallTempReg2),
5127 tempFixed(CallTempReg5));
5128 #else
5129 auto* lir = new (alloc())
5130 LMegamorphicStoreSlot(useRegisterAtStart(ins->object()),
5131 useBoxAtStart(ins->rhs()), tempFixed(CallTempReg0),
5132 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5133 #endif
5135 add(lir, ins);
5136 assignSafepoint(lir, ins);
5139 void LIRGenerator::visitMegamorphicHasProp(MMegamorphicHasProp* ins) {
5140 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5141 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5142 auto* lir = new (alloc())
5143 LMegamorphicHasProp(useRegisterAtStart(ins->object()),
5144 useBoxAtStart(ins->idVal()), tempFixed(CallTempReg0),
5145 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5146 assignSnapshot(lir, ins->bailoutKind());
5147 defineReturn(lir, ins);
5150 void LIRGenerator::visitGuardIsNotArrayBufferMaybeShared(
5151 MGuardIsNotArrayBufferMaybeShared* ins) {
5152 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5154 auto* lir = new (alloc())
5155 LGuardIsNotArrayBufferMaybeShared(useRegister(ins->object()), temp());
5156 assignSnapshot(lir, ins->bailoutKind());
5157 add(lir, ins);
5158 redefine(ins, ins->object());
5161 void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray* ins) {
5162 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5164 auto* lir =
5165 new (alloc()) LGuardIsTypedArray(useRegister(ins->object()), temp());
5166 assignSnapshot(lir, ins->bailoutKind());
5167 add(lir, ins);
5168 redefine(ins, ins->object());
5171 void LIRGenerator::visitGuardIsFixedLengthTypedArray(
5172 MGuardIsFixedLengthTypedArray* ins) {
5173 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5175 auto* lir = new (alloc())
5176 LGuardIsFixedLengthTypedArray(useRegister(ins->object()), temp());
5177 assignSnapshot(lir, ins->bailoutKind());
5178 add(lir, ins);
5179 redefine(ins, ins->object());
5182 void LIRGenerator::visitGuardHasProxyHandler(MGuardHasProxyHandler* ins) {
5183 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5185 auto* lir = new (alloc()) LGuardHasProxyHandler(useRegister(ins->object()));
5186 assignSnapshot(lir, ins->bailoutKind());
5187 add(lir, ins);
5188 redefine(ins, ins->object());
5191 void LIRGenerator::visitNurseryObject(MNurseryObject* ins) {
5192 MOZ_ASSERT(ins->type() == MIRType::Object);
5194 auto* lir = new (alloc()) LNurseryObject();
5195 define(lir, ins);
5198 void LIRGenerator::visitGuardValue(MGuardValue* ins) {
5199 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5200 auto* lir = new (alloc()) LGuardValue(useBox(ins->value()));
5201 assignSnapshot(lir, ins->bailoutKind());
5202 add(lir, ins);
5203 redefine(ins, ins->value());
5206 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined* ins) {
5207 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5208 auto* lir = new (alloc()) LGuardNullOrUndefined(useBox(ins->value()));
5209 assignSnapshot(lir, ins->bailoutKind());
5210 add(lir, ins);
5211 redefine(ins, ins->value());
5214 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject* ins) {
5215 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5216 auto* lir = new (alloc()) LGuardIsNotObject(useBox(ins->value()));
5217 assignSnapshot(lir, ins->bailoutKind());
5218 add(lir, ins);
5219 redefine(ins, ins->value());
5222 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags* ins) {
5223 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5225 auto* lir = new (alloc()) LGuardFunctionFlags(useRegister(ins->function()));
5226 assignSnapshot(lir, ins->bailoutKind());
5227 add(lir, ins);
5228 redefine(ins, ins->function());
5231 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor(
5232 MGuardFunctionIsNonBuiltinCtor* ins) {
5233 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5235 auto* lir = new (alloc())
5236 LGuardFunctionIsNonBuiltinCtor(useRegister(ins->function()), temp());
5237 assignSnapshot(lir, ins->bailoutKind());
5238 add(lir, ins);
5239 redefine(ins, ins->function());
5242 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind* ins) {
5243 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5245 auto* lir =
5246 new (alloc()) LGuardFunctionKind(useRegister(ins->function()), temp());
5247 assignSnapshot(lir, ins->bailoutKind());
5248 add(lir, ins);
5249 redefine(ins, ins->function());
5252 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript* ins) {
5253 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5255 auto* lir = new (alloc()) LGuardFunctionScript(useRegister(ins->function()));
5256 assignSnapshot(lir, ins->bailoutKind());
5257 add(lir, ins);
5258 redefine(ins, ins->function());
5261 void LIRGenerator::visitAssertRange(MAssertRange* ins) {
5262 MDefinition* input = ins->input();
5263 LInstruction* lir = nullptr;
5265 switch (input->type()) {
5266 case MIRType::Boolean:
5267 case MIRType::Int32:
5268 case MIRType::IntPtr:
5269 lir = new (alloc()) LAssertRangeI(useRegisterAtStart(input));
5270 break;
5272 case MIRType::Double:
5273 lir = new (alloc()) LAssertRangeD(useRegister(input), tempDouble());
5274 break;
5276 case MIRType::Float32:
5277 lir = new (alloc())
5278 LAssertRangeF(useRegister(input), tempDouble(), tempDouble());
5279 break;
5281 case MIRType::Value:
5282 lir = new (alloc()) LAssertRangeV(useBox(input), tempToUnbox(),
5283 tempDouble(), tempDouble());
5284 break;
5286 default:
5287 MOZ_CRASH("Unexpected Range for MIRType");
5288 break;
5291 lir->setMir(ins);
5292 add(lir);
5295 void LIRGenerator::visitAssertClass(MAssertClass* ins) {
5296 auto* lir =
5297 new (alloc()) LAssertClass(useRegisterAtStart(ins->input()), temp());
5298 add(lir, ins);
5301 void LIRGenerator::visitAssertShape(MAssertShape* ins) {
5302 auto* lir = new (alloc()) LAssertShape(useRegisterAtStart(ins->input()));
5303 add(lir, ins);
5306 void LIRGenerator::visitDeleteProperty(MDeleteProperty* ins) {
5307 LCallDeleteProperty* lir =
5308 new (alloc()) LCallDeleteProperty(useBoxAtStart(ins->value()));
5309 defineReturn(lir, ins);
5310 assignSafepoint(lir, ins);
5313 void LIRGenerator::visitDeleteElement(MDeleteElement* ins) {
5314 LCallDeleteElement* lir = new (alloc()) LCallDeleteElement(
5315 useBoxAtStart(ins->value()), useBoxAtStart(ins->index()));
5316 defineReturn(lir, ins);
5317 assignSafepoint(lir, ins);
5320 void LIRGenerator::visitObjectToIterator(MObjectToIterator* ins) {
5321 auto* lir = new (alloc())
5322 LObjectToIterator(useRegister(ins->object()), temp(), temp(), temp());
5323 define(lir, ins);
5324 assignSafepoint(lir, ins);
5327 void LIRGenerator::visitValueToIterator(MValueToIterator* ins) {
5328 auto* lir = new (alloc()) LValueToIterator(useBoxAtStart(ins->value()));
5329 defineReturn(lir, ins);
5330 assignSafepoint(lir, ins);
5333 void LIRGenerator::visitLoadSlotByIteratorIndex(MLoadSlotByIteratorIndex* ins) {
5334 auto* lir = new (alloc()) LLoadSlotByIteratorIndex(
5335 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->iterator()),
5336 temp(), temp());
5337 defineBox(lir, ins);
5340 void LIRGenerator::visitStoreSlotByIteratorIndex(
5341 MStoreSlotByIteratorIndex* ins) {
5342 auto* lir = new (alloc()) LStoreSlotByIteratorIndex(
5343 useRegister(ins->object()), useRegister(ins->iterator()),
5344 useBox(ins->value()), temp(), temp());
5345 add(lir, ins);
5348 void LIRGenerator::visitIteratorHasIndices(MIteratorHasIndices* ins) {
5349 MOZ_ASSERT(ins->hasOneUse());
5350 emitAtUses(ins);
5353 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) {
5354 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5356 MDefinition* id = ins->idval();
5357 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5358 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5360 // If this is a SetProp, the id is a constant string. Allow passing it as a
5361 // constant to reduce register allocation pressure.
5362 bool useConstId =
5363 id->type() == MIRType::String || id->type() == MIRType::Symbol;
5364 bool useConstValue = IsNonNurseryConstant(ins->value());
5366 // Emit an overrecursed check: this is necessary because the cache can
5367 // attach a scripted setter stub that calls this script recursively.
5368 gen->setNeedsOverrecursedCheck();
5370 // We need a double temp register for TypedArray stubs.
5371 LDefinition tempD = tempFixed(FloatReg0);
5373 LInstruction* lir = new (alloc()) LSetPropertyCache(
5374 useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId),
5375 useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD);
5376 add(lir, ins);
5377 assignSafepoint(lir, ins);
5380 void LIRGenerator::visitMegamorphicSetElement(MMegamorphicSetElement* ins) {
5381 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5382 MOZ_ASSERT(ins->index()->type() == MIRType::Value);
5383 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5385 // See comment in LIROps.yaml (x86 is short on registers)
5386 #ifdef JS_CODEGEN_X86
5387 auto* lir = new (alloc()) LMegamorphicSetElement(
5388 useFixedAtStart(ins->object(), CallTempReg0),
5389 useBoxFixedAtStart(ins->index(), CallTempReg1, CallTempReg2),
5390 useBoxFixedAtStart(ins->value(), CallTempReg3, CallTempReg4),
5391 tempFixed(CallTempReg5));
5392 #else
5393 auto* lir = new (alloc()) LMegamorphicSetElement(
5394 useRegisterAtStart(ins->object()), useBoxAtStart(ins->index()),
5395 useBoxAtStart(ins->value()), tempFixed(CallTempReg0),
5396 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5397 #endif
5398 add(lir, ins);
5399 assignSafepoint(lir, ins);
5402 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache* ins) {
5403 MDefinition* value = ins->value();
5404 MOZ_ASSERT(value->type() == MIRType::Object ||
5405 value->type() == MIRType::Value);
5407 LGetIteratorCache* lir =
5408 new (alloc()) LGetIteratorCache(useBoxOrTyped(value), temp(), temp());
5409 define(lir, ins);
5410 assignSafepoint(lir, ins);
5413 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache* ins) {
5414 MDefinition* value = ins->value();
5415 MOZ_ASSERT(value->type() == MIRType::Value);
5417 auto* lir = new (alloc()) LOptimizeSpreadCallCache(useBox(value), temp());
5418 defineBox(lir, ins);
5419 assignSafepoint(lir, ins);
5422 void LIRGenerator::visitIteratorMore(MIteratorMore* ins) {
5423 LIteratorMore* lir =
5424 new (alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
5425 defineBox(lir, ins);
5428 void LIRGenerator::visitIsNoIter(MIsNoIter* ins) {
5429 MOZ_ASSERT(ins->hasOneUse());
5430 emitAtUses(ins);
5433 void LIRGenerator::visitIteratorEnd(MIteratorEnd* ins) {
5434 LIteratorEnd* lir = new (alloc())
5435 LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
5436 add(lir, ins);
5439 void LIRGenerator::visitCloseIterCache(MCloseIterCache* ins) {
5440 LCloseIterCache* lir =
5441 new (alloc()) LCloseIterCache(useRegister(ins->iter()), temp());
5442 add(lir, ins);
5443 assignSafepoint(lir, ins);
5446 void LIRGenerator::visitOptimizeGetIteratorCache(
5447 MOptimizeGetIteratorCache* ins) {
5448 MDefinition* value = ins->value();
5449 MOZ_ASSERT(value->type() == MIRType::Value);
5451 auto* lir = new (alloc()) LOptimizeGetIteratorCache(useBox(value), temp());
5452 define(lir, ins);
5453 assignSafepoint(lir, ins);
5456 void LIRGenerator::visitStringLength(MStringLength* ins) {
5457 MOZ_ASSERT(ins->string()->type() == MIRType::String);
5458 define(new (alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
5461 void LIRGenerator::visitArgumentsLength(MArgumentsLength* ins) {
5462 define(new (alloc()) LArgumentsLength(), ins);
5465 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument* ins) {
5466 LGetFrameArgument* lir =
5467 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
5468 defineBox(lir, ins);
5471 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole* ins) {
5472 LDefinition spectreTemp =
5473 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5475 auto* lir = new (alloc()) LGetFrameArgumentHole(
5476 useRegister(ins->index()), useRegister(ins->length()), spectreTemp);
5477 assignSnapshot(lir, ins->bailoutKind());
5478 defineBox(lir, ins);
5481 void LIRGenerator::visitNewTarget(MNewTarget* ins) {
5482 LNewTarget* lir = new (alloc()) LNewTarget();
5483 defineBox(lir, ins);
5486 void LIRGenerator::visitRest(MRest* ins) {
5487 MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32);
5489 LRest* lir = new (alloc())
5490 LRest(useRegisterAtStart(ins->numActuals()), tempFixed(CallTempReg0),
5491 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5492 defineReturn(lir, ins);
5493 assignSafepoint(lir, ins);
5496 void LIRGenerator::visitThrow(MThrow* ins) {
5497 MDefinition* value = ins->value();
5498 MOZ_ASSERT(value->type() == MIRType::Value);
5500 LThrow* lir = new (alloc()) LThrow(useBoxAtStart(value));
5501 add(lir, ins);
5502 assignSafepoint(lir, ins);
5505 void LIRGenerator::visitThrowWithStack(MThrowWithStack* ins) {
5506 MDefinition* value = ins->value();
5507 MOZ_ASSERT(value->type() == MIRType::Value);
5509 MDefinition* stack = ins->stack();
5510 MOZ_ASSERT(stack->type() == MIRType::Value);
5512 auto* lir =
5513 new (alloc()) LThrowWithStack(useBoxAtStart(value), useBoxAtStart(stack));
5514 add(lir, ins);
5515 assignSafepoint(lir, ins);
5518 void LIRGenerator::visitInCache(MInCache* ins) {
5519 MDefinition* lhs = ins->lhs();
5520 MDefinition* rhs = ins->rhs();
5522 MOZ_ASSERT(lhs->type() == MIRType::String || lhs->type() == MIRType::Symbol ||
5523 lhs->type() == MIRType::Int32 || lhs->type() == MIRType::Value);
5524 MOZ_ASSERT(rhs->type() == MIRType::Object);
5526 LInCache* lir =
5527 new (alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp());
5528 define(lir, ins);
5529 assignSafepoint(lir, ins);
5532 void LIRGenerator::visitHasOwnCache(MHasOwnCache* ins) {
5533 MDefinition* value = ins->value();
5534 MOZ_ASSERT(value->type() == MIRType::Object ||
5535 value->type() == MIRType::Value);
5537 MDefinition* id = ins->idval();
5538 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5539 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5541 // Emit an overrecursed check: this is necessary because the cache can
5542 // attach a scripted getter stub that calls this script recursively.
5543 gen->setNeedsOverrecursedCheck();
5545 LHasOwnCache* lir =
5546 new (alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id));
5547 define(lir, ins);
5548 assignSafepoint(lir, ins);
5551 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache* ins) {
5552 MDefinition* value = ins->value();
5553 MOZ_ASSERT(value->type() == MIRType::Object ||
5554 value->type() == MIRType::Value);
5556 MDefinition* id = ins->idval();
5557 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5558 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5560 LCheckPrivateFieldCache* lir = new (alloc())
5561 LCheckPrivateFieldCache(useBoxOrTyped(value), useBoxOrTyped(id));
5562 define(lir, ins);
5563 assignSafepoint(lir, ins);
5566 void LIRGenerator::visitNewPrivateName(MNewPrivateName* ins) {
5567 auto* lir = new (alloc()) LNewPrivateName();
5568 defineReturn(lir, ins);
5569 assignSafepoint(lir, ins);
5572 void LIRGenerator::visitInstanceOf(MInstanceOf* ins) {
5573 MDefinition* lhs = ins->lhs();
5574 MDefinition* rhs = ins->rhs();
5576 MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object);
5577 MOZ_ASSERT(rhs->type() == MIRType::Object);
5579 if (lhs->type() == MIRType::Object) {
5580 auto* lir = new (alloc()) LInstanceOfO(useRegister(lhs), useRegister(rhs));
5581 define(lir, ins);
5582 assignSafepoint(lir, ins);
5583 } else {
5584 auto* lir = new (alloc()) LInstanceOfV(useBox(lhs), useRegister(rhs));
5585 define(lir, ins);
5586 assignSafepoint(lir, ins);
5590 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins) {
5591 MDefinition* lhs = ins->lhs();
5592 MDefinition* rhs = ins->rhs();
5594 MOZ_ASSERT(lhs->type() == MIRType::Value);
5595 MOZ_ASSERT(rhs->type() == MIRType::Object);
5597 LInstanceOfCache* lir =
5598 new (alloc()) LInstanceOfCache(useBox(lhs), useRegister(rhs));
5599 define(lir, ins);
5600 assignSafepoint(lir, ins);
5603 void LIRGenerator::visitIsArray(MIsArray* ins) {
5604 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5606 if (ins->value()->type() == MIRType::Object) {
5607 LIsArrayO* lir = new (alloc()) LIsArrayO(useRegister(ins->value()));
5608 define(lir, ins);
5609 assignSafepoint(lir, ins);
5610 } else {
5611 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5612 LIsArrayV* lir = new (alloc()) LIsArrayV(useBox(ins->value()), temp());
5613 define(lir, ins);
5614 assignSafepoint(lir, ins);
5618 void LIRGenerator::visitIsTypedArray(MIsTypedArray* ins) {
5619 MOZ_ASSERT(ins->value()->type() == MIRType::Object);
5620 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5622 auto* lir = new (alloc()) LIsTypedArray(useRegister(ins->value()));
5623 define(lir, ins);
5625 if (ins->isPossiblyWrapped()) {
5626 assignSafepoint(lir, ins);
5630 void LIRGenerator::visitIsCallable(MIsCallable* ins) {
5631 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5633 if (ins->object()->type() == MIRType::Object) {
5634 define(new (alloc()) LIsCallableO(useRegister(ins->object())), ins);
5635 } else {
5636 MOZ_ASSERT(ins->object()->type() == MIRType::Value);
5637 define(new (alloc()) LIsCallableV(useBox(ins->object()), temp()), ins);
5641 void LIRGenerator::visitIsConstructor(MIsConstructor* ins) {
5642 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5643 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5644 define(new (alloc()) LIsConstructor(useRegister(ins->object())), ins);
5647 void LIRGenerator::visitIsCrossRealmArrayConstructor(
5648 MIsCrossRealmArrayConstructor* ins) {
5649 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5650 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5651 define(new (alloc())
5652 LIsCrossRealmArrayConstructor(useRegister(ins->object())),
5653 ins);
5656 static bool CanEmitAtUseForSingleTest(MInstruction* ins) {
5657 if (!ins->canEmitAtUses()) {
5658 return false;
5661 MUseIterator iter(ins->usesBegin());
5662 if (iter == ins->usesEnd()) {
5663 return false;
5666 MNode* node = iter->consumer();
5667 if (!node->isDefinition()) {
5668 return false;
5671 if (!node->toDefinition()->isTest()) {
5672 return false;
5675 iter++;
5676 return iter == ins->usesEnd();
5679 void LIRGenerator::visitIsObject(MIsObject* ins) {
5680 if (CanEmitAtUseForSingleTest(ins)) {
5681 emitAtUses(ins);
5682 return;
5685 MDefinition* opd = ins->input();
5686 MOZ_ASSERT(opd->type() == MIRType::Value);
5687 LIsObject* lir = new (alloc()) LIsObject(useBoxAtStart(opd));
5688 define(lir, ins);
5691 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined* ins) {
5692 if (CanEmitAtUseForSingleTest(ins)) {
5693 emitAtUses(ins);
5694 return;
5697 MDefinition* opd = ins->input();
5698 if (opd->type() == MIRType::Value) {
5699 auto* lir = new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd));
5700 define(lir, ins);
5701 } else {
5702 define(new (alloc()) LInteger(IsNullOrUndefined(opd->type())), ins);
5706 void LIRGenerator::visitHasClass(MHasClass* ins) {
5707 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5708 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5709 define(new (alloc()) LHasClass(useRegister(ins->object())), ins);
5712 void LIRGenerator::visitGuardToClass(MGuardToClass* ins) {
5713 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5714 MOZ_ASSERT(ins->type() == MIRType::Object);
5715 LGuardToClass* lir =
5716 new (alloc()) LGuardToClass(useRegisterAtStart(ins->object()), temp());
5717 assignSnapshot(lir, ins->bailoutKind());
5718 defineReuseInput(lir, ins, 0);
5721 void LIRGenerator::visitGuardToFunction(MGuardToFunction* ins) {
5722 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5723 MOZ_ASSERT(ins->type() == MIRType::Object);
5724 LGuardToFunction* lir =
5725 new (alloc()) LGuardToFunction(useRegisterAtStart(ins->object()), temp());
5726 assignSnapshot(lir, ins->bailoutKind());
5727 defineReuseInput(lir, ins, 0);
5730 void LIRGenerator::visitObjectClassToString(MObjectClassToString* ins) {
5731 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5732 MOZ_ASSERT(ins->type() == MIRType::String);
5733 auto* lir = new (alloc()) LObjectClassToString(
5734 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0));
5735 assignSnapshot(lir, ins->bailoutKind());
5736 defineReturn(lir, ins);
5739 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) {
5740 MOZ_ASSERT(ins->offset());
5741 if (ins->base()->type() == MIRType::Int32) {
5742 MOZ_ASSERT(ins->type() == MIRType::Int32);
5743 MOZ_ASSERT(ins->offset() <= UINT32_MAX); // Because memory32
5744 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins);
5745 } else {
5746 MOZ_ASSERT(ins->type() == MIRType::Int64);
5747 #ifdef JS_64BIT
5748 defineInt64(new (alloc())
5749 LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5750 ins);
5751 #else
5752 // Avoid situation where the input is (a,b) and the output is (b,a).
5753 defineInt64ReuseInput(
5754 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5755 ins, 0);
5756 #endif
5760 void LIRGenerator::visitWasmLoadInstance(MWasmLoadInstance* ins) {
5761 if (ins->type() == MIRType::Int64) {
5762 #ifdef JS_PUNBOX64
5763 LAllocation instance = useRegisterAtStart(ins->instance());
5764 #else
5765 // Avoid reusing instance for a 64-bit output pair as the load clobbers the
5766 // first half of that pair before loading the second half.
5767 LAllocation instance = useRegister(ins->instance());
5768 #endif
5769 auto* lir = new (alloc()) LWasmLoadInstance64(instance);
5770 defineInt64(lir, ins);
5771 } else {
5772 auto* lir =
5773 new (alloc()) LWasmLoadInstance(useRegisterAtStart(ins->instance()));
5774 define(lir, ins);
5778 void LIRGenerator::visitWasmStoreInstance(MWasmStoreInstance* ins) {
5779 MDefinition* value = ins->value();
5780 if (value->type() == MIRType::Int64) {
5781 #ifdef JS_PUNBOX64
5782 LAllocation instance = useRegisterAtStart(ins->instance());
5783 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5784 #else
5785 LAllocation instance = useRegister(ins->instance());
5786 LInt64Allocation valueAlloc = useInt64Register(value);
5787 #endif
5788 add(new (alloc()) LWasmStoreSlotI64(valueAlloc, instance, ins->offset(),
5789 mozilla::Nothing()),
5790 ins);
5791 } else {
5792 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5793 LAllocation instance = useRegisterAtStart(ins->instance());
5794 LAllocation valueAlloc = useRegisterAtStart(value);
5795 add(new (alloc())
5796 LWasmStoreSlot(valueAlloc, instance, ins->offset(), value->type(),
5797 MNarrowingOp::None, mozilla::Nothing()),
5798 ins);
5802 void LIRGenerator::visitWasmHeapReg(MWasmHeapReg* ins) {
5803 #ifdef WASM_HAS_HEAPREG
5804 auto* lir = new (alloc()) LWasmHeapReg();
5805 define(lir, ins);
5806 #else
5807 MOZ_CRASH();
5808 #endif
5811 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) {
5812 MOZ_ASSERT(!ins->isRedundant());
5814 MDefinition* index = ins->index();
5815 MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
5817 MOZ_ASSERT(boundsCheckLimit->type() == index->type());
5819 if (index->type() == MIRType::Int64) {
5820 if (JitOptions.spectreIndexMasking) {
5821 auto* lir = new (alloc()) LWasmBoundsCheck64(
5822 useInt64RegisterAtStart(index), useInt64Register(boundsCheckLimit));
5823 defineInt64ReuseInput(lir, ins, 0);
5824 } else {
5825 auto* lir = new (alloc())
5826 LWasmBoundsCheck64(useInt64RegisterAtStart(index),
5827 useInt64RegisterAtStart(boundsCheckLimit));
5828 add(lir, ins);
5830 } else {
5831 MOZ_ASSERT(index->type() == MIRType::Int32);
5833 if (JitOptions.spectreIndexMasking) {
5834 auto* lir = new (alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
5835 useRegister(boundsCheckLimit));
5836 defineReuseInput(lir, ins, 0);
5837 } else {
5838 auto* lir = new (alloc()) LWasmBoundsCheck(
5839 useRegisterAtStart(index), useRegisterAtStart(boundsCheckLimit));
5840 add(lir, ins);
5845 void LIRGenerator::visitWasmBoundsCheckRange32(MWasmBoundsCheckRange32* ins) {
5846 MDefinition* index = ins->index();
5847 MDefinition* length = ins->length();
5848 MDefinition* limit = ins->limit();
5850 MOZ_ASSERT(index->type() == MIRType::Int32);
5851 MOZ_ASSERT(length->type() == MIRType::Int32);
5852 MOZ_ASSERT(limit->type() == MIRType::Int32);
5854 add(new (alloc()) LWasmBoundsCheckRange32(
5855 useRegister(index), useRegister(length), useRegister(limit), temp()),
5856 ins);
5859 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) {
5860 MDefinition* index = ins->index();
5861 if (index->type() == MIRType::Int64) {
5862 auto* lir =
5863 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index));
5864 add(lir, ins);
5865 } else {
5866 auto* lir = new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index));
5867 add(lir, ins);
5871 void LIRGenerator::visitWasmLoadInstanceDataField(
5872 MWasmLoadInstanceDataField* ins) {
5873 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
5874 if (ins->type() == MIRType::Int64) {
5875 #ifdef JS_PUNBOX64
5876 LAllocation instance = useRegisterAtStart(ins->instance());
5877 #else
5878 // Avoid reusing instance for the output pair as the load clobbers the first
5879 // half of that pair before loading the second half.
5880 LAllocation instance = useRegister(ins->instance());
5881 #endif
5882 defineInt64(new (alloc())
5883 LWasmLoadSlotI64(instance, offs, mozilla::Nothing()),
5884 ins);
5885 } else {
5886 LAllocation instance = useRegisterAtStart(ins->instance());
5887 define(new (alloc()) LWasmLoadSlot(instance, offs, ins->type(),
5888 MWideningOp::None, mozilla::Nothing()),
5889 ins);
5893 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell* ins) {
5894 if (ins->type() == MIRType::Int64) {
5895 #ifdef JS_PUNBOX64
5896 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5897 #else
5898 // Avoid reusing cellPtr for the output pair as the load clobbers the first
5899 // half of that pair before loading the second half.
5900 LAllocation cellPtr = useRegister(ins->cellPtr());
5901 #endif
5902 defineInt64(new (alloc())
5903 LWasmLoadSlotI64(cellPtr, /*offset=*/0, mozilla::Nothing()),
5904 ins);
5905 } else {
5906 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5907 define(new (alloc()) LWasmLoadSlot(cellPtr, /*offset=*/0, ins->type(),
5908 MWideningOp::None, mozilla::Nothing()),
5909 ins);
5913 void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement* ins) {
5914 LAllocation elements = useRegisterAtStart(ins->elements());
5915 LAllocation index = useRegisterAtStart(ins->index());
5916 define(new (alloc()) LWasmLoadTableElement(elements, index), ins);
5919 void LIRGenerator::visitWasmStoreInstanceDataField(
5920 MWasmStoreInstanceDataField* ins) {
5921 MDefinition* value = ins->value();
5922 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
5923 if (value->type() == MIRType::Int64) {
5924 #ifdef JS_PUNBOX64
5925 LAllocation instance = useRegisterAtStart(ins->instance());
5926 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5927 #else
5928 LAllocation instance = useRegister(ins->instance());
5929 LInt64Allocation valueAlloc = useInt64Register(value);
5930 #endif
5931 add(new (alloc())
5932 LWasmStoreSlotI64(valueAlloc, instance, offs, mozilla::Nothing()),
5933 ins);
5934 } else {
5935 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5936 LAllocation instance = useRegisterAtStart(ins->instance());
5937 LAllocation valueAlloc = useRegisterAtStart(value);
5938 add(new (alloc()) LWasmStoreSlot(valueAlloc, instance, offs, value->type(),
5939 MNarrowingOp::None, mozilla::Nothing()),
5940 ins);
5944 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell* ins) {
5945 MDefinition* value = ins->value();
5946 size_t offs = 0;
5947 if (value->type() == MIRType::Int64) {
5948 #ifdef JS_PUNBOX64
5949 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5950 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5951 #else
5952 LAllocation cellPtr = useRegister(ins->cellPtr());
5953 LInt64Allocation valueAlloc = useInt64Register(value);
5954 #endif
5955 add(new (alloc())
5956 LWasmStoreSlotI64(valueAlloc, cellPtr, offs, mozilla::Nothing()));
5957 } else {
5958 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5959 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5960 LAllocation valueAlloc = useRegisterAtStart(value);
5961 add(new (alloc()) LWasmStoreSlot(valueAlloc, cellPtr, offs, value->type(),
5962 MNarrowingOp::None, mozilla::Nothing()));
5966 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult* ins) {
5967 MDefinition* stackResultArea = ins->stackResultArea();
5968 MDefinition* value = ins->value();
5969 size_t offs = ins->offset();
5970 LInstruction* lir;
5971 if (value->type() == MIRType::Int64) {
5972 lir = new (alloc())
5973 LWasmStoreSlotI64(useInt64Register(value), useRegister(stackResultArea),
5974 offs, mozilla::Nothing());
5975 } else {
5976 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5977 lir = new (alloc())
5978 LWasmStoreSlot(useRegister(value), useRegister(stackResultArea), offs,
5979 value->type(), MNarrowingOp::None, mozilla::Nothing());
5981 add(lir, ins);
5984 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer* ins) {
5985 LAllocation base = useRegisterAtStart(ins->base());
5986 define(new (alloc()) LWasmDerivedPointer(base), ins);
5989 void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer* ins) {
5990 LAllocation base = useRegisterAtStart(ins->base());
5991 LAllocation index = useRegisterAtStart(ins->index());
5992 define(new (alloc()) LWasmDerivedIndexPointer(base, index), ins);
5995 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef* ins) {
5996 LAllocation instance = useRegister(ins->instance());
5997 LAllocation valueBase = useFixed(ins->valueBase(), PreBarrierReg);
5998 LAllocation value = useRegister(ins->value());
5999 uint32_t valueOffset = ins->offset();
6000 add(new (alloc())
6001 LWasmStoreRef(instance, valueBase, value, temp(), valueOffset,
6002 mozilla::Nothing(), ins->preBarrierKind()),
6003 ins);
6006 void LIRGenerator::visitWasmPostWriteBarrier(MWasmPostWriteBarrier* ins) {
6007 LWasmPostWriteBarrier* lir = new (alloc()) LWasmPostWriteBarrier(
6008 useFixed(ins->instance(), InstanceReg), useRegister(ins->object()),
6009 useRegister(ins->valueBase()), useRegister(ins->value()), temp(),
6010 ins->valueOffset());
6011 add(lir, ins);
6012 assignWasmSafepoint(lir);
6015 void LIRGenerator::visitWasmParameter(MWasmParameter* ins) {
6016 ABIArg abi = ins->abi();
6017 if (ins->type() == MIRType::StackResults) {
6018 // Functions that return stack results receive an extra incoming parameter
6019 // with type MIRType::StackResults. This value is a pointer to fresh
6020 // memory. Here we treat it as if it were in fact MIRType::Pointer.
6021 auto* lir = new (alloc()) LWasmParameter;
6022 LDefinition def(LDefinition::TypeFrom(MIRType::Pointer),
6023 LDefinition::FIXED);
6024 def.setOutput(abi.argInRegister() ? LAllocation(abi.reg())
6025 : LArgument(abi.offsetFromArgBase()));
6026 define(lir, ins, def);
6027 return;
6029 if (abi.argInRegister()) {
6030 #if defined(JS_NUNBOX32)
6031 if (abi.isGeneralRegPair()) {
6032 defineInt64Fixed(
6033 new (alloc()) LWasmParameterI64, ins,
6034 LInt64Allocation(LAllocation(AnyRegister(abi.gpr64().high)),
6035 LAllocation(AnyRegister(abi.gpr64().low))));
6036 return;
6038 #endif
6039 defineFixed(new (alloc()) LWasmParameter, ins, LAllocation(abi.reg()));
6040 return;
6042 if (ins->type() == MIRType::Int64) {
6043 MOZ_ASSERT(!abi.argInRegister());
6044 defineInt64Fixed(
6045 new (alloc()) LWasmParameterI64, ins,
6046 #if defined(JS_NUNBOX32)
6047 LInt64Allocation(LArgument(abi.offsetFromArgBase() + INT64HIGH_OFFSET),
6048 LArgument(abi.offsetFromArgBase() + INT64LOW_OFFSET))
6049 #else
6050 LInt64Allocation(LArgument(abi.offsetFromArgBase()))
6051 #endif
6053 } else {
6054 MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType::WasmAnyRef
6055 #ifdef ENABLE_WASM_SIMD
6056 || ins->type() == MIRType::Simd128
6057 #endif
6059 defineFixed(new (alloc()) LWasmParameter, ins,
6060 LArgument(abi.offsetFromArgBase()));
6064 void LIRGenerator::visitWasmReturn(MWasmReturn* ins) {
6065 MDefinition* rval = ins->getOperand(0);
6066 MDefinition* instance = ins->getOperand(1);
6068 if (rval->type() == MIRType::Int64) {
6069 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64),
6070 useFixed(instance, InstanceReg)));
6071 return;
6074 LAllocation returnReg;
6075 if (rval->type() == MIRType::Float32) {
6076 returnReg = useFixed(rval, ReturnFloat32Reg);
6077 } else if (rval->type() == MIRType::Double) {
6078 returnReg = useFixed(rval, ReturnDoubleReg);
6079 #ifdef ENABLE_WASM_SIMD
6080 } else if (rval->type() == MIRType::Simd128) {
6081 returnReg = useFixed(rval, ReturnSimd128Reg);
6082 #endif
6083 } else if (rval->type() == MIRType::Int32 ||
6084 rval->type() == MIRType::WasmAnyRef) {
6085 returnReg = useFixed(rval, ReturnReg);
6086 } else {
6087 MOZ_CRASH("Unexpected wasm return type");
6090 LWasmReturn* lir =
6091 new (alloc()) LWasmReturn(useFixed(instance, InstanceReg), returnReg);
6092 add(lir);
6095 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins) {
6096 MDefinition* instance = ins->getOperand(0);
6097 LWasmReturnVoid* lir =
6098 new (alloc()) LWasmReturnVoid(useFixed(instance, InstanceReg));
6099 add(lir);
6102 void LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) {
6103 if (ins->arg()->type() == MIRType::Int64) {
6104 add(new (alloc())
6105 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())),
6106 ins);
6107 } else if (IsFloatingPointType(ins->arg()->type())) {
6108 MOZ_ASSERT(!ins->arg()->isEmittedAtUses());
6109 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins);
6110 } else {
6111 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins->arg())),
6112 ins);
6116 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult* ins) {
6117 auto* lir = new (alloc()) LWasmRegisterResult();
6118 uint32_t vreg = getVirtualRegister();
6119 MOZ_ASSERT(ins->type() != MIRType::Int64);
6120 auto type = LDefinition::TypeFrom(ins->type());
6121 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ins->loc())));
6122 ins->setVirtualRegister(vreg);
6123 add(lir, ins);
6126 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult* ins) {
6127 auto* lir = new (alloc()) LWasmRegisterResult();
6128 uint32_t vreg = getVirtualRegister();
6129 auto type = LDefinition::TypeFrom(ins->type());
6130 lir->setDef(0, LDefinition(vreg, type, LFloatReg(ins->loc())));
6131 ins->setVirtualRegister(vreg);
6132 add(lir, ins);
6135 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result* ins) {
6136 MOZ_ASSERT(ins->type() == MIRType::Int64);
6137 uint32_t vreg = getVirtualRegister();
6139 #if defined(JS_NUNBOX32)
6140 auto* lir = new (alloc()) LWasmRegisterPairResult();
6141 lir->setDef(INT64LOW_INDEX,
6142 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL,
6143 LGeneralReg(ins->loc().low)));
6144 lir->setDef(INT64HIGH_INDEX,
6145 LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL,
6146 LGeneralReg(ins->loc().high)));
6147 getVirtualRegister();
6148 #elif defined(JS_PUNBOX64)
6149 auto* lir = new (alloc()) LWasmRegisterResult();
6150 lir->setDef(
6151 0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ins->loc().reg)));
6152 #else
6153 # error expected either JS_NUNBOX32 or JS_PUNBOX64
6154 #endif
6156 ins->setVirtualRegister(vreg);
6157 add(lir, ins);
6160 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea* ins) {
6161 MOZ_ASSERT(ins->type() == MIRType::StackResults);
6162 auto* lir = new (alloc()) LWasmStackResultArea(temp());
6163 uint32_t vreg = getVirtualRegister();
6164 lir->setDef(0,
6165 LDefinition(vreg, LDefinition::STACKRESULTS, LDefinition::STACK));
6166 ins->setVirtualRegister(vreg);
6167 add(lir, ins);
6170 void LIRGenerator::visitWasmStackResult(MWasmStackResult* ins) {
6171 MWasmStackResultArea* area = ins->resultArea()->toWasmStackResultArea();
6172 LDefinition::Policy pol = LDefinition::STACK;
6174 if (ins->type() == MIRType::Int64) {
6175 auto* lir = new (alloc()) LWasmStackResult64;
6176 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6177 uint32_t vreg = getVirtualRegister();
6178 LDefinition::Type typ = LDefinition::GENERAL;
6179 #if defined(JS_NUNBOX32)
6180 getVirtualRegister();
6181 lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, typ, pol));
6182 lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, typ, pol));
6183 #else
6184 lir->setDef(0, LDefinition(vreg, typ, pol));
6185 #endif
6186 ins->setVirtualRegister(vreg);
6187 add(lir, ins);
6188 return;
6191 auto* lir = new (alloc()) LWasmStackResult;
6192 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6193 uint32_t vreg = getVirtualRegister();
6194 LDefinition::Type typ = LDefinition::TypeFrom(ins->type());
6195 lir->setDef(0, LDefinition(vreg, typ, pol));
6196 ins->setVirtualRegister(vreg);
6197 add(lir, ins);
6200 template <class MWasmCallT>
6201 void LIRGenerator::visitWasmCall(MWasmCallT ins) {
6202 bool needsBoundsCheck = true;
6203 mozilla::Maybe<uint32_t> tableSize;
6205 if (ins->callee().isTable()) {
6206 MDefinition* index = ins->getOperand(ins->numArgs());
6208 if (ins->callee().which() == wasm::CalleeDesc::WasmTable) {
6209 uint32_t minLength = ins->callee().wasmTableMinLength();
6210 mozilla::Maybe<uint32_t> maxLength = ins->callee().wasmTableMaxLength();
6211 if (index->isConstant() &&
6212 uint32_t(index->toConstant()->toInt32()) < minLength) {
6213 needsBoundsCheck = false;
6215 if (maxLength.isSome() && *maxLength == minLength) {
6216 tableSize = maxLength;
6221 auto* lir = allocateVariadic<LWasmCall>(ins->numOperands(), needsBoundsCheck,
6222 tableSize);
6223 if (!lir) {
6224 abort(AbortReason::Alloc, "OOM: LIRGenerator::lowerWasmCall");
6225 return;
6228 for (unsigned i = 0; i < ins->numArgs(); i++) {
6229 lir->setOperand(
6230 i, useFixedAtStart(ins->getOperand(i), ins->registerForArg(i)));
6233 if (ins->callee().isTable()) {
6234 MDefinition* index = ins->getOperand(ins->numArgs());
6235 lir->setOperand(ins->numArgs(),
6236 useFixedAtStart(index, WasmTableCallIndexReg));
6238 if (ins->callee().isFuncRef()) {
6239 MDefinition* ref = ins->getOperand(ins->numArgs());
6240 lir->setOperand(ins->numArgs(), useFixedAtStart(ref, WasmCallRefReg));
6243 add(lir, ins);
6244 assignWasmSafepoint(lir);
6246 // WasmCall with WasmTable has two call instructions, and they both need a
6247 // safepoint associated with them. Create a second safepoint here; the node
6248 // otherwise does nothing, and codegen for it only marks the safepoint at the
6249 // node.
6250 if (ins->callee().which() == wasm::CalleeDesc::WasmTable &&
6251 !ins->isWasmReturnCall()) {
6252 auto* adjunctSafepoint = new (alloc()) LWasmCallIndirectAdjunctSafepoint();
6253 add(adjunctSafepoint);
6254 assignWasmSafepoint(adjunctSafepoint);
6255 lir->setAdjunctSafepoint(adjunctSafepoint);
6259 void LIRGenerator::visitWasmCallCatchable(MWasmCallCatchable* ins) {
6260 visitWasmCall(ins);
6263 void LIRGenerator::visitWasmCallUncatchable(MWasmCallUncatchable* ins) {
6264 visitWasmCall(ins);
6267 void LIRGenerator::visitWasmReturnCall(MWasmReturnCall* ins) {
6268 visitWasmCall(ins);
6271 void LIRGenerator::visitWasmCallLandingPrePad(MWasmCallLandingPrePad* ins) {
6272 add(new (alloc()) LWasmCallLandingPrePad, ins);
6275 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty* ins) {
6276 MDefinition* val = ins->value();
6278 Register cxReg, objReg, privReg, valueReg;
6279 GetTempRegForIntArg(0, 0, &cxReg);
6280 GetTempRegForIntArg(1, 0, &objReg);
6281 GetTempRegForIntArg(2, 0, &privReg);
6282 GetTempRegForIntArg(3, 0, &valueReg);
6284 // Keep using GetTempRegForIntArg, since we want to make sure we
6285 // don't clobber registers we're already using.
6286 Register tempReg1, tempReg2;
6287 GetTempRegForIntArg(4, 0, &tempReg1);
6288 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
6289 MOZ_ASSERT(ok, "How can we not have six temp registers?");
6291 LSetDOMProperty* lir = new (alloc())
6292 LSetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6293 useBoxFixedAtStart(val, tempReg1, tempReg2),
6294 tempFixed(privReg), tempFixed(valueReg));
6295 add(lir, ins);
6296 assignSafepoint(lir, ins);
6299 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins) {
6300 Register cxReg, objReg, privReg, valueReg;
6301 GetTempRegForIntArg(0, 0, &cxReg);
6302 GetTempRegForIntArg(1, 0, &objReg);
6303 GetTempRegForIntArg(2, 0, &privReg);
6304 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
6305 MOZ_ASSERT(ok, "How can we not have four temp registers?");
6306 LGetDOMProperty* lir = new (alloc())
6307 LGetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6308 tempFixed(privReg), tempFixed(valueReg));
6310 defineReturn(lir, ins);
6311 assignSafepoint(lir, ins);
6314 void LIRGenerator::visitGetDOMMember(MGetDOMMember* ins) {
6315 MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
6316 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
6317 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
6318 // value can in fact change as a result of DOM setters and method calls.
6319 MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
6320 "Member gets had better not alias the world");
6322 MDefinition* obj = ins->object();
6323 MOZ_ASSERT(obj->type() == MIRType::Object);
6325 MIRType type = ins->type();
6327 if (type == MIRType::Value) {
6328 LGetDOMMemberV* lir = new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj));
6329 defineBox(lir, ins);
6330 } else {
6331 LGetDOMMemberT* lir =
6332 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj, type));
6333 define(lir, ins);
6337 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue* ins) {
6338 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6339 auto* lir =
6340 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins->proxy()));
6341 defineBox(lir, ins);
6344 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration(
6345 MLoadDOMExpandoValueGuardGeneration* ins) {
6346 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6347 auto* lir = new (alloc())
6348 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins->proxy()));
6349 assignSnapshot(lir, ins->bailoutKind());
6350 defineBox(lir, ins);
6353 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration(
6354 MLoadDOMExpandoValueIgnoreGeneration* ins) {
6355 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6356 auto* lir = new (alloc())
6357 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins->proxy()));
6358 defineBox(lir, ins);
6361 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape(
6362 MGuardDOMExpandoMissingOrGuardShape* ins) {
6363 MOZ_ASSERT(ins->expando()->type() == MIRType::Value);
6364 auto* lir = new (alloc())
6365 LGuardDOMExpandoMissingOrGuardShape(useBox(ins->expando()), temp());
6366 assignSnapshot(lir, ins->bailoutKind());
6367 add(lir, ins);
6368 redefine(ins, ins->expando());
6371 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter* ins) {
6372 LIncrementWarmUpCounter* lir = new (alloc()) LIncrementWarmUpCounter(temp());
6373 add(lir, ins);
6376 void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) {
6377 MDefinition* input = ins->input();
6378 MOZ_ASSERT(input->type() == MIRType::Value);
6379 LLexicalCheck* lir = new (alloc()) LLexicalCheck(useBox(input));
6380 assignSnapshot(lir, ins->bailoutKind());
6381 add(lir, ins);
6382 redefine(ins, input);
6385 void LIRGenerator::visitThrowRuntimeLexicalError(
6386 MThrowRuntimeLexicalError* ins) {
6387 LThrowRuntimeLexicalError* lir = new (alloc()) LThrowRuntimeLexicalError();
6388 add(lir, ins);
6389 assignSafepoint(lir, ins);
6392 void LIRGenerator::visitThrowMsg(MThrowMsg* ins) {
6393 LThrowMsg* lir = new (alloc()) LThrowMsg();
6394 add(lir, ins);
6395 assignSafepoint(lir, ins);
6398 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation* ins) {
6399 LGlobalDeclInstantiation* lir = new (alloc()) LGlobalDeclInstantiation();
6400 add(lir, ins);
6401 assignSafepoint(lir, ins);
6404 void LIRGenerator::visitDebugger(MDebugger* ins) {
6405 auto* lir = new (alloc()) LDebugger(tempFixed(CallTempReg0));
6406 assignSnapshot(lir, ins->bailoutKind());
6407 add(lir, ins);
6410 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins) {
6411 define(new (alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
6414 void LIRGenerator::visitCheckReturn(MCheckReturn* ins) {
6415 MDefinition* retVal = ins->returnValue();
6416 MDefinition* thisVal = ins->thisValue();
6417 MOZ_ASSERT(retVal->type() == MIRType::Value);
6418 MOZ_ASSERT(thisVal->type() == MIRType::Value);
6420 auto* lir =
6421 new (alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal));
6422 defineBox(lir, ins);
6423 assignSafepoint(lir, ins);
6426 void LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) {
6427 MDefinition* input = ins->input();
6428 MOZ_ASSERT(input->type() == MIRType::Value);
6430 LCheckIsObj* lir = new (alloc()) LCheckIsObj(useBox(input));
6431 define(lir, ins);
6432 assignSafepoint(lir, ins);
6435 #ifdef JS_PUNBOX64
6436 void LIRGenerator::visitCheckScriptedProxyGetResult(
6437 MCheckScriptedProxyGetResult* ins) {
6438 MDefinition* target = ins->target();
6439 MDefinition* id = ins->id();
6440 MDefinition* value = ins->value();
6442 LCheckScriptedProxyGetResult* lir =
6443 new (alloc()) LCheckScriptedProxyGetResult(useBox(target), useBox(id),
6444 useBox(value), temp(), temp());
6445 add(lir, ins);
6446 assignSafepoint(lir, ins);
6448 #endif
6450 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) {
6451 MDefinition* checkVal = ins->checkValue();
6452 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6454 auto* lir = new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal));
6455 redefine(ins, checkVal);
6456 add(lir, ins);
6457 assignSafepoint(lir, ins);
6460 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage* ins) {
6461 MDefinition* heritage = ins->heritage();
6462 MOZ_ASSERT(heritage->type() == MIRType::Value);
6464 auto* lir =
6465 new (alloc()) LCheckClassHeritage(useBox(heritage), temp(), temp());
6466 redefine(ins, heritage);
6467 add(lir, ins);
6468 assignSafepoint(lir, ins);
6471 void LIRGenerator::visitCheckThis(MCheckThis* ins) {
6472 MDefinition* thisValue = ins->thisValue();
6473 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6475 auto* lir = new (alloc()) LCheckThis(useBoxAtStart(thisValue));
6476 redefine(ins, thisValue);
6477 add(lir, ins);
6478 assignSafepoint(lir, ins);
6481 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit* ins) {
6482 MDefinition* thisValue = ins->thisValue();
6483 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6485 auto* lir = new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue));
6486 redefine(ins, thisValue);
6487 add(lir, ins);
6488 assignSafepoint(lir, ins);
6491 void LIRGenerator::visitGenerator(MGenerator* ins) {
6492 auto* lir =
6493 new (alloc()) LGenerator(useRegisterAtStart(ins->callee()),
6494 useRegisterAtStart(ins->environmentChain()),
6495 useRegisterAtStart(ins->argsObject()));
6496 defineReturn(lir, ins);
6497 assignSafepoint(lir, ins);
6500 void LIRGenerator::visitAsyncResolve(MAsyncResolve* ins) {
6501 auto* lir = new (alloc()) LAsyncResolve(useRegisterAtStart(ins->generator()),
6502 useBoxAtStart(ins->value()));
6503 defineReturn(lir, ins);
6504 assignSafepoint(lir, ins);
6507 void LIRGenerator::visitAsyncReject(MAsyncReject* ins) {
6508 auto* lir = new (alloc())
6509 LAsyncReject(useRegisterAtStart(ins->generator()),
6510 useBoxAtStart(ins->reason()), useBoxAtStart(ins->stack()));
6511 defineReturn(lir, ins);
6512 assignSafepoint(lir, ins);
6515 void LIRGenerator::visitAsyncAwait(MAsyncAwait* ins) {
6516 MOZ_ASSERT(ins->generator()->type() == MIRType::Object);
6517 auto* lir = new (alloc()) LAsyncAwait(useBoxAtStart(ins->value()),
6518 useRegisterAtStart(ins->generator()));
6519 defineReturn(lir, ins);
6520 assignSafepoint(lir, ins);
6523 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait* ins) {
6524 auto* lir = new (alloc()) LCanSkipAwait(useBoxAtStart(ins->value()));
6525 defineReturn(lir, ins);
6526 assignSafepoint(lir, ins);
6529 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue* ins) {
6530 auto* lir = new (alloc()) LMaybeExtractAwaitValue(
6531 useBoxAtStart(ins->value()), useRegisterAtStart(ins->canSkip()));
6532 defineReturn(lir, ins);
6533 assignSafepoint(lir, ins);
6536 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) {
6537 MDefinition* checkVal = ins->checkValue();
6538 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6540 LDebugCheckSelfHosted* lir =
6541 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal));
6542 redefine(ins, checkVal);
6543 add(lir, ins);
6544 assignSafepoint(lir, ins);
6547 void LIRGenerator::visitIsPackedArray(MIsPackedArray* ins) {
6548 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6549 MOZ_ASSERT(ins->type() == MIRType::Boolean);
6551 auto lir = new (alloc()) LIsPackedArray(useRegister(ins->object()), temp());
6552 define(lir, ins);
6555 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked* ins) {
6556 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
6558 auto* lir = new (alloc())
6559 LGuardArrayIsPacked(useRegister(ins->array()), temp(), temp());
6560 assignSnapshot(lir, ins->bailoutKind());
6561 add(lir, ins);
6562 redefine(ins, ins->array());
6565 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf* ins) {
6566 MOZ_ASSERT(ins->target()->type() == MIRType::Object);
6567 MOZ_ASSERT(ins->type() == MIRType::Value);
6569 auto lir = new (alloc()) LGetPrototypeOf(useRegister(ins->target()));
6570 defineBox(lir, ins);
6571 assignSafepoint(lir, ins);
6574 void LIRGenerator::visitObjectWithProto(MObjectWithProto* ins) {
6575 MOZ_ASSERT(ins->prototype()->type() == MIRType::Value);
6576 MOZ_ASSERT(ins->type() == MIRType::Object);
6578 auto* lir = new (alloc()) LObjectWithProto(useBoxAtStart(ins->prototype()));
6579 defineReturn(lir, ins);
6580 assignSafepoint(lir, ins);
6583 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto* ins) {
6584 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6585 MOZ_ASSERT(ins->type() == MIRType::Object);
6587 auto* lir =
6588 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins->object()));
6589 define(lir, ins);
6592 void LIRGenerator::visitBuiltinObject(MBuiltinObject* ins) {
6593 MOZ_ASSERT(ins->type() == MIRType::Object);
6595 auto* lir = new (alloc()) LBuiltinObject();
6596 defineReturn(lir, ins);
6597 assignSafepoint(lir, ins);
6600 void LIRGenerator::visitReturn(MReturn* ret) {
6601 return visitReturnImpl(ret->getOperand(0));
6604 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn* ret) {
6605 return visitReturnImpl(ret->getOperand(0), true);
6608 void LIRGenerator::visitSuperFunction(MSuperFunction* ins) {
6609 MOZ_ASSERT(ins->callee()->type() == MIRType::Object);
6610 MOZ_ASSERT(ins->type() == MIRType::Value);
6612 auto* lir = new (alloc()) LSuperFunction(useRegister(ins->callee()), temp());
6613 defineBox(lir, ins);
6616 void LIRGenerator::visitInitHomeObject(MInitHomeObject* ins) {
6617 MDefinition* function = ins->function();
6618 MOZ_ASSERT(function->type() == MIRType::Object);
6620 MDefinition* homeObject = ins->homeObject();
6621 MOZ_ASSERT(homeObject->type() == MIRType::Value);
6623 MOZ_ASSERT(ins->type() == MIRType::Object);
6625 auto* lir = new (alloc())
6626 LInitHomeObject(useRegisterAtStart(function), useBoxAtStart(homeObject));
6627 redefine(ins, function);
6628 add(lir, ins);
6631 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor* ins) {
6632 MDefinition* object = ins->object();
6633 MOZ_ASSERT(object->type() == MIRType::Object);
6635 auto* lir = new (alloc()) LIsTypedArrayConstructor(useRegister(object));
6636 define(lir, ins);
6639 void LIRGenerator::visitLoadValueTag(MLoadValueTag* ins) {
6640 MDefinition* value = ins->value();
6641 MOZ_ASSERT(value->type() == MIRType::Value);
6643 define(new (alloc()) LLoadValueTag(useBoxAtStart(value)), ins);
6646 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual* ins) {
6647 MDefinition* lhs = ins->lhs();
6648 MOZ_ASSERT(lhs->type() == MIRType::Int32);
6650 MDefinition* rhs = ins->rhs();
6651 MOZ_ASSERT(rhs->type() == MIRType::Int32);
6653 auto* guard =
6654 new (alloc()) LGuardTagNotEqual(useRegister(lhs), useRegister(rhs));
6655 assignSnapshot(guard, ins->bailoutKind());
6656 add(guard, ins);
6659 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget* ins) {
6660 MDefinition* object = ins->object();
6661 MOZ_ASSERT(object->type() == MIRType::Object);
6663 define(new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object)), ins);
6666 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter* ins) {
6667 MDefinition* object = ins->object();
6668 MOZ_ASSERT(object->type() == MIRType::Object);
6670 auto* guard = new (alloc())
6671 LGuardHasGetterSetter(useRegisterAtStart(object), tempFixed(CallTempReg0),
6672 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
6673 assignSnapshot(guard, ins->bailoutKind());
6674 add(guard, ins);
6675 redefine(ins, object);
6678 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible* ins) {
6679 MDefinition* object = ins->object();
6680 MOZ_ASSERT(object->type() == MIRType::Object);
6682 auto* guard = new (alloc()) LGuardIsExtensible(useRegister(object), temp());
6683 assignSnapshot(guard, ins->bailoutKind());
6684 add(guard, ins);
6685 redefine(ins, object);
6688 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative* ins) {
6689 MDefinition* index = ins->index();
6690 MOZ_ASSERT(index->type() == MIRType::Int32);
6692 auto* guard = new (alloc()) LGuardInt32IsNonNegative(useRegister(index));
6693 assignSnapshot(guard, ins->bailoutKind());
6694 add(guard, ins);
6695 redefine(ins, index);
6698 void LIRGenerator::visitGuardInt32Range(MGuardInt32Range* ins) {
6699 MDefinition* input = ins->input();
6700 MOZ_ASSERT(input->type() == MIRType::Int32);
6702 auto* guard = new (alloc()) LGuardInt32Range(useRegister(input));
6703 assignSnapshot(guard, ins->bailoutKind());
6704 add(guard, ins);
6705 redefine(ins, input);
6708 void LIRGenerator::visitGuardIndexIsNotDenseElement(
6709 MGuardIndexIsNotDenseElement* ins) {
6710 MDefinition* object = ins->object();
6711 MOZ_ASSERT(object->type() == MIRType::Object);
6713 MDefinition* index = ins->index();
6714 MOZ_ASSERT(index->type() == MIRType::Int32);
6716 LDefinition spectreTemp =
6717 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6719 auto* guard = new (alloc()) LGuardIndexIsNotDenseElement(
6720 useRegister(object), useRegister(index), temp(), spectreTemp);
6721 assignSnapshot(guard, ins->bailoutKind());
6722 add(guard, ins);
6723 redefine(ins, index);
6726 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd(
6727 MGuardIndexIsValidUpdateOrAdd* ins) {
6728 MDefinition* object = ins->object();
6729 MOZ_ASSERT(object->type() == MIRType::Object);
6731 MDefinition* index = ins->index();
6732 MOZ_ASSERT(index->type() == MIRType::Int32);
6734 LDefinition spectreTemp =
6735 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6737 auto* guard = new (alloc()) LGuardIndexIsValidUpdateOrAdd(
6738 useRegister(object), useRegister(index), temp(), spectreTemp);
6739 assignSnapshot(guard, ins->bailoutKind());
6740 add(guard, ins);
6741 redefine(ins, index);
6744 void LIRGenerator::visitCallAddOrUpdateSparseElement(
6745 MCallAddOrUpdateSparseElement* ins) {
6746 MDefinition* object = ins->object();
6747 MOZ_ASSERT(object->type() == MIRType::Object);
6749 MDefinition* index = ins->index();
6750 MOZ_ASSERT(index->type() == MIRType::Int32);
6752 MDefinition* value = ins->value();
6753 MOZ_ASSERT(value->type() == MIRType::Value);
6755 auto* lir = new (alloc()) LCallAddOrUpdateSparseElement(
6756 useRegisterAtStart(object), useRegisterAtStart(index),
6757 useBoxAtStart(value));
6758 add(lir, ins);
6759 assignSafepoint(lir, ins);
6762 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement* ins) {
6763 MDefinition* object = ins->object();
6764 MOZ_ASSERT(object->type() == MIRType::Object);
6766 MDefinition* index = ins->index();
6767 MOZ_ASSERT(index->type() == MIRType::Int32);
6769 auto* lir = new (alloc()) LCallGetSparseElement(useRegisterAtStart(object),
6770 useRegisterAtStart(index));
6771 defineReturn(lir, ins);
6772 assignSafepoint(lir, ins);
6775 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement* ins) {
6776 MDefinition* object = ins->object();
6777 MOZ_ASSERT(object->type() == MIRType::Object);
6779 MDefinition* index = ins->index();
6780 MOZ_ASSERT(index->type() == MIRType::Int32);
6782 auto* lir = new (alloc()) LCallNativeGetElement(useRegisterAtStart(object),
6783 useRegisterAtStart(index));
6784 defineReturn(lir, ins);
6785 assignSafepoint(lir, ins);
6788 void LIRGenerator::visitCallNativeGetElementSuper(
6789 MCallNativeGetElementSuper* ins) {
6790 MDefinition* object = ins->object();
6791 MOZ_ASSERT(object->type() == MIRType::Object);
6793 MDefinition* index = ins->index();
6794 MOZ_ASSERT(index->type() == MIRType::Int32);
6796 MDefinition* receiver = ins->receiver();
6798 auto* lir = new (alloc()) LCallNativeGetElementSuper(
6799 useRegisterAtStart(object), useRegisterAtStart(index),
6800 useBoxAtStart(receiver));
6801 defineReturn(lir, ins);
6802 assignSafepoint(lir, ins);
6805 void LIRGenerator::visitCallObjectHasSparseElement(
6806 MCallObjectHasSparseElement* ins) {
6807 MDefinition* object = ins->object();
6808 MOZ_ASSERT(object->type() == MIRType::Object);
6810 MDefinition* index = ins->index();
6811 MOZ_ASSERT(index->type() == MIRType::Int32);
6813 auto* lir = new (alloc()) LCallObjectHasSparseElement(
6814 useRegisterAtStart(object), useRegisterAtStart(index),
6815 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
6816 assignSnapshot(lir, ins->bailoutKind());
6817 defineReturn(lir, ins);
6820 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN* ins) {
6821 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
6822 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
6824 if (ins->bits()->isConstant()) {
6825 int32_t bits = ins->bits()->toConstant()->toInt32();
6826 if (bits == 64) {
6827 auto* lir = new (alloc())
6828 LBigIntAsIntN64(useRegister(ins->input()), temp(), tempInt64());
6829 define(lir, ins);
6830 assignSafepoint(lir, ins);
6831 return;
6833 if (bits == 32) {
6834 auto* lir = new (alloc())
6835 LBigIntAsIntN32(useRegister(ins->input()), temp(), tempInt64());
6836 define(lir, ins);
6837 assignSafepoint(lir, ins);
6838 return;
6842 auto* lir = new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins->bits()),
6843 useRegisterAtStart(ins->input()));
6844 defineReturn(lir, ins);
6845 assignSafepoint(lir, ins);
6848 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN* ins) {
6849 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
6850 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
6852 if (ins->bits()->isConstant()) {
6853 int32_t bits = ins->bits()->toConstant()->toInt32();
6854 if (bits == 64) {
6855 auto* lir = new (alloc())
6856 LBigIntAsUintN64(useRegister(ins->input()), temp(), tempInt64());
6857 define(lir, ins);
6858 assignSafepoint(lir, ins);
6859 return;
6861 if (bits == 32) {
6862 auto* lir = new (alloc())
6863 LBigIntAsUintN32(useRegister(ins->input()), temp(), tempInt64());
6864 define(lir, ins);
6865 assignSafepoint(lir, ins);
6866 return;
6870 auto* lir = new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins->bits()),
6871 useRegisterAtStart(ins->input()));
6872 defineReturn(lir, ins);
6873 assignSafepoint(lir, ins);
6876 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing* ins) {
6877 MDefinition* input = ins->input();
6879 auto* guard = new (alloc()) LGuardNonGCThing(useBox(input));
6880 assignSnapshot(guard, ins->bailoutKind());
6881 add(guard, ins);
6882 redefine(ins, input);
6885 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing* ins) {
6886 auto* lir =
6887 new (alloc()) LToHashableNonGCThing(useBox(ins->input()), tempDouble());
6888 defineBox(lir, ins);
6891 void LIRGenerator::visitToHashableString(MToHashableString* ins) {
6892 auto* lir = new (alloc()) LToHashableString(useRegister(ins->input()));
6893 define(lir, ins);
6894 assignSafepoint(lir, ins);
6897 void LIRGenerator::visitToHashableValue(MToHashableValue* ins) {
6898 auto* lir =
6899 new (alloc()) LToHashableValue(useBox(ins->input()), tempDouble());
6900 defineBox(lir, ins);
6901 assignSafepoint(lir, ins);
6904 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing* ins) {
6905 auto* lir = new (alloc()) LHashNonGCThing(useBox(ins->input()), temp());
6906 define(lir, ins);
6909 void LIRGenerator::visitHashString(MHashString* ins) {
6910 auto* lir = new (alloc()) LHashString(useRegister(ins->input()), temp());
6911 define(lir, ins);
6914 void LIRGenerator::visitHashSymbol(MHashSymbol* ins) {
6915 auto* lir = new (alloc()) LHashSymbol(useRegister(ins->input()));
6916 define(lir, ins);
6919 void LIRGenerator::visitHashBigInt(MHashBigInt* ins) {
6920 auto* lir = new (alloc())
6921 LHashBigInt(useRegister(ins->input()), temp(), temp(), temp());
6922 define(lir, ins);
6925 void LIRGenerator::visitHashObject(MHashObject* ins) {
6926 auto* lir =
6927 new (alloc()) LHashObject(useRegister(ins->set()), useBox(ins->input()),
6928 temp(), temp(), temp(), temp());
6929 define(lir, ins);
6932 void LIRGenerator::visitHashValue(MHashValue* ins) {
6933 auto* lir =
6934 new (alloc()) LHashValue(useRegister(ins->set()), useBox(ins->input()),
6935 temp(), temp(), temp(), temp());
6936 define(lir, ins);
6939 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt* ins) {
6940 auto* lir = new (alloc())
6941 LSetObjectHasNonBigInt(useRegister(ins->set()), useBox(ins->value()),
6942 useRegister(ins->hash()), temp(), temp());
6943 define(lir, ins);
6946 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt* ins) {
6947 auto* lir = new (alloc()) LSetObjectHasBigInt(
6948 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
6949 temp(), temp(), temp(), temp());
6950 define(lir, ins);
6953 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue* ins) {
6954 auto* lir = new (alloc()) LSetObjectHasValue(
6955 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
6956 temp(), temp(), temp(), temp());
6957 define(lir, ins);
6960 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall* ins) {
6961 auto* lir = new (alloc()) LSetObjectHasValueVMCall(
6962 useRegisterAtStart(ins->set()), useBoxAtStart(ins->value()));
6963 defineReturn(lir, ins);
6964 assignSafepoint(lir, ins);
6967 void LIRGenerator::visitSetObjectSize(MSetObjectSize* ins) {
6968 auto* lir = new (alloc()) LSetObjectSize(useRegisterAtStart(ins->set()));
6969 define(lir, ins);
6972 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt* ins) {
6973 auto* lir = new (alloc())
6974 LMapObjectHasNonBigInt(useRegister(ins->map()), useBox(ins->value()),
6975 useRegister(ins->hash()), temp(), temp());
6976 define(lir, ins);
6979 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt* ins) {
6980 auto* lir = new (alloc()) LMapObjectHasBigInt(
6981 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6982 temp(), temp(), temp(), temp());
6983 define(lir, ins);
6986 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue* ins) {
6987 auto* lir = new (alloc()) LMapObjectHasValue(
6988 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6989 temp(), temp(), temp(), temp());
6990 define(lir, ins);
6993 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall* ins) {
6994 auto* lir = new (alloc()) LMapObjectHasValueVMCall(
6995 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
6996 defineReturn(lir, ins);
6997 assignSafepoint(lir, ins);
7000 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt* ins) {
7001 auto* lir = new (alloc())
7002 LMapObjectGetNonBigInt(useRegister(ins->map()), useBox(ins->value()),
7003 useRegister(ins->hash()), temp(), temp());
7004 defineBox(lir, ins);
7007 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt* ins) {
7008 auto* lir = new (alloc()) LMapObjectGetBigInt(
7009 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7010 temp(), temp(), temp(), temp());
7011 defineBox(lir, ins);
7014 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue* ins) {
7015 auto* lir = new (alloc()) LMapObjectGetValue(
7016 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7017 temp(), temp(), temp(), temp());
7018 defineBox(lir, ins);
7021 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall* ins) {
7022 auto* lir = new (alloc()) LMapObjectGetValueVMCall(
7023 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
7024 defineReturn(lir, ins);
7025 assignSafepoint(lir, ins);
7028 void LIRGenerator::visitMapObjectSize(MMapObjectSize* ins) {
7029 auto* lir = new (alloc()) LMapObjectSize(useRegisterAtStart(ins->map()));
7030 define(lir, ins);
7033 void LIRGenerator::visitConstant(MConstant* ins) {
7034 if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
7035 emitAtUses(ins);
7036 return;
7039 switch (ins->type()) {
7040 case MIRType::Double:
7041 define(new (alloc()) LDouble(ins->toDouble()), ins);
7042 break;
7043 case MIRType::Float32:
7044 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7045 break;
7046 case MIRType::Boolean:
7047 define(new (alloc()) LInteger(ins->toBoolean()), ins);
7048 break;
7049 case MIRType::Int32:
7050 define(new (alloc()) LInteger(ins->toInt32()), ins);
7051 break;
7052 case MIRType::Int64:
7053 defineInt64(new (alloc()) LInteger64(ins->toInt64()), ins);
7054 break;
7055 case MIRType::IntPtr:
7056 #ifdef JS_64BIT
7057 defineInt64(new (alloc()) LInteger64(ins->toIntPtr()), ins);
7058 #else
7059 define(new (alloc()) LInteger(ins->toIntPtr()), ins);
7060 #endif
7061 break;
7062 case MIRType::String:
7063 define(new (alloc()) LPointer(ins->toString()), ins);
7064 break;
7065 case MIRType::Symbol:
7066 define(new (alloc()) LPointer(ins->toSymbol()), ins);
7067 break;
7068 case MIRType::BigInt:
7069 define(new (alloc()) LPointer(ins->toBigInt()), ins);
7070 break;
7071 case MIRType::Object:
7072 define(new (alloc()) LPointer(&ins->toObject()), ins);
7073 break;
7074 case MIRType::Shape:
7075 MOZ_ASSERT(ins->isEmittedAtUses());
7076 break;
7077 default:
7078 // Constants of special types (undefined, null) should never flow into
7079 // here directly. Operations blindly consuming them require a Box.
7080 MOZ_CRASH("unexpected constant type");
7084 void LIRGenerator::visitConstantProto(MConstantProto* ins) {
7085 JSObject* obj = &ins->protoObject()->toConstant()->toObject();
7086 define(new (alloc()) LPointer(obj), ins);
7089 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant* ins) {
7090 define(new (alloc()) LWasmNullConstant(), ins);
7093 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant* ins) {
7094 switch (ins->type()) {
7095 case MIRType::Double:
7096 define(new (alloc()) LDouble(ins->toDouble()), ins);
7097 break;
7098 case MIRType::Float32:
7099 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7100 break;
7101 #ifdef ENABLE_WASM_SIMD
7102 case MIRType::Simd128:
7103 define(new (alloc()) LSimd128(ins->toSimd128()), ins);
7104 break;
7105 #endif
7106 default:
7107 MOZ_CRASH("unexpected constant type");
7111 #ifdef JS_JITSPEW
7112 static void SpewResumePoint(MBasicBlock* block, MInstruction* ins,
7113 MResumePoint* resumePoint) {
7114 Fprinter& out = JitSpewPrinter();
7115 out.printf("Current resume point %p details:\n", (void*)resumePoint);
7116 out.printf(" frame count: %u\n", resumePoint->frameCount());
7118 if (ins) {
7119 out.printf(" taken after: ");
7120 ins->printName(out);
7121 } else {
7122 out.printf(" taken at block %u entry", block->id());
7124 out.printf("\n");
7126 out.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint->pc(),
7127 (void*)resumePoint->block()->info().script(),
7128 int(resumePoint->block()->info().script()->pcToOffset(
7129 resumePoint->pc())));
7131 for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
7132 MDefinition* in = resumePoint->getOperand(i);
7133 out.printf(" slot%u: ", (unsigned)i);
7134 in->printName(out);
7135 out.printf("\n");
7138 #endif
7140 void LIRGenerator::visitInstructionDispatch(MInstruction* ins) {
7141 #ifdef JS_CODEGEN_NONE
7142 // Don't compile the switch-statement below so that we don't have to define
7143 // the platform-specific visit* methods for the none-backend.
7144 MOZ_CRASH();
7145 #else
7146 switch (ins->op()) {
7147 # define MIR_OP(op) \
7148 case MDefinition::Opcode::op: \
7149 visit##op(ins->to##op()); \
7150 break;
7151 MIR_OPCODE_LIST(MIR_OP)
7152 # undef MIR_OP
7153 default:
7154 MOZ_CRASH("Invalid instruction");
7156 #endif
7159 void LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins) {
7160 static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins);
7163 bool LIRGenerator::visitInstruction(MInstruction* ins) {
7164 MOZ_ASSERT(!errored());
7166 if (ins->isRecoveredOnBailout()) {
7167 MOZ_ASSERT(!JitOptions.disableRecoverIns);
7168 return true;
7171 if (!gen->ensureBallast()) {
7172 return false;
7174 visitInstructionDispatch(ins);
7176 if (ins->resumePoint()) {
7177 updateResumeState(ins);
7180 #ifdef DEBUG
7181 ins->setInWorklistUnchecked();
7182 #endif
7184 // If no safepoint was created, there's no need for an OSI point.
7185 if (LOsiPoint* osiPoint = popOsiPoint()) {
7186 add(osiPoint);
7189 return !errored();
7192 bool LIRGenerator::definePhis() {
7193 size_t lirIndex = 0;
7194 MBasicBlock* block = current->mir();
7195 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
7196 if (phi->type() == MIRType::Value) {
7197 defineUntypedPhi(*phi, lirIndex);
7198 lirIndex += BOX_PIECES;
7199 } else if (phi->type() == MIRType::Int64) {
7200 defineInt64Phi(*phi, lirIndex);
7201 lirIndex += INT64_PIECES;
7202 } else {
7203 defineTypedPhi(*phi, lirIndex);
7204 lirIndex += 1;
7207 return !errored();
7210 void LIRGenerator::updateResumeState(MInstruction* ins) {
7211 lastResumePoint_ = ins->resumePoint();
7212 #ifdef JS_JITSPEW
7213 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7214 SpewResumePoint(nullptr, ins, lastResumePoint_);
7216 #endif
7219 void LIRGenerator::updateResumeState(MBasicBlock* block) {
7220 // Note: RangeAnalysis can flag blocks as unreachable, but they are only
7221 // removed iff GVN (including UCE) is enabled.
7222 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(),
7223 block->entryResumePoint());
7224 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7225 lastResumePoint_ = block->entryResumePoint();
7226 #ifdef JS_JITSPEW
7227 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7228 SpewResumePoint(block, nullptr, lastResumePoint_);
7230 #endif
7233 bool LIRGenerator::visitBlock(MBasicBlock* block) {
7234 current = block->lir();
7235 updateResumeState(block);
7237 if (!definePhis()) {
7238 return false;
7241 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7242 for (MInstructionIterator iter = block->begin(); *iter != block->lastIns();
7243 iter++) {
7244 if (!visitInstruction(*iter)) {
7245 return false;
7249 if (block->successorWithPhis()) {
7250 // If we have a successor with phis, lower the phi input now that we
7251 // are approaching the join point.
7252 MBasicBlock* successor = block->successorWithPhis();
7253 uint32_t position = block->positionInPhiSuccessor();
7254 size_t lirIndex = 0;
7255 for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd();
7256 phi++) {
7257 if (!gen->ensureBallast()) {
7258 return false;
7261 MDefinition* opd = phi->getOperand(position);
7262 ensureDefined(opd);
7264 MOZ_ASSERT(opd->type() == phi->type());
7266 if (phi->type() == MIRType::Value) {
7267 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
7268 lirIndex += BOX_PIECES;
7269 } else if (phi->type() == MIRType::Int64) {
7270 lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex);
7271 lirIndex += INT64_PIECES;
7272 } else {
7273 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
7274 lirIndex += 1;
7279 // Now emit the last instruction, which is some form of branch.
7280 if (!visitInstruction(block->lastIns())) {
7281 return false;
7284 return true;
7287 void LIRGenerator::visitNaNToZero(MNaNToZero* ins) {
7288 MDefinition* input = ins->input();
7290 if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) {
7291 redefine(ins, input);
7292 return;
7294 LNaNToZero* lir =
7295 new (alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble());
7296 defineReuseInput(lir, ins, 0);
7299 bool LIRGenerator::generate() {
7300 // Create all blocks and prep all phis beforehand.
7301 for (ReversePostorderIterator block(graph.rpoBegin());
7302 block != graph.rpoEnd(); block++) {
7303 if (gen->shouldCancel("Lowering (preparation loop)")) {
7304 return false;
7307 if (!lirGraph_.initBlock(*block)) {
7308 return false;
7312 for (ReversePostorderIterator block(graph.rpoBegin());
7313 block != graph.rpoEnd(); block++) {
7314 if (gen->shouldCancel("Lowering (main loop)")) {
7315 return false;
7318 if (!visitBlock(*block)) {
7319 return false;
7323 lirGraph_.setArgumentSlotCount(maxargslots_);
7324 return true;
7327 void LIRGenerator::visitPhi(MPhi* phi) {
7328 // Phi nodes are not lowered because they are only meaningful for the register
7329 // allocator.
7330 MOZ_CRASH("Unexpected Phi node during Lowering.");
7333 void LIRGenerator::visitBeta(MBeta* beta) {
7334 // Beta nodes are supposed to be removed before because they are
7335 // only used to carry the range information for Range analysis
7336 MOZ_CRASH("Unexpected Beta node during Lowering.");
7339 void LIRGenerator::visitObjectState(MObjectState* objState) {
7340 // ObjectState nodes are always recovered on bailouts
7341 MOZ_CRASH("Unexpected ObjectState node during Lowering.");
7344 void LIRGenerator::visitArrayState(MArrayState* objState) {
7345 // ArrayState nodes are always recovered on bailouts
7346 MOZ_CRASH("Unexpected ArrayState node during Lowering.");
7349 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall* ins) {
7350 // The instruction needs a temp register:
7351 // - that's not the FramePointer, since wasm is going to use it in the
7352 // function.
7353 // - that's not aliasing an input register.
7354 LDefinition scratch = tempFixed(ABINonArgReg0);
7356 // Note that since this is a LIR call instruction, regalloc will prevent
7357 // the use*AtStart below from reusing any of the temporaries.
7359 LInstruction* lir;
7360 if (ins->type() == MIRType::Value) {
7361 lir = allocateVariadic<LIonToWasmCallV>(ins->numOperands(), scratch);
7362 } else if (ins->type() == MIRType::Int64) {
7363 lir = allocateVariadic<LIonToWasmCallI64>(ins->numOperands(), scratch);
7364 } else {
7365 lir = allocateVariadic<LIonToWasmCall>(ins->numOperands(), scratch);
7367 if (!lir) {
7368 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitIonToWasmCall");
7369 return;
7372 ABIArgGenerator abi;
7373 for (unsigned i = 0; i < ins->numOperands(); i++) {
7374 MDefinition* argDef = ins->getOperand(i);
7375 ABIArg arg = abi.next(ToMIRType(argDef->type()));
7376 switch (arg.kind()) {
7377 case ABIArg::GPR:
7378 case ABIArg::FPU:
7379 lir->setOperand(i, useFixedAtStart(argDef, arg.reg()));
7380 break;
7381 case ABIArg::Stack:
7382 lir->setOperand(i, useAtStart(argDef));
7383 break;
7384 #ifdef JS_CODEGEN_REGISTER_PAIR
7385 case ABIArg::GPR_PAIR:
7386 MOZ_CRASH(
7387 "no way to pass i64, and wasm uses hardfp for function calls");
7388 #endif
7389 case ABIArg::Uninitialized:
7390 MOZ_CRASH("Uninitialized ABIArg kind");
7394 defineReturn(lir, ins);
7395 assignSafepoint(lir, ins);
7398 void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
7399 MDefinition* condExpr = ins->condExpr();
7401 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid
7402 // generating a boolean that we then have to test again.
7403 if (condExpr->isCompare() && condExpr->isEmittedAtUses()) {
7404 MCompare* comp = condExpr->toCompare();
7405 MCompare::CompareType compTy = comp->compareType();
7406 if (canSpecializeWasmCompareAndSelect(compTy, ins->type())) {
7407 JSOp jsop = comp->jsop();
7408 // We don't currently generate any other JSOPs for the comparison, and if
7409 // that changes, we want to know about it. Hence this assertion.
7410 MOZ_ASSERT(jsop == JSOp::Eq || jsop == JSOp::Ne || jsop == JSOp::Lt ||
7411 jsop == JSOp::Gt || jsop == JSOp::Le || jsop == JSOp::Ge);
7412 MDefinition* lhs = comp->lhs();
7413 MDefinition* rhs = comp->rhs();
7414 jsop = ReorderComparison(jsop, &lhs, &rhs);
7415 lowerWasmCompareAndSelect(ins, lhs, rhs, compTy, jsop);
7416 return;
7419 // Fall through to code that generates a boolean and selects on that.
7421 if (ins->type() == MIRType::Int64) {
7422 lowerWasmSelectI64(ins);
7423 return;
7426 lowerWasmSelectI(ins);
7429 void LIRGenerator::visitWasmFence(MWasmFence* ins) {
7430 add(new (alloc()) LWasmFence, ins);
7433 void LIRGenerator::visitWasmLoadField(MWasmLoadField* ins) {
7434 uint32_t offs = ins->offset();
7435 LAllocation obj = useRegister(ins->obj());
7436 MWideningOp wideningOp = ins->wideningOp();
7437 if (ins->type() == MIRType::Int64) {
7438 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7439 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7440 ins);
7441 } else {
7442 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7443 ins->maybeTrap()),
7444 ins);
7448 void LIRGenerator::visitWasmLoadFieldKA(MWasmLoadFieldKA* ins) {
7449 uint32_t offs = ins->offset();
7450 LAllocation obj = useRegister(ins->obj());
7451 MWideningOp wideningOp = ins->wideningOp();
7452 if (ins->type() == MIRType::Int64) {
7453 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7454 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7455 ins);
7456 } else {
7457 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7458 ins->maybeTrap()),
7459 ins);
7461 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7464 void LIRGenerator::visitWasmStoreFieldKA(MWasmStoreFieldKA* ins) {
7465 MDefinition* value = ins->value();
7466 uint32_t offs = ins->offset();
7467 MNarrowingOp narrowingOp = ins->narrowingOp();
7468 LAllocation obj = useRegister(ins->obj());
7469 LInstruction* lir;
7470 if (value->type() == MIRType::Int64) {
7471 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None);
7472 lir = new (alloc())
7473 LWasmStoreSlotI64(useInt64Register(value), obj, offs, ins->maybeTrap());
7474 } else {
7475 lir = new (alloc())
7476 LWasmStoreSlot(useRegister(value), obj, offs, value->type(),
7477 narrowingOp, ins->maybeTrap());
7479 add(lir, ins);
7480 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7483 void LIRGenerator::visitWasmStoreFieldRefKA(MWasmStoreFieldRefKA* ins) {
7484 LAllocation instance = useRegister(ins->instance());
7485 LAllocation obj = useFixed(ins->obj(), PreBarrierReg);
7486 LAllocation value = useRegister(ins->value());
7487 uint32_t offset = ins->offset();
7488 add(new (alloc()) LWasmStoreRef(instance, obj, value, temp(), offset,
7489 ins->maybeTrap(), ins->preBarrierKind()),
7490 ins);
7491 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7494 void LIRGenerator::visitWasmRefIsSubtypeOfAbstract(
7495 MWasmRefIsSubtypeOfAbstract* ins) {
7496 if (CanEmitAtUseForSingleTest(ins)) {
7497 emitAtUses(ins);
7498 return;
7501 LAllocation ref = useRegister(ins->ref());
7502 LDefinition scratch1 = LDefinition();
7503 if (ins->destType().isAnyHierarchy()) {
7504 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7505 // We know we do not need scratch2 and superSTV because we know
7506 // this is not a concrete type.
7507 MOZ_ASSERT(!MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7508 ins->destType()));
7509 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7510 ins->destType()));
7512 scratch1 = MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7513 ins->destType())
7514 ? temp()
7515 : LDefinition();
7516 } else if (ins->destType().isFuncHierarchy()) {
7517 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7518 // We know we do not need any supertype vectors or scratch registers because
7519 // this is not a concrete cast.
7520 MOZ_ASSERT(
7521 !MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7522 ins->destType()));
7523 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7524 ins->destType()));
7525 } else if (ins->destType().isExternHierarchy()) {
7526 // no scratch registers needed for casts in the extern hierarchy
7527 } else {
7528 MOZ_CRASH("unknown type hierarchy for abstract cast");
7531 define(new (alloc()) LWasmRefIsSubtypeOfAbstract(ref, scratch1), ins);
7534 void LIRGenerator::visitWasmRefIsSubtypeOfConcrete(
7535 MWasmRefIsSubtypeOfConcrete* ins) {
7536 if (CanEmitAtUseForSingleTest(ins)) {
7537 emitAtUses(ins);
7538 return;
7541 // This gets a bit wild because it needs to handle concrete casts in all
7542 // hierarchies. Supertype vectors are always required (that's what concrete
7543 // means) but the scratch registers can vary.
7545 LAllocation ref = useRegister(ins->ref());
7546 LAllocation superSTV = useRegister(ins->superSTV());
7547 LDefinition scratch1 = LDefinition();
7548 LDefinition scratch2 = LDefinition();
7549 if (ins->destType().isAnyHierarchy()) {
7550 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7551 // We know we need scratch1 because we know this is a concrete type.
7552 MOZ_ASSERT(MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7553 ins->destType()));
7554 MOZ_ASSERT(MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7555 ins->destType()));
7556 scratch1 = temp();
7557 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7558 ins->destType())
7559 ? temp()
7560 : LDefinition();
7561 } else if (ins->destType().isFuncHierarchy()) {
7562 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7563 // We know we need scratch1 because we know this is a concrete type.
7564 MOZ_ASSERT(
7565 MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7566 ins->destType()));
7567 scratch1 = temp();
7568 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7569 ins->destType())
7570 ? temp()
7571 : LDefinition();
7572 } else if (ins->destType().isExternHierarchy()) {
7573 MOZ_CRASH("concrete casts are impossible in the extern hierarchy");
7574 } else {
7575 MOZ_CRASH("unknown type hierarchy for concrete cast");
7578 define(new (alloc())
7579 LWasmRefIsSubtypeOfConcrete(ref, superSTV, scratch1, scratch2),
7580 ins);
7583 void LIRGenerator::visitWasmNewStructObject(MWasmNewStructObject* ins) {
7584 LWasmNewStructObject* lir = new (alloc())
7585 LWasmNewStructObject(useFixed(ins->instance(), InstanceReg),
7586 useRegister(ins->typeDefData()), temp(), temp());
7587 define(lir, ins);
7588 assignWasmSafepoint(lir);
7591 #ifdef FUZZING_JS_FUZZILLI
7592 void LIRGenerator::visitFuzzilliHash(MFuzzilliHash* ins) {
7593 MDefinition* value = ins->getOperand(0);
7595 if (value->type() == MIRType::Undefined || value->type() == MIRType::Null) {
7596 define(new (alloc()) LFuzzilliHashT(LAllocation(), temp(), tempDouble()),
7597 ins);
7598 } else if (value->type() == MIRType::Int32 ||
7599 value->type() == MIRType::Double ||
7600 value->type() == MIRType::Float32 ||
7601 value->type() == MIRType::Boolean ||
7602 value->type() == MIRType::BigInt) {
7603 define(new (alloc())
7604 LFuzzilliHashT(useRegister(value), temp(), tempDouble()),
7605 ins);
7606 } else if (value->type() == MIRType::Object) {
7607 LFuzzilliHashT* lir =
7608 new (alloc()) LFuzzilliHashT(useRegister(value), temp(), tempDouble());
7609 define(lir, ins);
7610 assignSafepoint(lir, ins);
7611 } else if (value->type() == MIRType::Value) {
7612 LFuzzilliHashV* lir =
7613 new (alloc()) LFuzzilliHashV(useBox(value), temp(), tempDouble());
7614 define(lir, ins);
7615 assignSafepoint(lir, ins);
7616 } else {
7617 define(new (alloc()) LInteger(0), ins);
7621 void LIRGenerator::visitFuzzilliHashStore(MFuzzilliHashStore* ins) {
7622 MDefinition* value = ins->getOperand(0);
7623 MOZ_ASSERT(value->type() == MIRType::Int32);
7624 add(new (alloc()) LFuzzilliHashStore(useRegister(value), temp(), temp()),
7625 ins);
7627 #endif
7629 static_assert(!std::is_polymorphic_v<LIRGenerator>,
7630 "LIRGenerator should not have any virtual methods");
7632 #ifdef JS_CODEGEN_NONE
7633 void LIRGenerator::visitReturnImpl(MDefinition*, bool) { MOZ_CRASH(); }
7634 #endif