1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/x86/Lowering-x86.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,308 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/x86/Lowering-x86.h" 1.11 + 1.12 +#include "jit/MIR.h" 1.13 +#include "jit/x86/Assembler-x86.h" 1.14 + 1.15 +#include "jit/shared/Lowering-shared-inl.h" 1.16 + 1.17 +using namespace js; 1.18 +using namespace js::jit; 1.19 + 1.20 +LDefinition 1.21 +LIRGeneratorX86::tempForDispatchCache(MIRType outputType) 1.22 +{ 1.23 + // x86 doesn't have a scratch register and we need one for the 1.24 + // indirect jump for dispatch-style ICs. 1.25 + // 1.26 + // Note that currently we only install dispatch-style ICs for parallel 1.27 + // execution. If this assumption changes, please change it here. 1.28 + if (gen->info().executionMode() != ParallelExecution) 1.29 + return LDefinition::BogusTemp(); 1.30 + 1.31 + // If we don't have an output register, we need a temp. 1.32 + if (outputType == MIRType_None) 1.33 + return temp(); 1.34 + 1.35 + // If we have a double output register, we need a temp. 1.36 + if (outputType == MIRType_Double) 1.37 + return temp(); 1.38 + 1.39 + // Otherwise we have a non-double output register and we can reuse it. 1.40 + return LDefinition::BogusTemp(); 1.41 +} 1.42 + 1.43 +bool 1.44 +LIRGeneratorX86::useBox(LInstruction *lir, size_t n, MDefinition *mir, 1.45 + LUse::Policy policy, bool useAtStart) 1.46 +{ 1.47 + JS_ASSERT(mir->type() == MIRType_Value); 1.48 + 1.49 + if (!ensureDefined(mir)) 1.50 + return false; 1.51 + lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart)); 1.52 + lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart)); 1.53 + return true; 1.54 +} 1.55 + 1.56 +bool 1.57 +LIRGeneratorX86::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, 1.58 + Register reg2) 1.59 +{ 1.60 + JS_ASSERT(mir->type() == MIRType_Value); 1.61 + JS_ASSERT(reg1 != reg2); 1.62 + 1.63 + if (!ensureDefined(mir)) 1.64 + return false; 1.65 + lir->setOperand(n, LUse(reg1, mir->virtualRegister())); 1.66 + lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir))); 1.67 + return true; 1.68 +} 1.69 + 1.70 +LAllocation 1.71 +LIRGeneratorX86::useByteOpRegister(MDefinition *mir) 1.72 +{ 1.73 + return useFixed(mir, eax); 1.74 +} 1.75 + 1.76 +LAllocation 1.77 +LIRGeneratorX86::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir) 1.78 +{ 1.79 + return useFixed(mir, eax); 1.80 +} 1.81 + 1.82 +bool 1.83 +LIRGeneratorX86::visitBox(MBox *box) 1.84 +{ 1.85 + MDefinition *inner = box->getOperand(0); 1.86 + 1.87 + // If the box wrapped a double, it needs a new register. 1.88 + if (IsFloatingPointType(inner->type())) 1.89 + return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0), 1.90 + inner->type()), box); 1.91 + 1.92 + if (box->canEmitAtUses()) 1.93 + return emitAtUses(box); 1.94 + 1.95 + if (inner->isConstant()) 1.96 + return defineBox(new(alloc()) LValue(inner->toConstant()->value()), box); 1.97 + 1.98 + LBox *lir = new(alloc()) LBox(use(inner), inner->type()); 1.99 + 1.100 + // Otherwise, we should not define a new register for the payload portion 1.101 + // of the output, so bypass defineBox(). 1.102 + uint32_t vreg = getVirtualRegister(); 1.103 + if (vreg >= MAX_VIRTUAL_REGISTERS) 1.104 + return false; 1.105 + 1.106 + // Note that because we're using PASSTHROUGH, we do not change the type of 1.107 + // the definition. We also do not define the first output as "TYPE", 1.108 + // because it has no corresponding payload at (vreg + 1). Also note that 1.109 + // although we copy the input's original type for the payload half of the 1.110 + // definition, this is only for clarity. PASSTHROUGH definitions are 1.111 + // ignored. 1.112 + lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL)); 1.113 + lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()), 1.114 + LDefinition::PASSTHROUGH)); 1.115 + box->setVirtualRegister(vreg); 1.116 + return add(lir); 1.117 +} 1.118 + 1.119 +bool 1.120 +LIRGeneratorX86::visitUnbox(MUnbox *unbox) 1.121 +{ 1.122 + // An unbox on x86 reads in a type tag (either in memory or a register) and 1.123 + // a payload. Unlike most instructions conusming a box, we ask for the type 1.124 + // second, so that the result can re-use the first input. 1.125 + MDefinition *inner = unbox->getOperand(0); 1.126 + 1.127 + if (!ensureDefined(inner)) 1.128 + return false; 1.129 + 1.130 + if (IsFloatingPointType(unbox->type())) { 1.131 + LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type()); 1.132 + if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind())) 1.133 + return false; 1.134 + if (!useBox(lir, LUnboxFloatingPoint::Input, inner)) 1.135 + return false; 1.136 + return define(lir, unbox); 1.137 + } 1.138 + 1.139 + // Swap the order we use the box pieces so we can re-use the payload register. 1.140 + LUnbox *lir = new(alloc()) LUnbox; 1.141 + lir->setOperand(0, usePayloadInRegisterAtStart(inner)); 1.142 + lir->setOperand(1, useType(inner, LUse::ANY)); 1.143 + 1.144 + if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind())) 1.145 + return false; 1.146 + 1.147 + // Note that PASSTHROUGH here is illegal, since types and payloads form two 1.148 + // separate intervals. If the type becomes dead before the payload, it 1.149 + // could be used as a Value without the type being recoverable. Unbox's 1.150 + // purpose is to eagerly kill the definition of a type tag, so keeping both 1.151 + // alive (for the purpose of gcmaps) is unappealing. Instead, we create a 1.152 + // new virtual register. 1.153 + return defineReuseInput(lir, unbox, 0); 1.154 +} 1.155 + 1.156 +bool 1.157 +LIRGeneratorX86::visitReturn(MReturn *ret) 1.158 +{ 1.159 + MDefinition *opd = ret->getOperand(0); 1.160 + JS_ASSERT(opd->type() == MIRType_Value); 1.161 + 1.162 + LReturn *ins = new(alloc()) LReturn; 1.163 + ins->setOperand(0, LUse(JSReturnReg_Type)); 1.164 + ins->setOperand(1, LUse(JSReturnReg_Data)); 1.165 + return fillBoxUses(ins, 0, opd) && add(ins); 1.166 +} 1.167 + 1.168 +bool 1.169 +LIRGeneratorX86::defineUntypedPhi(MPhi *phi, size_t lirIndex) 1.170 +{ 1.171 + LPhi *type = current->getPhi(lirIndex + VREG_TYPE_OFFSET); 1.172 + LPhi *payload = current->getPhi(lirIndex + VREG_DATA_OFFSET); 1.173 + 1.174 + uint32_t typeVreg = getVirtualRegister(); 1.175 + if (typeVreg >= MAX_VIRTUAL_REGISTERS) 1.176 + return false; 1.177 + 1.178 + phi->setVirtualRegister(typeVreg); 1.179 + 1.180 + uint32_t payloadVreg = getVirtualRegister(); 1.181 + if (payloadVreg >= MAX_VIRTUAL_REGISTERS) 1.182 + return false; 1.183 + JS_ASSERT(typeVreg + 1 == payloadVreg); 1.184 + 1.185 + type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE)); 1.186 + payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD)); 1.187 + annotate(type); 1.188 + annotate(payload); 1.189 + return true; 1.190 +} 1.191 + 1.192 +void 1.193 +LIRGeneratorX86::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex) 1.194 +{ 1.195 + MDefinition *operand = phi->getOperand(inputPosition); 1.196 + LPhi *type = block->getPhi(lirIndex + VREG_TYPE_OFFSET); 1.197 + LPhi *payload = block->getPhi(lirIndex + VREG_DATA_OFFSET); 1.198 + type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET, LUse::ANY)); 1.199 + payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY)); 1.200 +} 1.201 + 1.202 +bool 1.203 +LIRGeneratorX86::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins) 1.204 +{ 1.205 + JS_ASSERT(ins->input()->type() == MIRType_Int32); 1.206 + LAsmJSUInt32ToDouble *lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()), temp()); 1.207 + return define(lir, ins); 1.208 +} 1.209 + 1.210 +bool 1.211 +LIRGeneratorX86::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins) 1.212 +{ 1.213 + JS_ASSERT(ins->input()->type() == MIRType_Int32); 1.214 + LAsmJSUInt32ToFloat32 *lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()), temp()); 1.215 + return define(lir, ins); 1.216 +} 1.217 + 1.218 +bool 1.219 +LIRGeneratorX86::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins) 1.220 +{ 1.221 + MDefinition *ptr = ins->ptr(); 1.222 + LAllocation ptrAlloc; 1.223 + JS_ASSERT(ptr->type() == MIRType_Int32); 1.224 + 1.225 + // For the x86 it is best to keep the 'ptr' in a register if a bounds check is needed. 1.226 + if (ptr->isConstant() && ins->skipBoundsCheck()) { 1.227 + int32_t ptrValue = ptr->toConstant()->value().toInt32(); 1.228 + // A bounds check is only skipped for a positive index. 1.229 + JS_ASSERT(ptrValue >= 0); 1.230 + ptrAlloc = LAllocation(ptr->toConstant()->vp()); 1.231 + } else { 1.232 + ptrAlloc = useRegisterAtStart(ptr); 1.233 + } 1.234 + LAsmJSLoadHeap *lir = new(alloc()) LAsmJSLoadHeap(ptrAlloc); 1.235 + return define(lir, ins); 1.236 +} 1.237 + 1.238 +bool 1.239 +LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) 1.240 +{ 1.241 + MDefinition *ptr = ins->ptr(); 1.242 + LAsmJSStoreHeap *lir; 1.243 + JS_ASSERT(ptr->type() == MIRType_Int32); 1.244 + 1.245 + if (ptr->isConstant() && ins->skipBoundsCheck()) { 1.246 + int32_t ptrValue = ptr->toConstant()->value().toInt32(); 1.247 + JS_ASSERT(ptrValue >= 0); 1.248 + LAllocation ptrAlloc = LAllocation(ptr->toConstant()->vp()); 1.249 + switch (ins->viewType()) { 1.250 + case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8: 1.251 + // See comment below. 1.252 + lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useFixed(ins->value(), eax)); 1.253 + break; 1.254 + case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16: 1.255 + case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32: 1.256 + case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64: 1.257 + // See comment below. 1.258 + lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())); 1.259 + break; 1.260 + default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); 1.261 + } 1.262 + return add(lir, ins); 1.263 + } 1.264 + 1.265 + switch (ins->viewType()) { 1.266 + case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8: 1.267 + // See comment for LIRGeneratorX86::useByteOpRegister. 1.268 + lir = new(alloc()) LAsmJSStoreHeap(useRegister(ins->ptr()), useFixed(ins->value(), eax)); 1.269 + break; 1.270 + case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16: 1.271 + case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32: 1.272 + case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64: 1.273 + // For now, don't allow constant values. The immediate operand 1.274 + // affects instruction layout which affects patching. 1.275 + lir = new(alloc()) LAsmJSStoreHeap(useRegisterAtStart(ptr), useRegisterAtStart(ins->value())); 1.276 + break; 1.277 + default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); 1.278 + } 1.279 + 1.280 + return add(lir, ins); 1.281 +} 1.282 + 1.283 +bool 1.284 +LIRGeneratorX86::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins) 1.285 +{ 1.286 + // The code generated for StoreTypedArrayElementStatic is identical to that 1.287 + // for AsmJSStoreHeap, and the same concerns apply. 1.288 + LStoreTypedArrayElementStatic *lir; 1.289 + switch (ins->viewType()) { 1.290 + case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8: 1.291 + case ArrayBufferView::TYPE_UINT8_CLAMPED: 1.292 + lir = new(alloc()) LStoreTypedArrayElementStatic(useRegister(ins->ptr()), 1.293 + useFixed(ins->value(), eax)); 1.294 + break; 1.295 + case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16: 1.296 + case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32: 1.297 + case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64: 1.298 + lir = new(alloc()) LStoreTypedArrayElementStatic(useRegisterAtStart(ins->ptr()), 1.299 + useRegisterAtStart(ins->value())); 1.300 + break; 1.301 + default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); 1.302 + } 1.303 + 1.304 + return add(lir, ins); 1.305 +} 1.306 + 1.307 +bool 1.308 +LIRGeneratorX86::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins) 1.309 +{ 1.310 + return define(new(alloc()) LAsmJSLoadFuncPtr(useRegisterAtStart(ins->index())), ins); 1.311 +}