js/src/jit/x86/Lowering-x86.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #include "jit/x86/Lowering-x86.h"
     9 #include "jit/MIR.h"
    10 #include "jit/x86/Assembler-x86.h"
    12 #include "jit/shared/Lowering-shared-inl.h"
    14 using namespace js;
    15 using namespace js::jit;
    17 LDefinition
    18 LIRGeneratorX86::tempForDispatchCache(MIRType outputType)
    19 {
    20     // x86 doesn't have a scratch register and we need one for the
    21     // indirect jump for dispatch-style ICs.
    22     //
    23     // Note that currently we only install dispatch-style ICs for parallel
    24     // execution. If this assumption changes, please change it here.
    25     if (gen->info().executionMode() != ParallelExecution)
    26         return LDefinition::BogusTemp();
    28     // If we don't have an output register, we need a temp.
    29     if (outputType == MIRType_None)
    30         return temp();
    32     // If we have a double output register, we need a temp.
    33     if (outputType == MIRType_Double)
    34         return temp();
    36     // Otherwise we have a non-double output register and we can reuse it.
    37     return LDefinition::BogusTemp();
    38 }
    40 bool
    41 LIRGeneratorX86::useBox(LInstruction *lir, size_t n, MDefinition *mir,
    42                         LUse::Policy policy, bool useAtStart)
    43 {
    44     JS_ASSERT(mir->type() == MIRType_Value);
    46     if (!ensureDefined(mir))
    47         return false;
    48     lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
    49     lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
    50     return true;
    51 }
    53 bool
    54 LIRGeneratorX86::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
    55                              Register reg2)
    56 {
    57     JS_ASSERT(mir->type() == MIRType_Value);
    58     JS_ASSERT(reg1 != reg2);
    60     if (!ensureDefined(mir))
    61         return false;
    62     lir->setOperand(n, LUse(reg1, mir->virtualRegister()));
    63     lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir)));
    64     return true;
    65 }
    67 LAllocation
    68 LIRGeneratorX86::useByteOpRegister(MDefinition *mir)
    69 {
    70     return useFixed(mir, eax);
    71 }
    73 LAllocation
    74 LIRGeneratorX86::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir)
    75 {
    76     return useFixed(mir, eax);
    77 }
    79 bool
    80 LIRGeneratorX86::visitBox(MBox *box)
    81 {
    82     MDefinition *inner = box->getOperand(0);
    84     // If the box wrapped a double, it needs a new register.
    85     if (IsFloatingPointType(inner->type()))
    86         return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0),
    87                                                         inner->type()), box);
    89     if (box->canEmitAtUses())
    90         return emitAtUses(box);
    92     if (inner->isConstant())
    93         return defineBox(new(alloc()) LValue(inner->toConstant()->value()), box);
    95     LBox *lir = new(alloc()) LBox(use(inner), inner->type());
    97     // Otherwise, we should not define a new register for the payload portion
    98     // of the output, so bypass defineBox().
    99     uint32_t vreg = getVirtualRegister();
   100     if (vreg >= MAX_VIRTUAL_REGISTERS)
   101         return false;
   103     // Note that because we're using PASSTHROUGH, we do not change the type of
   104     // the definition. We also do not define the first output as "TYPE",
   105     // because it has no corresponding payload at (vreg + 1). Also note that
   106     // although we copy the input's original type for the payload half of the
   107     // definition, this is only for clarity. PASSTHROUGH definitions are
   108     // ignored.
   109     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
   110     lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
   111                                LDefinition::PASSTHROUGH));
   112     box->setVirtualRegister(vreg);
   113     return add(lir);
   114 }
   116 bool
   117 LIRGeneratorX86::visitUnbox(MUnbox *unbox)
   118 {
   119     // An unbox on x86 reads in a type tag (either in memory or a register) and
   120     // a payload. Unlike most instructions conusming a box, we ask for the type
   121     // second, so that the result can re-use the first input.
   122     MDefinition *inner = unbox->getOperand(0);
   124     if (!ensureDefined(inner))
   125         return false;
   127     if (IsFloatingPointType(unbox->type())) {
   128         LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
   129         if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
   130             return false;
   131         if (!useBox(lir, LUnboxFloatingPoint::Input, inner))
   132             return false;
   133         return define(lir, unbox);
   134     }
   136     // Swap the order we use the box pieces so we can re-use the payload register.
   137     LUnbox *lir = new(alloc()) LUnbox;
   138     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
   139     lir->setOperand(1, useType(inner, LUse::ANY));
   141     if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
   142         return false;
   144     // Note that PASSTHROUGH here is illegal, since types and payloads form two
   145     // separate intervals. If the type becomes dead before the payload, it
   146     // could be used as a Value without the type being recoverable. Unbox's
   147     // purpose is to eagerly kill the definition of a type tag, so keeping both
   148     // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
   149     // new virtual register.
   150     return defineReuseInput(lir, unbox, 0);
   151 }
   153 bool
   154 LIRGeneratorX86::visitReturn(MReturn *ret)
   155 {
   156     MDefinition *opd = ret->getOperand(0);
   157     JS_ASSERT(opd->type() == MIRType_Value);
   159     LReturn *ins = new(alloc()) LReturn;
   160     ins->setOperand(0, LUse(JSReturnReg_Type));
   161     ins->setOperand(1, LUse(JSReturnReg_Data));
   162     return fillBoxUses(ins, 0, opd) && add(ins);
   163 }
   165 bool
   166 LIRGeneratorX86::defineUntypedPhi(MPhi *phi, size_t lirIndex)
   167 {
   168     LPhi *type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
   169     LPhi *payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
   171     uint32_t typeVreg = getVirtualRegister();
   172     if (typeVreg >= MAX_VIRTUAL_REGISTERS)
   173         return false;
   175     phi->setVirtualRegister(typeVreg);
   177     uint32_t payloadVreg = getVirtualRegister();
   178     if (payloadVreg >= MAX_VIRTUAL_REGISTERS)
   179         return false;
   180     JS_ASSERT(typeVreg + 1 == payloadVreg);
   182     type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE));
   183     payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD));
   184     annotate(type);
   185     annotate(payload);
   186     return true;
   187 }
   189 void
   190 LIRGeneratorX86::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex)
   191 {
   192     MDefinition *operand = phi->getOperand(inputPosition);
   193     LPhi *type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
   194     LPhi *payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
   195     type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET, LUse::ANY));
   196     payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
   197 }
   199 bool
   200 LIRGeneratorX86::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins)
   201 {
   202     JS_ASSERT(ins->input()->type() == MIRType_Int32);
   203     LAsmJSUInt32ToDouble *lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()), temp());
   204     return define(lir, ins);
   205 }
   207 bool
   208 LIRGeneratorX86::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins)
   209 {
   210     JS_ASSERT(ins->input()->type() == MIRType_Int32);
   211     LAsmJSUInt32ToFloat32 *lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()), temp());
   212     return define(lir, ins);
   213 }
   215 bool
   216 LIRGeneratorX86::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
   217 {
   218     MDefinition *ptr = ins->ptr();
   219     LAllocation ptrAlloc;
   220     JS_ASSERT(ptr->type() == MIRType_Int32);
   222     // For the x86 it is best to keep the 'ptr' in a register if a bounds check is needed.
   223     if (ptr->isConstant() && ins->skipBoundsCheck()) {
   224         int32_t ptrValue = ptr->toConstant()->value().toInt32();
   225         // A bounds check is only skipped for a positive index.
   226         JS_ASSERT(ptrValue >= 0);
   227         ptrAlloc = LAllocation(ptr->toConstant()->vp());
   228     } else {
   229         ptrAlloc = useRegisterAtStart(ptr);
   230     }
   231     LAsmJSLoadHeap *lir = new(alloc()) LAsmJSLoadHeap(ptrAlloc);
   232     return define(lir, ins);
   233 }
   235 bool
   236 LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
   237 {
   238     MDefinition *ptr = ins->ptr();
   239     LAsmJSStoreHeap *lir;
   240     JS_ASSERT(ptr->type() == MIRType_Int32);
   242     if (ptr->isConstant() && ins->skipBoundsCheck()) {
   243         int32_t ptrValue = ptr->toConstant()->value().toInt32();
   244         JS_ASSERT(ptrValue >= 0);
   245         LAllocation ptrAlloc = LAllocation(ptr->toConstant()->vp());
   246         switch (ins->viewType()) {
   247           case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8:
   248             // See comment below.
   249             lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useFixed(ins->value(), eax));
   250             break;
   251           case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16:
   252           case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32:
   253           case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64:
   254             // See comment below.
   255             lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value()));
   256             break;
   257           default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
   258         }
   259         return add(lir, ins);
   260     }
   262     switch (ins->viewType()) {
   263       case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8:
   264         // See comment for LIRGeneratorX86::useByteOpRegister.
   265         lir = new(alloc()) LAsmJSStoreHeap(useRegister(ins->ptr()), useFixed(ins->value(), eax));
   266         break;
   267       case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16:
   268       case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32:
   269       case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64:
   270         // For now, don't allow constant values. The immediate operand
   271         // affects instruction layout which affects patching.
   272         lir = new(alloc()) LAsmJSStoreHeap(useRegisterAtStart(ptr), useRegisterAtStart(ins->value()));
   273         break;
   274       default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
   275     }
   277     return add(lir, ins);
   278 }
   280 bool
   281 LIRGeneratorX86::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
   282 {
   283     // The code generated for StoreTypedArrayElementStatic is identical to that
   284     // for AsmJSStoreHeap, and the same concerns apply.
   285     LStoreTypedArrayElementStatic *lir;
   286     switch (ins->viewType()) {
   287       case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8:
   288       case ArrayBufferView::TYPE_UINT8_CLAMPED:
   289         lir = new(alloc()) LStoreTypedArrayElementStatic(useRegister(ins->ptr()),
   290                                                          useFixed(ins->value(), eax));
   291         break;
   292       case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16:
   293       case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32:
   294       case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64:
   295         lir = new(alloc()) LStoreTypedArrayElementStatic(useRegisterAtStart(ins->ptr()),
   296                                                          useRegisterAtStart(ins->value()));
   297         break;
   298       default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
   299     }
   301     return add(lir, ins);
   302 }
   304 bool
   305 LIRGeneratorX86::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
   306 {
   307     return define(new(alloc()) LAsmJSLoadFuncPtr(useRegisterAtStart(ins->index())), ins);
   308 }

mercurial