js/src/jit/mips/Lowering-mips.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 "mozilla/MathAlgorithms.h"
    10 #include "jit/Lowering.h"
    11 #include "jit/mips/Assembler-mips.h"
    12 #include "jit/MIR.h"
    14 #include "jit/shared/Lowering-shared-inl.h"
    16 using namespace js;
    17 using namespace js::jit;
    19 using mozilla::FloorLog2;
    21 bool
    22 LIRGeneratorMIPS::useBox(LInstruction *lir, size_t n, MDefinition *mir,
    23                          LUse::Policy policy, bool useAtStart)
    24 {
    25     MOZ_ASSERT(mir->type() == MIRType_Value);
    27     if (!ensureDefined(mir))
    28         return false;
    29     lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
    30     lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
    31     return true;
    32 }
    34 bool
    35 LIRGeneratorMIPS::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
    36                               Register reg2)
    37 {
    38     MOZ_ASSERT(mir->type() == MIRType_Value);
    39     MOZ_ASSERT(reg1 != reg2);
    41     if (!ensureDefined(mir))
    42         return false;
    43     lir->setOperand(n, LUse(reg1, mir->virtualRegister()));
    44     lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir)));
    45     return true;
    46 }
    48 LAllocation
    49 LIRGeneratorMIPS::useByteOpRegister(MDefinition *mir)
    50 {
    51     return useRegister(mir);
    52 }
    54 LAllocation
    55 LIRGeneratorMIPS::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir)
    56 {
    57     return useRegisterOrNonDoubleConstant(mir);
    58 }
    60 bool
    61 LIRGeneratorMIPS::lowerConstantDouble(double d, MInstruction *mir)
    62 {
    63     return define(new(alloc()) LDouble(d), mir);
    64 }
    66 bool
    67 LIRGeneratorMIPS::lowerConstantFloat32(float d, MInstruction *mir)
    68 {
    69     return define(new(alloc()) LFloat32(d), mir);
    70 }
    72 bool
    73 LIRGeneratorMIPS::visitConstant(MConstant *ins)
    74 {
    75     if (ins->type() == MIRType_Double)
    76         return lowerConstantDouble(ins->value().toDouble(), ins);
    78     if (ins->type() == MIRType_Float32)
    79         return lowerConstantFloat32(ins->value().toDouble(), ins);
    81     // Emit non-double constants at their uses.
    82     if (ins->canEmitAtUses())
    83         return emitAtUses(ins);
    85     return LIRGeneratorShared::visitConstant(ins);
    86 }
    88 bool
    89 LIRGeneratorMIPS::visitBox(MBox *box)
    90 {
    91     MDefinition *inner = box->getOperand(0);
    93     // If the box wrapped a double, it needs a new register.
    94     if (IsFloatingPointType(inner->type()))
    95         return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner),
    96                                                         tempCopy(inner, 0), inner->type()), box);
    98     if (box->canEmitAtUses())
    99         return emitAtUses(box);
   101     if (inner->isConstant())
   102         return defineBox(new(alloc()) LValue(inner->toConstant()->value()), box);
   104     LBox *lir = new(alloc()) LBox(use(inner), inner->type());
   106     // Otherwise, we should not define a new register for the payload portion
   107     // of the output, so bypass defineBox().
   108     uint32_t vreg = getVirtualRegister();
   109     if (vreg >= MAX_VIRTUAL_REGISTERS)
   110         return false;
   112     // Note that because we're using PASSTHROUGH, we do not change the type of
   113     // the definition. We also do not define the first output as "TYPE",
   114     // because it has no corresponding payload at (vreg + 1). Also note that
   115     // although we copy the input's original type for the payload half of the
   116     // definition, this is only for clarity. PASSTHROUGH definitions are
   117     // ignored.
   118     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
   119     lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
   120                                LDefinition::PASSTHROUGH));
   121     box->setVirtualRegister(vreg);
   122     return add(lir);
   123 }
   125 bool
   126 LIRGeneratorMIPS::visitUnbox(MUnbox *unbox)
   127 {
   128     // An unbox on mips reads in a type tag (either in memory or a register) and
   129     // a payload. Unlike most instructions consuming a box, we ask for the type
   130     // second, so that the result can re-use the first input.
   131     MDefinition *inner = unbox->getOperand(0);
   133     if (!ensureDefined(inner))
   134         return false;
   136     if (IsFloatingPointType(unbox->type())) {
   137         LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
   138         if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
   139             return false;
   140         if (!useBox(lir, LUnboxFloatingPoint::Input, inner))
   141             return false;
   142         return define(lir, unbox);
   143     }
   145     // Swap the order we use the box pieces so we can re-use the payload
   146     // register.
   147     LUnbox *lir = new(alloc()) LUnbox;
   148     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
   149     lir->setOperand(1, useType(inner, LUse::REGISTER));
   151     if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
   152         return false;
   154     // Note that PASSTHROUGH here is illegal, since types and payloads form two
   155     // separate intervals. If the type becomes dead before the payload, it
   156     // could be used as a Value without the type being recoverable. Unbox's
   157     // purpose is to eagerly kill the definition of a type tag, so keeping both
   158     // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
   159     // new virtual register.
   160     return defineReuseInput(lir, unbox, 0);
   161 }
   163 bool
   164 LIRGeneratorMIPS::visitReturn(MReturn *ret)
   165 {
   166     MDefinition *opd = ret->getOperand(0);
   167     MOZ_ASSERT(opd->type() == MIRType_Value);
   169     LReturn *ins = new(alloc()) LReturn;
   170     ins->setOperand(0, LUse(JSReturnReg_Type));
   171     ins->setOperand(1, LUse(JSReturnReg_Data));
   172     return fillBoxUses(ins, 0, opd) && add(ins);
   173 }
   175 // x = !y
   176 bool
   177 LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 1, 0> *ins,
   178                               MDefinition *mir, MDefinition *input)
   179 {
   180     ins->setOperand(0, useRegister(input));
   181     return define(ins, mir,
   182                   LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
   183 }
   185 // z = x+y
   186 bool
   187 LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
   188                               MDefinition *lhs, MDefinition *rhs)
   189 {
   190     ins->setOperand(0, useRegister(lhs));
   191     ins->setOperand(1, useRegisterOrConstant(rhs));
   192     return define(ins, mir,
   193                   LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
   194 }
   196 bool
   197 LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
   198                               MDefinition *input)
   199 {
   200     ins->setOperand(0, useRegister(input));
   201     return define(ins, mir,
   202                   LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
   203 }
   205 bool
   206 LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
   207                               MDefinition *lhs, MDefinition *rhs)
   208 {
   209     ins->setOperand(0, useRegister(lhs));
   210     ins->setOperand(1, useRegister(rhs));
   211     return define(ins, mir,
   212                   LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
   213 }
   215 bool
   216 LIRGeneratorMIPS::lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir,
   217                                           MDefinition *lhs, MDefinition *rhs)
   218 {
   219     baab->setOperand(0, useRegisterAtStart(lhs));
   220     baab->setOperand(1, useRegisterOrConstantAtStart(rhs));
   221     return add(baab, mir);
   222 }
   224 bool
   225 LIRGeneratorMIPS::defineUntypedPhi(MPhi *phi, size_t lirIndex)
   226 {
   227     LPhi *type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
   228     LPhi *payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
   230     uint32_t typeVreg = getVirtualRegister();
   231     if (typeVreg >= MAX_VIRTUAL_REGISTERS)
   232         return false;
   234     phi->setVirtualRegister(typeVreg);
   236     uint32_t payloadVreg = getVirtualRegister();
   237     if (payloadVreg >= MAX_VIRTUAL_REGISTERS)
   238         return false;
   239     MOZ_ASSERT(typeVreg + 1 == payloadVreg);
   241     type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE));
   242     payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD));
   243     annotate(type);
   244     annotate(payload);
   245     return true;
   246 }
   248 void
   249 LIRGeneratorMIPS::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition,
   250                                        LBlock *block, size_t lirIndex)
   251 {
   252     MDefinition *operand = phi->getOperand(inputPosition);
   253     LPhi *type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
   254     LPhi *payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
   255     type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET,
   256                                          LUse::ANY));
   257     payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
   258 }
   260 bool
   261 LIRGeneratorMIPS::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
   262                                 MDefinition *lhs, MDefinition *rhs)
   263 {
   264     ins->setOperand(0, useRegister(lhs));
   265     ins->setOperand(1, useRegisterOrConstant(rhs));
   266     return define(ins, mir);
   267 }
   269 bool
   270 LIRGeneratorMIPS::lowerDivI(MDiv *div)
   271 {
   272     if (div->isUnsigned())
   273         return lowerUDiv(div);
   275     // Division instructions are slow. Division by constant denominators can be
   276     // rewritten to use other instructions.
   277     if (div->rhs()->isConstant()) {
   278         int32_t rhs = div->rhs()->toConstant()->value().toInt32();
   279         // Check for division by a positive power of two, which is an easy and
   280         // important case to optimize. Note that other optimizations are also
   281         // possible; division by negative powers of two can be optimized in a
   282         // similar manner as positive powers of two, and division by other
   283         // constants can be optimized by a reciprocal multiplication technique.
   284         int32_t shift = FloorLog2(rhs);
   285         if (rhs > 0 && 1 << shift == rhs) {
   286             LDivPowTwoI *lir = new(alloc()) LDivPowTwoI(useRegister(div->lhs()), shift, temp());
   287             if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   288                 return false;
   289             return define(lir, div);
   290         }
   291     }
   293     LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp());
   294     if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   295         return false;
   296     return define(lir, div);
   297 }
   299 bool
   300 LIRGeneratorMIPS::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
   301 {
   302     LMulI *lir = new(alloc()) LMulI;
   303     if (mul->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   304         return false;
   306     return lowerForALU(lir, mul, lhs, rhs);
   307 }
   309 bool
   310 LIRGeneratorMIPS::lowerModI(MMod *mod)
   311 {
   312     if (mod->isUnsigned())
   313         return lowerUMod(mod);
   315     if (mod->rhs()->isConstant()) {
   316         int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
   317         int32_t shift = FloorLog2(rhs);
   318         if (rhs > 0 && 1 << shift == rhs) {
   319             LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegister(mod->lhs()), shift);
   320             if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   321                 return false;
   322             return define(lir, mod);
   323         } else if (shift < 31 && (1 << (shift + 1)) - 1 == rhs) {
   324             LModMaskI *lir = new(alloc()) LModMaskI(useRegister(mod->lhs()),
   325                                            temp(LDefinition::GENERAL), shift + 1);
   326             if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   327                 return false;
   328             return define(lir, mod);
   329         }
   330     }
   331     LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()), useRegister(mod->rhs()),
   332                            temp(LDefinition::GENERAL));
   334     if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   335         return false;
   336     return define(lir, mod);
   337 }
   339 bool
   340 LIRGeneratorMIPS::visitPowHalf(MPowHalf *ins)
   341 {
   342     MDefinition *input = ins->input();
   343     MOZ_ASSERT(input->type() == MIRType_Double);
   344     LPowHalfD *lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
   345     return defineReuseInput(lir, ins, 0);
   346 }
   348 LTableSwitch *
   349 LIRGeneratorMIPS::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
   350                                   MTableSwitch *tableswitch)
   351 {
   352     return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
   353 }
   355 LTableSwitchV *
   356 LIRGeneratorMIPS::newLTableSwitchV(MTableSwitch *tableswitch)
   357 {
   358     return new(alloc()) LTableSwitchV(temp(), tempFloat32(), temp(), tableswitch);
   359 }
   361 bool
   362 LIRGeneratorMIPS::visitGuardShape(MGuardShape *ins)
   363 {
   364     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
   366     LDefinition tempObj = temp(LDefinition::OBJECT);
   367     LGuardShape *guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj);
   368     if (!assignSnapshot(guard, ins->bailoutKind()))
   369         return false;
   370     if (!add(guard, ins))
   371         return false;
   372     return redefine(ins, ins->obj());
   373 }
   375 bool
   376 LIRGeneratorMIPS::visitGuardObjectType(MGuardObjectType *ins)
   377 {
   378     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
   380     LDefinition tempObj = temp(LDefinition::OBJECT);
   381     LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj);
   382     if (!assignSnapshot(guard))
   383         return false;
   384     if (!add(guard, ins))
   385         return false;
   386     return redefine(ins, ins->obj());
   387 }
   389 bool
   390 LIRGeneratorMIPS::lowerUrshD(MUrsh *mir)
   391 {
   392     MDefinition *lhs = mir->lhs();
   393     MDefinition *rhs = mir->rhs();
   395     MOZ_ASSERT(lhs->type() == MIRType_Int32);
   396     MOZ_ASSERT(rhs->type() == MIRType_Int32);
   398     LUrshD *lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
   399     return define(lir, mir);
   400 }
   402 bool
   403 LIRGeneratorMIPS::visitAsmJSNeg(MAsmJSNeg *ins)
   404 {
   405     if (ins->type() == MIRType_Int32)
   406         return define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
   408     if (ins->type() == MIRType_Float32)
   409     return define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
   411     MOZ_ASSERT(ins->type() == MIRType_Double);
   412     return define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
   413 }
   415 bool
   416 LIRGeneratorMIPS::lowerUDiv(MDiv *div)
   417 {
   418     MDefinition *lhs = div->getOperand(0);
   419     MDefinition *rhs = div->getOperand(1);
   421     LUDiv *lir = new(alloc()) LUDiv;
   422     lir->setOperand(0, useRegister(lhs));
   423     lir->setOperand(1, useRegister(rhs));
   424     if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   425         return false;
   427     return define(lir, div);
   428 }
   430 bool
   431 LIRGeneratorMIPS::lowerUMod(MMod *mod)
   432 {
   433     MDefinition *lhs = mod->getOperand(0);
   434     MDefinition *rhs = mod->getOperand(1);
   436     LUMod *lir = new(alloc()) LUMod;
   437     lir->setOperand(0, useRegister(lhs));
   438     lir->setOperand(1, useRegister(rhs));
   439     if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
   440         return false;
   442     return define(lir, mod);
   443 }
   445 bool
   446 LIRGeneratorMIPS::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins)
   447 {
   448     MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
   449     LAsmJSUInt32ToDouble *lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()));
   450     return define(lir, ins);
   451 }
   453 bool
   454 LIRGeneratorMIPS::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins)
   455 {
   456     MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
   457     LAsmJSUInt32ToFloat32 *lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()));
   458     return define(lir, ins);
   459 }
   461 bool
   462 LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
   463 {
   464     MDefinition *ptr = ins->ptr();
   465     MOZ_ASSERT(ptr->type() == MIRType_Int32);
   466     LAllocation ptrAlloc;
   468     // For MIPS it is best to keep the 'ptr' in a register if a bounds check
   469     // is needed.
   470     if (ptr->isConstant() && ins->skipBoundsCheck()) {
   471         int32_t ptrValue = ptr->toConstant()->value().toInt32();
   472         // A bounds check is only skipped for a positive index.
   473         MOZ_ASSERT(ptrValue >= 0);
   474         ptrAlloc = LAllocation(ptr->toConstant()->vp());
   475     } else
   476         ptrAlloc = useRegisterAtStart(ptr);
   478     return define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
   479 }
   481 bool
   482 LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
   483 {
   484     MDefinition *ptr = ins->ptr();
   485     MOZ_ASSERT(ptr->type() == MIRType_Int32);
   486     LAllocation ptrAlloc;
   488     if (ptr->isConstant() && ins->skipBoundsCheck()) {
   489         MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0);
   490         ptrAlloc = LAllocation(ptr->toConstant()->vp());
   491     } else
   492         ptrAlloc = useRegisterAtStart(ptr);
   494     return add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
   495 }
   497 bool
   498 LIRGeneratorMIPS::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
   499 {
   500     return define(new(alloc()) LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins);
   501 }
   503 bool
   504 LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32 *ins)
   505 {
   506     MDefinition *opd = ins->input();
   507     MOZ_ASSERT(opd->type() == MIRType_Double);
   509     return define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
   510 }
   512 bool
   513 LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32 *ins)
   514 {
   515     MDefinition *opd = ins->input();
   516     MOZ_ASSERT(opd->type() == MIRType_Float32);
   518     return define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
   519 }
   521 bool
   522 LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
   523 {
   524     MOZ_ASSUME_UNREACHABLE("NYI");
   525 }
   527 bool
   528 LIRGeneratorMIPS::visitForkJoinGetSlice(MForkJoinGetSlice *ins)
   529 {
   530     MOZ_ASSUME_UNREACHABLE("NYI");
   531 }

mercurial