LCOV - code coverage report
Current view: top level - js/src/jit/shared - Lowering-shared.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 82 125 65.6 %
Date: 2017-07-14 16:53:18 Functions: 10 11 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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/shared/Lowering-shared-inl.h"
       8             : 
       9             : #include "jit/LIR.h"
      10             : #include "jit/MIR.h"
      11             : 
      12             : #include "vm/Symbol.h"
      13             : 
      14             : using namespace js;
      15             : using namespace jit;
      16             : 
      17             : bool
      18          13 : LIRGeneratorShared::ShouldReorderCommutative(MDefinition* lhs, MDefinition* rhs, MInstruction* ins)
      19             : {
      20             :     // lhs and rhs are used by the commutative operator.
      21          13 :     MOZ_ASSERT(lhs->hasDefUses());
      22          13 :     MOZ_ASSERT(rhs->hasDefUses());
      23             : 
      24             :     // Ensure that if there is a constant, then it is in rhs.
      25          13 :     if (rhs->isConstant())
      26          13 :         return false;
      27           0 :     if (lhs->isConstant())
      28           0 :         return true;
      29             : 
      30             :     // Since clobbering binary operations clobber the left operand, prefer a
      31             :     // non-constant lhs operand with no further uses. To be fully precise, we
      32             :     // should check whether this is the *last* use, but checking hasOneDefUse()
      33             :     // is a decent approximation which doesn't require any extra analysis.
      34           0 :     bool rhsSingleUse = rhs->hasOneDefUse();
      35           0 :     bool lhsSingleUse = lhs->hasOneDefUse();
      36           0 :     if (rhsSingleUse) {
      37           0 :         if (!lhsSingleUse)
      38           0 :             return true;
      39             :     } else {
      40           0 :         if (lhsSingleUse)
      41           0 :             return false;
      42             :     }
      43             : 
      44             :     // If this is a reduction-style computation, such as
      45             :     //
      46             :     //   sum = 0;
      47             :     //   for (...)
      48             :     //      sum += ...;
      49             :     //
      50             :     // put the phi on the left to promote coalescing. This is fairly specific.
      51           0 :     if (rhsSingleUse &&
      52           0 :         rhs->isPhi() &&
      53           0 :         rhs->block()->isLoopHeader() &&
      54           0 :         ins == rhs->toPhi()->getLoopBackedgeOperand())
      55             :     {
      56           0 :         return true;
      57             :     }
      58             : 
      59           0 :     return false;
      60             : }
      61             : 
      62             : void
      63          13 : LIRGeneratorShared::ReorderCommutative(MDefinition** lhsp, MDefinition** rhsp, MInstruction* ins)
      64             : {
      65          13 :     MDefinition* lhs = *lhsp;
      66          13 :     MDefinition* rhs = *rhsp;
      67             : 
      68          13 :     if (ShouldReorderCommutative(lhs, rhs, ins)) {
      69           0 :         *rhsp = lhs;
      70           0 :         *lhsp = rhs;
      71             :     }
      72          13 : }
      73             : 
      74             : void
      75         252 : LIRGeneratorShared::visitConstant(MConstant* ins)
      76             : {
      77         252 :     if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
      78         184 :         emitAtUses(ins);
      79         184 :         return;
      80             :     }
      81             : 
      82          68 :     switch (ins->type()) {
      83             :       case MIRType::Double:
      84           0 :         define(new(alloc()) LDouble(ins->toDouble()), ins);
      85           0 :         break;
      86             :       case MIRType::Float32:
      87           0 :         define(new(alloc()) LFloat32(ins->toFloat32()), ins);
      88           0 :         break;
      89             :       case MIRType::Boolean:
      90          42 :         define(new(alloc()) LInteger(ins->toBoolean()), ins);
      91          42 :         break;
      92             :       case MIRType::Int32:
      93           7 :         define(new(alloc()) LInteger(ins->toInt32()), ins);
      94           7 :         break;
      95             :       case MIRType::Int64:
      96           0 :         defineInt64(new(alloc()) LInteger64(ins->toInt64()), ins);
      97           0 :         break;
      98             :       case MIRType::String:
      99          10 :         define(new(alloc()) LPointer(ins->toString()), ins);
     100          10 :         break;
     101             :       case MIRType::Symbol:
     102           0 :         define(new(alloc()) LPointer(ins->toSymbol()), ins);
     103           0 :         break;
     104             :       case MIRType::Object:
     105           9 :         define(new(alloc()) LPointer(&ins->toObject()), ins);
     106           9 :         break;
     107             :       default:
     108             :         // Constants of special types (undefined, null) should never flow into
     109             :         // here directly. Operations blindly consuming them require a Box.
     110           0 :         MOZ_CRASH("unexpected constant type");
     111             :     }
     112             : }
     113             : 
     114             : void
     115           0 : LIRGeneratorShared::visitWasmFloatConstant(MWasmFloatConstant* ins)
     116             : {
     117           0 :     switch (ins->type()) {
     118             :       case MIRType::Double:
     119           0 :         define(new(alloc()) LDouble(ins->toDouble()), ins);
     120           0 :         break;
     121             :       case MIRType::Float32:
     122           0 :         define(new(alloc()) LFloat32(ins->toFloat32()), ins);
     123           0 :         break;
     124             :       default:
     125           0 :         MOZ_CRASH("unexpected constant type");
     126             :     }
     127           0 : }
     128             : 
     129             : void
     130         175 : LIRGeneratorShared::defineTypedPhi(MPhi* phi, size_t lirIndex)
     131             : {
     132         175 :     LPhi* lir = current->getPhi(lirIndex);
     133             : 
     134         175 :     uint32_t vreg = getVirtualRegister();
     135             : 
     136         175 :     phi->setVirtualRegister(vreg);
     137         175 :     lir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(phi->type())));
     138         175 :     annotate(lir);
     139         175 : }
     140             : 
     141             : void
     142         430 : LIRGeneratorShared::lowerTypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex)
     143             : {
     144         430 :     MDefinition* operand = phi->getOperand(inputPosition);
     145         430 :     LPhi* lir = block->getPhi(lirIndex);
     146         430 :     lir->setOperand(inputPosition, LUse(operand->virtualRegister(), LUse::ANY));
     147         430 : }
     148             : 
     149             : LRecoverInfo*
     150         326 : LIRGeneratorShared::getRecoverInfo(MResumePoint* rp)
     151             : {
     152         326 :     if (cachedRecoverInfo_ && cachedRecoverInfo_->mir() == rp)
     153         149 :         return cachedRecoverInfo_;
     154             : 
     155         177 :     LRecoverInfo* recoverInfo = LRecoverInfo::New(gen, rp);
     156         177 :     if (!recoverInfo)
     157           0 :         return nullptr;
     158             : 
     159         177 :     cachedRecoverInfo_ = recoverInfo;
     160         177 :     return recoverInfo;
     161             : }
     162             : 
     163             : #ifdef DEBUG
     164             : bool
     165        7321 : LRecoverInfo::OperandIter::canOptimizeOutIfUnused()
     166             : {
     167        7321 :     MDefinition* ins = **this;
     168             : 
     169             :     // We check ins->type() in addition to ins->isUnused() because
     170             :     // EliminateDeadResumePointOperands may replace nodes with the constant
     171             :     // MagicValue(JS_OPTIMIZED_OUT).
     172        7566 :     if ((ins->isUnused() || ins->type() == MIRType::MagicOptimizedOut) &&
     173         245 :         (*it_)->isResumePoint())
     174             :     {
     175         245 :         return !(*it_)->toResumePoint()->isObservableOperand(op_);
     176             :     }
     177             : 
     178        7076 :     return true;
     179             : }
     180             : #endif
     181             : 
     182             : #ifdef JS_NUNBOX32
     183             : LSnapshot*
     184             : LIRGeneratorShared::buildSnapshot(LInstruction* ins, MResumePoint* rp, BailoutKind kind)
     185             : {
     186             :     LRecoverInfo* recoverInfo = getRecoverInfo(rp);
     187             :     if (!recoverInfo)
     188             :         return nullptr;
     189             : 
     190             :     LSnapshot* snapshot = LSnapshot::New(gen, recoverInfo, kind);
     191             :     if (!snapshot)
     192             :         return nullptr;
     193             : 
     194             :     size_t index = 0;
     195             :     for (LRecoverInfo::OperandIter it(recoverInfo); !it; ++it) {
     196             :         // Check that optimized out operands are in eliminable slots.
     197             :         MOZ_ASSERT(it.canOptimizeOutIfUnused());
     198             : 
     199             :         MDefinition* ins = *it;
     200             : 
     201             :         if (ins->isRecoveredOnBailout())
     202             :             continue;
     203             : 
     204             :         LAllocation* type = snapshot->typeOfSlot(index);
     205             :         LAllocation* payload = snapshot->payloadOfSlot(index);
     206             :         ++index;
     207             : 
     208             :         if (ins->isBox())
     209             :             ins = ins->toBox()->getOperand(0);
     210             : 
     211             :         // Guards should never be eliminated.
     212             :         MOZ_ASSERT_IF(ins->isUnused(), !ins->isGuard());
     213             : 
     214             :         // Snapshot operands other than constants should never be
     215             :         // emitted-at-uses. Try-catch support depends on there being no
     216             :         // code between an instruction and the LOsiPoint that follows it.
     217             :         MOZ_ASSERT_IF(!ins->isConstant(), !ins->isEmittedAtUses());
     218             : 
     219             :         // The register allocation will fill these fields in with actual
     220             :         // register/stack assignments. During code generation, we can restore
     221             :         // interpreter state with the given information. Note that for
     222             :         // constants, including known types, we record a dummy placeholder,
     223             :         // since we can recover the same information, much cleaner, from MIR.
     224             :         if (ins->isConstant() || ins->isUnused()) {
     225             :             *type = LAllocation();
     226             :             *payload = LAllocation();
     227             :         } else if (ins->type() != MIRType::Value) {
     228             :             *type = LAllocation();
     229             :             *payload = use(ins, LUse(LUse::KEEPALIVE));
     230             :         } else {
     231             :             *type = useType(ins, LUse::KEEPALIVE);
     232             :             *payload = usePayload(ins, LUse::KEEPALIVE);
     233             :         }
     234             :     }
     235             : 
     236             :     return snapshot;
     237             : }
     238             : 
     239             : #elif JS_PUNBOX64
     240             : 
     241             : LSnapshot*
     242         326 : LIRGeneratorShared::buildSnapshot(LInstruction* ins, MResumePoint* rp, BailoutKind kind)
     243             : {
     244         326 :     LRecoverInfo* recoverInfo = getRecoverInfo(rp);
     245         326 :     if (!recoverInfo)
     246           0 :         return nullptr;
     247             : 
     248         326 :     LSnapshot* snapshot = LSnapshot::New(gen, recoverInfo, kind);
     249         326 :     if (!snapshot)
     250           0 :         return nullptr;
     251             : 
     252         326 :     size_t index = 0;
     253        7647 :     for (LRecoverInfo::OperandIter it(recoverInfo); !it; ++it) {
     254             :         // Check that optimized out operands are in eliminable slots.
     255        7321 :         MOZ_ASSERT(it.canOptimizeOutIfUnused());
     256             : 
     257        7321 :         MDefinition* def = *it;
     258             : 
     259        7321 :         if (def->isRecoveredOnBailout())
     260         308 :             continue;
     261             : 
     262        7013 :         if (def->isBox())
     263           2 :             def = def->toBox()->getOperand(0);
     264             : 
     265             :         // Guards should never be eliminated.
     266        7013 :         MOZ_ASSERT_IF(def->isUnused(), !def->isGuard());
     267             : 
     268             :         // Snapshot operands other than constants should never be
     269             :         // emitted-at-uses. Try-catch support depends on there being no
     270             :         // code between an instruction and the LOsiPoint that follows it.
     271        7013 :         MOZ_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses());
     272             : 
     273        7013 :         LAllocation* a = snapshot->getEntry(index++);
     274             : 
     275        7013 :         if (def->isUnused()) {
     276           0 :             *a = LAllocation();
     277           0 :             continue;
     278             :         }
     279             : 
     280        7013 :         *a = useKeepaliveOrConstant(def);
     281             :     }
     282             : 
     283         326 :     return snapshot;
     284             : }
     285             : #endif
     286             : 
     287             : void
     288         192 : LIRGeneratorShared::assignSnapshot(LInstruction* ins, BailoutKind kind)
     289             : {
     290             :     // assignSnapshot must be called before define/add, since
     291             :     // it may add new instructions for emitted-at-use operands.
     292         192 :     MOZ_ASSERT(ins->id() == 0);
     293             : 
     294         192 :     LSnapshot* snapshot = buildSnapshot(ins, lastResumePoint_, kind);
     295         192 :     if (snapshot)
     296         192 :         ins->assignSnapshot(snapshot);
     297             :     else
     298           0 :         abort(AbortReason::Alloc, "buildSnapshot failed");
     299         192 : }
     300             : 
     301             : void
     302         134 : LIRGeneratorShared::assignSafepoint(LInstruction* ins, MInstruction* mir, BailoutKind kind)
     303             : {
     304         134 :     MOZ_ASSERT(!osiPoint_);
     305         134 :     MOZ_ASSERT(!ins->safepoint());
     306             : 
     307         134 :     ins->initSafepoint(alloc());
     308             : 
     309         134 :     MResumePoint* mrp = mir->resumePoint() ? mir->resumePoint() : lastResumePoint_;
     310         134 :     LSnapshot* postSnapshot = buildSnapshot(ins, mrp, kind);
     311         134 :     if (!postSnapshot) {
     312           0 :         abort(AbortReason::Alloc, "buildSnapshot failed");
     313           0 :         return;
     314             :     }
     315             : 
     316         134 :     osiPoint_ = new(alloc()) LOsiPoint(ins->safepoint(), postSnapshot);
     317             : 
     318         134 :     if (!lirGraph_.noteNeedsSafepoint(ins))
     319           0 :         abort(AbortReason::Alloc, "noteNeedsSafepoint failed");
     320             : }
     321             : 

Generated by: LCOV version 1.13