1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 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/. */ 6 7 #include "jit/mips32/Lowering-mips32.h" 8 9 #include "jit/mips32/Assembler-mips32.h" 10 11 #include "jit/MIR.h" 12 13 #include "jit/shared/Lowering-shared-inl.h" 14 15 using namespace js; 16 using namespace js::jit; 17 18 LBoxAllocation 19 LIRGeneratorMIPS::useBoxFixed(MDefinition* mir, Register reg1, Register reg2, bool useAtStart) 20 { 21 MOZ_ASSERT(mir->type() == MIRType::Value); 22 MOZ_ASSERT(reg1 != reg2); 23 24 ensureDefined(mir); 25 return LBoxAllocation(LUse(reg1, mir->virtualRegister(), useAtStart), 26 LUse(reg2, VirtualRegisterOfPayload(mir), useAtStart)); 27 } 28 29 void 30 LIRGeneratorMIPS::visitBox(MBox* box) 31 { 32 MDefinition* inner = box->getOperand(0); 33 34 // If the box wrapped a double, it needs a new register. 35 if (IsFloatingPointType(inner->type())) { 36 defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), 37 tempCopy(inner, 0), inner->type()), box); 38 return; 39 } 40 41 if (box->canEmitAtUses()) { 42 emitAtUses(box); 43 return; 44 } 45 46 if (inner->isConstant()) { 47 defineBox(new(alloc()) LValue(inner->toConstant()->toJSValue()), box); 48 return; 49 } 50 51 LBox* lir = new(alloc()) LBox(use(inner), inner->type()); 52 53 // Otherwise, we should not define a new register for the payload portion 54 // of the output, so bypass defineBox(). 55 uint32_t vreg = getVirtualRegister(); 56 57 // Note that because we're using BogusTemp(), we do not change the type of 58 // the definition. We also do not define the first output as "TYPE", 59 // because it has no corresponding payload at (vreg + 1). Also note that 60 // although we copy the input's original type for the payload half of the 61 // definition, this is only for clarity. BogusTemp() definitions are 62 // ignored. 63 lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL)); 64 lir->setDef(1, LDefinition::BogusTemp()); 65 box->setVirtualRegister(vreg); 66 add(lir); 67 } 68 69 void 70 LIRGeneratorMIPS::visitUnbox(MUnbox* unbox) 71 { 72 MDefinition* inner = unbox->getOperand(0); 73 74 if (inner->type() == MIRType::ObjectOrNull) { 75 LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner)); 76 if (unbox->fallible()) 77 assignSnapshot(lir, unbox->bailoutKind()); 78 defineReuseInput(lir, unbox, 0); 79 return; 80 } 81 82 // An unbox on mips reads in a type tag (either in memory or a register) and 83 // a payload. Unlike most instructions consuming a box, we ask for the type 84 // second, so that the result can re-use the first input. 85 MOZ_ASSERT(inner->type() == MIRType::Value); 86 87 ensureDefined(inner); 88 89 if (IsFloatingPointType(unbox->type())) { 90 LUnboxFloatingPoint* lir = new(alloc()) LUnboxFloatingPoint(useBox(inner), unbox->type()); 91 if (unbox->fallible()) 92 assignSnapshot(lir, unbox->bailoutKind()); 93 define(lir, unbox); 94 return; 95 } 96 97 // Swap the order we use the box pieces so we can re-use the payload 98 // register. 99 LUnbox* lir = new(alloc()) LUnbox; 100 lir->setOperand(0, usePayloadInRegisterAtStart(inner)); 101 lir->setOperand(1, useType(inner, LUse::REGISTER)); 102 103 if (unbox->fallible()) 104 assignSnapshot(lir, unbox->bailoutKind()); 105 106 // Types and payloads form two separate intervals. If the type becomes dead 107 // before the payload, it could be used as a Value without the type being 108 // recoverable. Unbox's purpose is to eagerly kill the definition of a type 109 // tag, so keeping both alive (for the purpose of gcmaps) is unappealing. 110 // Instead, we create a new virtual register. 111 defineReuseInput(lir, unbox, 0); 112 } 113 114 void 115 LIRGeneratorMIPS::visitReturn(MReturn* ret) 116 { 117 MDefinition* opd = ret->getOperand(0); 118 MOZ_ASSERT(opd->type() == MIRType::Value); 119 120 LReturn* ins = new(alloc()) LReturn; 121 ins->setOperand(0, LUse(JSReturnReg_Type)); 122 ins->setOperand(1, LUse(JSReturnReg_Data)); 123 fillBoxUses(ins, 0, opd); 124 add(ins); 125 } 126 127 void 128 LIRGeneratorMIPS::defineUntypedPhi(MPhi* phi, size_t lirIndex) 129 { 130 LPhi* type = current->getPhi(lirIndex + VREG_TYPE_OFFSET); 131 LPhi* payload = current->getPhi(lirIndex + VREG_DATA_OFFSET); 132 133 uint32_t typeVreg = getVirtualRegister(); 134 phi->setVirtualRegister(typeVreg); 135 136 uint32_t payloadVreg = getVirtualRegister(); 137 MOZ_ASSERT(typeVreg + 1 == payloadVreg); 138 139 type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE)); 140 payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD)); 141 annotate(type); 142 annotate(payload); 143 } 144 145 void 146 LIRGeneratorMIPS::lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, 147 LBlock* block, size_t lirIndex) 148 { 149 MDefinition* operand = phi->getOperand(inputPosition); 150 LPhi* type = block->getPhi(lirIndex + VREG_TYPE_OFFSET); 151 LPhi* payload = block->getPhi(lirIndex + VREG_DATA_OFFSET); 152 type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET, 153 LUse::ANY)); 154 payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY)); 155 } 156 157 void 158 LIRGeneratorMIPS::defineInt64Phi(MPhi* phi, size_t lirIndex) 159 { 160 LPhi* low = current->getPhi(lirIndex + INT64LOW_INDEX); 161 LPhi* high = current->getPhi(lirIndex + INT64HIGH_INDEX); 162 163 uint32_t lowVreg = getVirtualRegister(); 164 165 phi->setVirtualRegister(lowVreg); 166 167 uint32_t highVreg = getVirtualRegister(); 168 MOZ_ASSERT(lowVreg + INT64HIGH_INDEX == highVreg + INT64LOW_INDEX); 169 170 low->setDef(0, LDefinition(lowVreg, LDefinition::INT32)); 171 high->setDef(0, LDefinition(highVreg, LDefinition::INT32)); 172 annotate(high); 173 annotate(low); 174 } 175 176 void 177 LIRGeneratorMIPS::lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, 178 LBlock* block, size_t lirIndex) 179 { 180 MDefinition* operand = phi->getOperand(inputPosition); 181 LPhi* low = block->getPhi(lirIndex + INT64LOW_INDEX); 182 LPhi* high = block->getPhi(lirIndex + INT64HIGH_INDEX); 183 low->setOperand(inputPosition, LUse(operand->virtualRegister() + INT64LOW_INDEX, LUse::ANY)); 184 high->setOperand(inputPosition, LUse(operand->virtualRegister() + INT64HIGH_INDEX, LUse::ANY)); 185 } 186 187 void 188 LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32* ins) 189 { 190 MDefinition* opd = ins->input(); 191 MOZ_ASSERT(opd->type() == MIRType::Double); 192 193 define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); 194 } 195 196 void 197 LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32* ins) 198 { 199 MDefinition* opd = ins->input(); 200 MOZ_ASSERT(opd->type() == MIRType::Float32); 201 202 define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); 203 } 204 205 void 206 LIRGeneratorMIPS::lowerDivI64(MDiv* div) 207 { 208 if (div->isUnsigned()) { 209 lowerUDivI64(div); 210 return; 211 } 212 213 LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(div->lhs()), 214 useInt64RegisterAtStart(div->rhs())); 215 216 defineReturn(lir, div); 217 } 218 219 void 220 LIRGeneratorMIPS::lowerModI64(MMod* mod) 221 { 222 if (mod->isUnsigned()) { 223 lowerUModI64(mod); 224 return; 225 } 226 227 LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(mod->lhs()), 228 useInt64RegisterAtStart(mod->rhs())); 229 230 defineReturn(lir, mod); 231 } 232 233 void 234 LIRGeneratorMIPS::lowerUDivI64(MDiv* div) 235 { 236 LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(div->lhs()), 237 useInt64RegisterAtStart(div->rhs())); 238 defineReturn(lir, div); 239 } 240 241 void 242 LIRGeneratorMIPS::lowerUModI64(MMod* mod) 243 { 244 LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(mod->lhs()), 245 useInt64RegisterAtStart(mod->rhs())); 246 defineReturn(lir, mod); 247 } 248 249 void 250 LIRGeneratorMIPS::visitRandom(MRandom* ins) 251 { 252 LRandom *lir = new(alloc()) LRandom(temp(), 253 temp(), 254 temp(), 255 temp(), 256 temp()); 257 defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); 258 } 259