js/src/jit/shared/Lowering-shared-inl.h

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 #ifndef jit_shared_Lowering_shared_inl_h
     8 #define jit_shared_Lowering_shared_inl_h
    10 #include "jit/shared/Lowering-shared.h"
    12 #include "jit/MIR.h"
    13 #include "jit/MIRGenerator.h"
    15 namespace js {
    16 namespace jit {
    18 bool
    19 LIRGeneratorShared::emitAtUses(MInstruction *mir)
    20 {
    21     JS_ASSERT(mir->canEmitAtUses());
    22     mir->setEmittedAtUses();
    23     mir->setVirtualRegister(0);
    24     return true;
    25 }
    27 LUse
    28 LIRGeneratorShared::use(MDefinition *mir, LUse policy)
    29 {
    30     // It is illegal to call use() on an instruction with two defs.
    31 #if BOX_PIECES > 1
    32     JS_ASSERT(mir->type() != MIRType_Value);
    33 #endif
    34     if (!ensureDefined(mir))
    35         return policy;
    36     policy.setVirtualRegister(mir->virtualRegister());
    37     return policy;
    38 }
    40 template <size_t X, size_t Y> bool
    41 LIRGeneratorShared::define(LInstructionHelper<1, X, Y> *lir, MDefinition *mir, const LDefinition &def)
    42 {
    43     // Call instructions should use defineReturn.
    44     JS_ASSERT(!lir->isCall());
    46     uint32_t vreg = getVirtualRegister();
    47     if (vreg >= MAX_VIRTUAL_REGISTERS)
    48         return false;
    50     // Assign the definition and a virtual register. Then, propagate this
    51     // virtual register to the MIR, so we can map MIR to LIR during lowering.
    52     lir->setDef(0, def);
    53     lir->getDef(0)->setVirtualRegister(vreg);
    54     lir->setMir(mir);
    55     mir->setVirtualRegister(vreg);
    56     return add(lir);
    57 }
    59 template <size_t X, size_t Y> bool
    60 LIRGeneratorShared::define(LInstructionHelper<1, X, Y> *lir, MDefinition *mir, LDefinition::Policy policy)
    61 {
    62     LDefinition::Type type = LDefinition::TypeFrom(mir->type());
    63     return define(lir, mir, LDefinition(type, policy));
    64 }
    66 template <size_t X, size_t Y> bool
    67 LIRGeneratorShared::defineFixed(LInstructionHelper<1, X, Y> *lir, MDefinition *mir, const LAllocation &output)
    68 {
    69     LDefinition::Type type = LDefinition::TypeFrom(mir->type());
    71     LDefinition def(type, LDefinition::PRESET);
    72     def.setOutput(output);
    74     // Add an LNop to avoid regalloc problems if the next op uses this value
    75     // with a fixed or at-start policy.
    76     if (!define(lir, mir, def))
    77         return false;
    79     if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) {
    80         if (!add(new(alloc()) LNop))
    81             return false;
    82     }
    84     return true;
    85 }
    87 template <size_t Ops, size_t Temps> bool
    88 LIRGeneratorShared::defineReuseInput(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, uint32_t operand)
    89 {
    90     // The input should be used at the start of the instruction, to avoid moves.
    91     JS_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart());
    93     LDefinition::Type type = LDefinition::TypeFrom(mir->type());
    95     LDefinition def(type, LDefinition::MUST_REUSE_INPUT);
    96     def.setReusedInput(operand);
    98     return define(lir, mir, def);
    99 }
   101 template <size_t Ops, size_t Temps> bool
   102 LIRGeneratorShared::defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps> *lir, MDefinition *mir,
   103                               LDefinition::Policy policy)
   104 {
   105     // Call instructions should use defineReturn.
   106     JS_ASSERT(!lir->isCall());
   108     uint32_t vreg = getVirtualRegister();
   109     if (vreg >= MAX_VIRTUAL_REGISTERS)
   110         return false;
   112 #if defined(JS_NUNBOX32)
   113     lir->setDef(0, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy));
   114     lir->setDef(1, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy));
   115     if (getVirtualRegister() >= MAX_VIRTUAL_REGISTERS)
   116         return false;
   117 #elif defined(JS_PUNBOX64)
   118     lir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy));
   119 #endif
   120     lir->setMir(mir);
   122     mir->setVirtualRegister(vreg);
   123     return add(lir);
   124 }
   126 bool
   127 LIRGeneratorShared::defineReturn(LInstruction *lir, MDefinition *mir)
   128 {
   129     lir->setMir(mir);
   131     JS_ASSERT(lir->isCall());
   133     uint32_t vreg = getVirtualRegister();
   134     if (vreg >= MAX_VIRTUAL_REGISTERS)
   135         return false;
   137     switch (mir->type()) {
   138       case MIRType_Value:
   139 #if defined(JS_NUNBOX32)
   140         lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE,
   141                                             LGeneralReg(JSReturnReg_Type)));
   142         lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD,
   143                                                LGeneralReg(JSReturnReg_Data)));
   145         if (getVirtualRegister() >= MAX_VIRTUAL_REGISTERS)
   146             return false;
   147 #elif defined(JS_PUNBOX64)
   148         lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg)));
   149 #endif
   150         break;
   151       case MIRType_Float32:
   152         lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, LFloatReg(ReturnFloatReg)));
   153         break;
   154       case MIRType_Double:
   155         lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnFloatReg)));
   156         break;
   157       default:
   158         LDefinition::Type type = LDefinition::TypeFrom(mir->type());
   159         JS_ASSERT(type != LDefinition::DOUBLE && type != LDefinition::FLOAT32);
   160         lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ReturnReg)));
   161         break;
   162     }
   164     mir->setVirtualRegister(vreg);
   165     if (!add(lir))
   166         return false;
   168     if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) {
   169         if (!add(new(alloc()) LNop))
   170             return false;
   171     }
   173     return true;
   174 }
   176 // In LIR, we treat booleans and integers as the same low-level type (INTEGER).
   177 // When snapshotting, we recover the actual JS type from MIR. This function
   178 // checks that when making redefinitions, we don't accidentally coerce two
   179 // incompatible types.
   180 static inline bool
   181 IsCompatibleLIRCoercion(MIRType to, MIRType from)
   182 {
   183     if (to == from)
   184         return true;
   185     if ((to == MIRType_Int32 || to == MIRType_Boolean) &&
   186         (from == MIRType_Int32 || from == MIRType_Boolean)) {
   187         return true;
   188     }
   189     return false;
   190 }
   192 bool
   193 LIRGeneratorShared::redefine(MDefinition *def, MDefinition *as)
   194 {
   195     JS_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type()));
   197     // Try to emit MIR marked as emitted-at-uses at, well, uses. For
   198     // snapshotting reasons we delay the MIRTypes match, or when we are
   199     // coercing between bool and int32 constants.
   200     if (as->isEmittedAtUses() &&
   201         (def->type() == as->type() ||
   202          (as->isConstant() &&
   203           (def->type() == MIRType_Int32 || def->type() == MIRType_Boolean) &&
   204           (as->type() == MIRType_Int32 || as->type() == MIRType_Boolean))))
   205     {
   206         MDefinition *replacement;
   207         if (def->type() != as->type()) {
   208             Value v = as->toConstant()->value();
   209             if (as->type() == MIRType_Int32)
   210                 replacement = MConstant::New(alloc(), BooleanValue(v.toInt32()));
   211             else
   212                 replacement = MConstant::New(alloc(), Int32Value(v.toBoolean()));
   213             if (!emitAtUses(replacement->toInstruction()))
   214                 return false;
   215         } else {
   216             replacement = as;
   217         }
   218         def->replaceAllUsesWith(replacement);
   219         return true;
   220     }
   222     if (!ensureDefined(as))
   223         return false;
   224     def->setVirtualRegister(as->virtualRegister());
   225     return true;
   226 }
   228 bool
   229 LIRGeneratorShared::defineAs(LInstruction *outLir, MDefinition *outMir, MDefinition *inMir)
   230 {
   231     uint32_t vreg = inMir->virtualRegister();
   232     LDefinition::Policy policy = LDefinition::PASSTHROUGH;
   234     if (outMir->type() == MIRType_Value) {
   235 #ifdef JS_NUNBOX32
   236         outLir->setDef(TYPE_INDEX,
   237                        LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy));
   238         outLir->setDef(PAYLOAD_INDEX,
   239                        LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy));
   240 #elif JS_PUNBOX64
   241         outLir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy));
   242 #else
   243 # error "Unexpected boxing type"
   244 #endif
   245     } else {
   246         outLir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(inMir->type()), policy));
   247     }
   248     outLir->setMir(outMir);
   249     return redefine(outMir, inMir);
   250 }
   252 bool
   253 LIRGeneratorShared::ensureDefined(MDefinition *mir)
   254 {
   255     if (mir->isEmittedAtUses()) {
   256         if (!mir->toInstruction()->accept(this))
   257             return false;
   258         JS_ASSERT(mir->isLowered());
   259     }
   260     return true;
   261 }
   263 LUse
   264 LIRGeneratorShared::useRegister(MDefinition *mir)
   265 {
   266     return use(mir, LUse(LUse::REGISTER));
   267 }
   269 LUse
   270 LIRGeneratorShared::useRegisterAtStart(MDefinition *mir)
   271 {
   272     return use(mir, LUse(LUse::REGISTER, true));
   273 }
   275 LUse
   276 LIRGeneratorShared::use(MDefinition *mir)
   277 {
   278     return use(mir, LUse(LUse::ANY));
   279 }
   281 LUse
   282 LIRGeneratorShared::useAtStart(MDefinition *mir)
   283 {
   284     return use(mir, LUse(LUse::ANY, true));
   285 }
   287 LAllocation
   288 LIRGeneratorShared::useOrConstant(MDefinition *mir)
   289 {
   290     if (mir->isConstant())
   291         return LAllocation(mir->toConstant()->vp());
   292     return use(mir);
   293 }
   295 LAllocation
   296 LIRGeneratorShared::useRegisterOrConstant(MDefinition *mir)
   297 {
   298     if (mir->isConstant())
   299         return LAllocation(mir->toConstant()->vp());
   300     return useRegister(mir);
   301 }
   303 LAllocation
   304 LIRGeneratorShared::useRegisterOrConstantAtStart(MDefinition *mir)
   305 {
   306     if (mir->isConstant())
   307         return LAllocation(mir->toConstant()->vp());
   308     return useRegisterAtStart(mir);
   309 }
   311 LAllocation
   312 LIRGeneratorShared::useRegisterOrNonNegativeConstantAtStart(MDefinition *mir)
   313 {
   314     if (mir->isConstant() && mir->toConstant()->value().toInt32() >= 0)
   315         return LAllocation(mir->toConstant()->vp());
   316     return useRegisterAtStart(mir);
   317 }
   319 LAllocation
   320 LIRGeneratorShared::useRegisterOrNonDoubleConstant(MDefinition *mir)
   321 {
   322     if (mir->isConstant() && mir->type() != MIRType_Double && mir->type() != MIRType_Float32)
   323         return LAllocation(mir->toConstant()->vp());
   324     return useRegister(mir);
   325 }
   327 #if defined(JS_CODEGEN_ARM)
   328 LAllocation
   329 LIRGeneratorShared::useAnyOrConstant(MDefinition *mir)
   330 {
   331     return useRegisterOrConstant(mir);
   332 }
   333 LAllocation
   334 LIRGeneratorShared::useStorable(MDefinition *mir)
   335 {
   336     return useRegister(mir);
   337 }
   338 LAllocation
   339 LIRGeneratorShared::useStorableAtStart(MDefinition *mir)
   340 {
   341     return useRegisterAtStart(mir);
   342 }
   344 LAllocation
   345 LIRGeneratorShared::useAny(MDefinition *mir)
   346 {
   347     return useRegister(mir);
   348 }
   349 #else
   350 LAllocation
   351 LIRGeneratorShared::useAnyOrConstant(MDefinition *mir)
   352 {
   353     return useOrConstant(mir);
   354 }
   356 LAllocation
   357 LIRGeneratorShared::useAny(MDefinition *mir)
   358 {
   359     return use(mir);
   360 }
   361 LAllocation
   362 LIRGeneratorShared::useStorable(MDefinition *mir)
   363 {
   364     return useRegisterOrConstant(mir);
   365 }
   366 LAllocation
   367 LIRGeneratorShared::useStorableAtStart(MDefinition *mir)
   368 {
   369     return useRegisterOrConstantAtStart(mir);
   370 }
   372 #endif
   374 LAllocation
   375 LIRGeneratorShared::useKeepaliveOrConstant(MDefinition *mir)
   376 {
   377     if (mir->isConstant())
   378         return LAllocation(mir->toConstant()->vp());
   379     return use(mir, LUse(LUse::KEEPALIVE));
   380 }
   382 LUse
   383 LIRGeneratorShared::useFixed(MDefinition *mir, Register reg)
   384 {
   385     return use(mir, LUse(reg));
   386 }
   388 LUse
   389 LIRGeneratorShared::useFixedAtStart(MDefinition *mir, Register reg)
   390 {
   391     return use(mir, LUse(reg, true));
   392 }
   394 LUse
   395 LIRGeneratorShared::useFixed(MDefinition *mir, FloatRegister reg)
   396 {
   397     return use(mir, LUse(reg));
   398 }
   400 LUse
   401 LIRGeneratorShared::useFixed(MDefinition *mir, AnyRegister reg)
   402 {
   403     return reg.isFloat() ? use(mir, reg.fpu()) : use(mir, reg.gpr());
   404 }
   406 LDefinition
   407 LIRGeneratorShared::temp(LDefinition::Type type, LDefinition::Policy policy)
   408 {
   409     uint32_t vreg = getVirtualRegister();
   410     if (vreg >= MAX_VIRTUAL_REGISTERS) {
   411         gen->abort("max virtual registers");
   412         return LDefinition();
   413     }
   414     return LDefinition(vreg, type, policy);
   415 }
   417 LDefinition
   418 LIRGeneratorShared::tempFixed(Register reg)
   419 {
   420     LDefinition t = temp(LDefinition::GENERAL);
   421     t.setOutput(LGeneralReg(reg));
   422     return t;
   423 }
   425 LDefinition
   426 LIRGeneratorShared::tempFloat32()
   427 {
   428     return temp(LDefinition::FLOAT32);
   429 }
   431 LDefinition
   432 LIRGeneratorShared::tempDouble()
   433 {
   434     return temp(LDefinition::DOUBLE);
   435 }
   437 LDefinition
   438 LIRGeneratorShared::tempCopy(MDefinition *input, uint32_t reusedInput)
   439 {
   440     JS_ASSERT(input->virtualRegister());
   441     LDefinition t = temp(LDefinition::TypeFrom(input->type()), LDefinition::MUST_REUSE_INPUT);
   442     t.setReusedInput(reusedInput);
   443     return t;
   444 }
   446 template <typename T> void
   447 LIRGeneratorShared::annotate(T *ins)
   448 {
   449     ins->setId(lirGraph_.getInstructionId());
   450 }
   452 template <typename T> bool
   453 LIRGeneratorShared::add(T *ins, MInstruction *mir)
   454 {
   455     JS_ASSERT(!ins->isPhi());
   456     current->add(ins);
   457     if (mir) {
   458         JS_ASSERT(current == mir->block()->lir());
   459         ins->setMir(mir);
   460     }
   461     annotate(ins);
   462     return true;
   463 }
   465 #ifdef JS_NUNBOX32
   466 // Returns the virtual register of a js::Value-defining instruction. This is
   467 // abstracted because MBox is a special value-returning instruction that
   468 // redefines its input payload if its input is not constant. Therefore, it is
   469 // illegal to request a box's payload by adding VREG_DATA_OFFSET to its raw id.
   470 static inline uint32_t
   471 VirtualRegisterOfPayload(MDefinition *mir)
   472 {
   473     if (mir->isBox()) {
   474         MDefinition *inner = mir->toBox()->getOperand(0);
   475         if (!inner->isConstant() && inner->type() != MIRType_Double && inner->type() != MIRType_Float32)
   476             return inner->virtualRegister();
   477     }
   478     if (mir->isTypeBarrier())
   479         return VirtualRegisterOfPayload(mir->getOperand(0));
   480     return mir->virtualRegister() + VREG_DATA_OFFSET;
   481 }
   483 // Note: always call ensureDefined before calling useType/usePayload,
   484 // so that emitted-at-use operands are handled correctly.
   485 LUse
   486 LIRGeneratorShared::useType(MDefinition *mir, LUse::Policy policy)
   487 {
   488     JS_ASSERT(mir->type() == MIRType_Value);
   490     return LUse(mir->virtualRegister() + VREG_TYPE_OFFSET, policy);
   491 }
   493 LUse
   494 LIRGeneratorShared::usePayload(MDefinition *mir, LUse::Policy policy)
   495 {
   496     JS_ASSERT(mir->type() == MIRType_Value);
   498     return LUse(VirtualRegisterOfPayload(mir), policy);
   499 }
   501 LUse
   502 LIRGeneratorShared::usePayloadAtStart(MDefinition *mir, LUse::Policy policy)
   503 {
   504     JS_ASSERT(mir->type() == MIRType_Value);
   506     return LUse(VirtualRegisterOfPayload(mir), policy, true);
   507 }
   509 LUse
   510 LIRGeneratorShared::usePayloadInRegisterAtStart(MDefinition *mir)
   511 {
   512     return usePayloadAtStart(mir, LUse::REGISTER);
   513 }
   515 bool
   516 LIRGeneratorShared::fillBoxUses(LInstruction *lir, size_t n, MDefinition *mir)
   517 {
   518     if (!ensureDefined(mir))
   519         return false;
   520     lir->getOperand(n)->toUse()->setVirtualRegister(mir->virtualRegister() + VREG_TYPE_OFFSET);
   521     lir->getOperand(n + 1)->toUse()->setVirtualRegister(VirtualRegisterOfPayload(mir));
   522     return true;
   523 }
   524 #endif
   526 } // namespace jit
   527 } // namespace js
   529 #endif /* jit_shared_Lowering_shared_inl_h */

mercurial