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/mips32/Lowering-mips32.h"
9 #include "jit/Lowering.h"
10 #include "jit/mips32/Assembler-mips32.h"
13 #include "jit/shared/Lowering-shared-inl.h"
16 using namespace js::jit
;
18 LBoxAllocation
LIRGeneratorMIPS::useBoxFixed(MDefinition
* mir
, Register reg1
,
19 Register reg2
, bool useAtStart
) {
20 MOZ_ASSERT(mir
->type() == MIRType::Value
);
21 MOZ_ASSERT(reg1
!= reg2
);
24 return LBoxAllocation(LUse(reg1
, mir
->virtualRegister(), useAtStart
),
25 LUse(reg2
, VirtualRegisterOfPayload(mir
), useAtStart
));
28 void LIRGenerator::visitBox(MBox
* box
) {
29 MDefinition
* inner
= box
->getOperand(0);
31 // If the box wrapped a double, it needs a new register.
32 if (IsFloatingPointType(inner
->type())) {
33 defineBox(new (alloc()) LBoxFloatingPoint(
34 useRegisterAtStart(inner
), tempCopy(inner
, 0), inner
->type()),
39 if (box
->canEmitAtUses()) {
44 if (inner
->isConstant()) {
45 defineBox(new (alloc()) LValue(inner
->toConstant()->toJSValue()), box
);
49 LBox
* lir
= new (alloc()) LBox(use(inner
), inner
->type());
51 // Otherwise, we should not define a new register for the payload portion
52 // of the output, so bypass defineBox().
53 uint32_t vreg
= getVirtualRegister();
55 // Note that because we're using BogusTemp(), we do not change the type of
56 // the definition. We also do not define the first output as "TYPE",
57 // because it has no corresponding payload at (vreg + 1). Also note that
58 // although we copy the input's original type for the payload half of the
59 // definition, this is only for clarity. BogusTemp() definitions are
61 lir
->setDef(0, LDefinition(vreg
, LDefinition::GENERAL
));
62 lir
->setDef(1, LDefinition::BogusTemp());
63 box
->setVirtualRegister(vreg
);
67 void LIRGenerator::visitUnbox(MUnbox
* unbox
) {
68 MDefinition
* inner
= unbox
->getOperand(0);
70 if (inner
->type() == MIRType::ObjectOrNull
) {
71 LUnboxObjectOrNull
* lir
=
72 new (alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner
));
73 if (unbox
->fallible()) {
74 assignSnapshot(lir
, unbox
->bailoutKind());
76 defineReuseInput(lir
, unbox
, 0);
80 // An unbox on mips reads in a type tag (either in memory or a register) and
81 // a payload. Unlike most instructions consuming a box, we ask for the type
82 // second, so that the result can re-use the first input.
83 MOZ_ASSERT(inner
->type() == MIRType::Value
);
87 if (IsFloatingPointType(unbox
->type())) {
88 LUnboxFloatingPoint
* lir
=
89 new (alloc()) LUnboxFloatingPoint(useBox(inner
), unbox
->type());
90 if (unbox
->fallible()) {
91 assignSnapshot(lir
, unbox
->bailoutKind());
97 // Swap the order we use the box pieces so we can re-use the payload
99 LUnbox
* lir
= new (alloc()) LUnbox
;
100 lir
->setOperand(0, usePayloadInRegisterAtStart(inner
));
101 lir
->setOperand(1, useType(inner
, LUse::REGISTER
));
103 if (unbox
->fallible()) {
104 assignSnapshot(lir
, unbox
->bailoutKind());
107 // Types and payloads form two separate intervals. If the type becomes dead
108 // before the payload, it could be used as a Value without the type being
109 // recoverable. Unbox's purpose is to eagerly kill the definition of a type
110 // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
111 // Instead, we create a new virtual register.
112 defineReuseInput(lir
, unbox
, 0);
115 void LIRGenerator::visitReturn(MReturn
* ret
) {
116 MDefinition
* opd
= ret
->getOperand(0);
117 MOZ_ASSERT(opd
->type() == MIRType::Value
);
119 LReturn
* ins
= new (alloc()) LReturn
;
120 ins
->setOperand(0, LUse(JSReturnReg_Type
));
121 ins
->setOperand(1, LUse(JSReturnReg_Data
));
122 fillBoxUses(ins
, 0, opd
);
126 void LIRGeneratorMIPS::lowerUntypedPhiInput(MPhi
* phi
, uint32_t inputPosition
,
127 LBlock
* block
, size_t lirIndex
) {
128 MDefinition
* operand
= phi
->getOperand(inputPosition
);
129 LPhi
* type
= block
->getPhi(lirIndex
+ VREG_TYPE_OFFSET
);
130 LPhi
* payload
= block
->getPhi(lirIndex
+ VREG_DATA_OFFSET
);
133 LUse(operand
->virtualRegister() + VREG_TYPE_OFFSET
, LUse::ANY
));
134 payload
->setOperand(inputPosition
,
135 LUse(VirtualRegisterOfPayload(operand
), LUse::ANY
));
138 void LIRGeneratorMIPS::defineInt64Phi(MPhi
* phi
, size_t lirIndex
) {
139 LPhi
* low
= current
->getPhi(lirIndex
+ INT64LOW_INDEX
);
140 LPhi
* high
= current
->getPhi(lirIndex
+ INT64HIGH_INDEX
);
142 uint32_t lowVreg
= getVirtualRegister();
144 phi
->setVirtualRegister(lowVreg
);
146 uint32_t highVreg
= getVirtualRegister();
147 MOZ_ASSERT(lowVreg
+ INT64HIGH_INDEX
== highVreg
+ INT64LOW_INDEX
);
149 low
->setDef(0, LDefinition(lowVreg
, LDefinition::INT32
));
150 high
->setDef(0, LDefinition(highVreg
, LDefinition::INT32
));
155 void LIRGeneratorMIPS::lowerInt64PhiInput(MPhi
* phi
, uint32_t inputPosition
,
156 LBlock
* block
, size_t lirIndex
) {
157 MDefinition
* operand
= phi
->getOperand(inputPosition
);
158 LPhi
* low
= block
->getPhi(lirIndex
+ INT64LOW_INDEX
);
159 LPhi
* high
= block
->getPhi(lirIndex
+ INT64HIGH_INDEX
);
160 low
->setOperand(inputPosition
,
161 LUse(operand
->virtualRegister() + INT64LOW_INDEX
, LUse::ANY
));
164 LUse(operand
->virtualRegister() + INT64HIGH_INDEX
, LUse::ANY
));
167 void LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32
* ins
) {
168 MDefinition
* opd
= ins
->input();
169 MOZ_ASSERT(opd
->type() == MIRType::Double
);
172 LTruncateDToInt32(useRegister(opd
), LDefinition::BogusTemp()),
176 void LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32
* ins
) {
177 MDefinition
* opd
= ins
->input();
178 MOZ_ASSERT(opd
->type() == MIRType::Float32
);
181 LTruncateFToInt32(useRegister(opd
), LDefinition::BogusTemp()),
185 void LIRGeneratorMIPS::lowerDivI64(MDiv
* div
) {
186 if (div
->isUnsigned()) {
191 LDivOrModI64
* lir
= new (alloc()) LDivOrModI64(
192 useInt64RegisterAtStart(div
->lhs()), useInt64RegisterAtStart(div
->rhs()));
194 defineReturn(lir
, div
);
197 void LIRGeneratorMIPS::lowerWasmBuiltinDivI64(MWasmBuiltinDivI64
* div
) {
198 MOZ_CRASH("We don't use runtime div for this architecture");
201 void LIRGeneratorMIPS::lowerModI64(MMod
* mod
) {
202 if (mod
->isUnsigned()) {
207 LDivOrModI64
* lir
= new (alloc()) LDivOrModI64(
208 useInt64RegisterAtStart(mod
->lhs()), useInt64RegisterAtStart(mod
->rhs()));
210 defineReturn(lir
, mod
);
213 void LIRGeneratorMIPS::lowerWasmBuiltinModI64(MWasmBuiltinModI64
* mod
) {
214 MOZ_CRASH("We don't use runtime mod for this architecture");
217 void LIRGeneratorMIPS::lowerUDivI64(MDiv
* div
) {
218 LUDivOrModI64
* lir
= new (alloc()) LUDivOrModI64(
219 useInt64RegisterAtStart(div
->lhs()), useInt64RegisterAtStart(div
->rhs()));
220 defineReturn(lir
, div
);
223 void LIRGeneratorMIPS::lowerUModI64(MMod
* mod
) {
224 LUDivOrModI64
* lir
= new (alloc()) LUDivOrModI64(
225 useInt64RegisterAtStart(mod
->lhs()), useInt64RegisterAtStart(mod
->rhs()));
226 defineReturn(lir
, mod
);
229 void LIRGenerator::visitWasmTruncateToInt64(MWasmTruncateToInt64
* ins
) {
230 MDefinition
* opd
= ins
->input();
231 MOZ_ASSERT(opd
->type() == MIRType::Double
|| opd
->type() == MIRType::Float32
);
233 defineReturn(new (alloc()) LWasmTruncateToInt64(useRegisterAtStart(opd
)),
237 void LIRGenerator::visitInt64ToFloatingPoint(MInt64ToFloatingPoint
* ins
) {
238 MDefinition
* opd
= ins
->input();
239 MOZ_ASSERT(opd
->type() == MIRType::Int64
);
240 MOZ_ASSERT(IsFloatingPointType(ins
->type()));
243 new (alloc()) LInt64ToFloatingPoint(useInt64RegisterAtStart(opd
)), ins
);