LCOV - code coverage report
Current view: top level - js/src/jit/shared - Lowering-shared.h (source / functions) Hit Total Coverage
Test: output.info Lines: 20 52 38.5 %
Date: 2017-07-14 16:53:18 Functions: 7 24 29.2 %
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             : #ifndef jit_shared_Lowering_shared_h
       8             : #define jit_shared_Lowering_shared_h
       9             : 
      10             : // This file declares the structures that are used for attaching LIR to a
      11             : // MIRGraph.
      12             : 
      13             : #include "jit/LIR.h"
      14             : #include "jit/MIRGenerator.h"
      15             : 
      16             : namespace js {
      17             : namespace jit {
      18             : 
      19             : class MIRGenerator;
      20             : class MIRGraph;
      21             : class MDefinition;
      22             : class MInstruction;
      23             : class LOsiPoint;
      24             : 
      25             : class LIRGeneratorShared : public MDefinitionVisitor
      26             : {
      27             :   protected:
      28             :     MIRGenerator* gen;
      29             :     MIRGraph& graph;
      30             :     LIRGraph& lirGraph_;
      31             :     LBlock* current;
      32             :     MResumePoint* lastResumePoint_;
      33             :     LRecoverInfo* cachedRecoverInfo_;
      34             :     LOsiPoint* osiPoint_;
      35             : 
      36             :   public:
      37           8 :     LIRGeneratorShared(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
      38           8 :       : gen(gen),
      39             :         graph(graph),
      40             :         lirGraph_(lirGraph),
      41             :         lastResumePoint_(nullptr),
      42             :         cachedRecoverInfo_(nullptr),
      43           8 :         osiPoint_(nullptr)
      44           8 :     { }
      45             : 
      46         403 :     MIRGenerator* mir() {
      47         403 :         return gen;
      48             :     }
      49             : 
      50             :     // Needed to capture the abort error out of the visitInstruction methods.
      51        1411 :     bool errored() {
      52        1411 :         return gen->getOffThreadStatus().isErr();
      53             :     }
      54           0 :     void abort(AbortReason r, const char* message, ...) MOZ_FORMAT_PRINTF(3, 4) {
      55             :         va_list ap;
      56           0 :         va_start(ap, message);
      57           0 :         auto reason_ = gen->abortFmt(r, message, ap);
      58           0 :         va_end(ap);
      59           0 :         gen->setOffThreadStatus(reason_);
      60           0 :     }
      61             :     void abort(AbortReason r) {
      62             :         auto reason_ = gen->abort(r);
      63             :         gen->setOffThreadStatus(reason_);
      64             :     }
      65             : 
      66             :   protected:
      67             : 
      68             :     static void ReorderCommutative(MDefinition** lhsp, MDefinition** rhsp, MInstruction* ins);
      69             :     static bool ShouldReorderCommutative(MDefinition* lhs, MDefinition* rhs, MInstruction* ins);
      70             : 
      71             :     // A backend can decide that an instruction should be emitted at its uses,
      72             :     // rather than at its definition. To communicate this, set the
      73             :     // instruction's virtual register set to 0. When using the instruction,
      74             :     // its virtual register is temporarily reassigned. To know to clear it
      75             :     // after constructing the use information, the worklist bit is temporarily
      76             :     // unset.
      77             :     //
      78             :     // The backend can use the worklist bit to determine whether or not a
      79             :     // definition should be created.
      80             :     inline void emitAtUses(MInstruction* mir);
      81             : 
      82             :     // The lowest-level calls to use, those that do not wrap another call to
      83             :     // use(), must prefix grabbing virtual register IDs by these calls.
      84             :     inline void ensureDefined(MDefinition* mir);
      85             : 
      86             :     // These all create a use of a virtual register, with an optional
      87             :     // allocation policy.
      88             :     //
      89             :     // Some of these use functions have atStart variants.
      90             :     // - non-atStart variants will tell the register allocator that the input
      91             :     // allocation must be different from any Temp or Definition also needed for
      92             :     // this LInstruction.
      93             :     // - atStart variants relax that restriction and allow the input to be in
      94             :     // the same register as any Temp or output Definition used by the
      95             :     // LInstruction. Note that it doesn't *imply* this will actually happen,
      96             :     // but gives a hint to the register allocator that it can do it.
      97             :     //
      98             :     // TL;DR: Use non-atStart variants only if you need the input value after
      99             :     // writing to any temp or definitions, during code generation of this
     100             :     // LInstruction. Otherwise, use atStart variants, which will lower register
     101             :     // pressure.
     102             :     inline LUse use(MDefinition* mir, LUse policy);
     103             :     inline LUse use(MDefinition* mir);
     104             :     inline LUse useAtStart(MDefinition* mir);
     105             :     inline LUse useRegister(MDefinition* mir);
     106             :     inline LUse useRegisterAtStart(MDefinition* mir);
     107             :     inline LUse useFixed(MDefinition* mir, Register reg);
     108             :     inline LUse useFixed(MDefinition* mir, FloatRegister reg);
     109             :     inline LUse useFixed(MDefinition* mir, AnyRegister reg);
     110             :     inline LUse useFixedAtStart(MDefinition* mir, Register reg);
     111             :     inline LUse useFixedAtStart(MDefinition* mir, AnyRegister reg);
     112             :     inline LAllocation useOrConstant(MDefinition* mir);
     113             :     inline LAllocation useOrConstantAtStart(MDefinition* mir);
     114             :     // "Any" is architecture dependent, and will include registers and stack
     115             :     // slots on X86, and only registers on ARM.
     116             :     inline LAllocation useAny(MDefinition* mir);
     117             :     inline LAllocation useAnyOrConstant(MDefinition* mir);
     118             :     // "Storable" is architecture dependend, and will include registers and
     119             :     // constants on X86 and only registers on ARM.  This is a generic "things
     120             :     // we can expect to write into memory in 1 instruction".
     121             :     inline LAllocation useStorable(MDefinition* mir);
     122             :     inline LAllocation useStorableAtStart(MDefinition* mir);
     123             :     inline LAllocation useKeepalive(MDefinition* mir);
     124             :     inline LAllocation useKeepaliveOrConstant(MDefinition* mir);
     125             :     inline LAllocation useRegisterOrConstant(MDefinition* mir);
     126             :     inline LAllocation useRegisterOrConstantAtStart(MDefinition* mir);
     127             :     inline LAllocation useRegisterOrZeroAtStart(MDefinition* mir);
     128             :     inline LAllocation useRegisterOrZero(MDefinition* mir);
     129             :     inline LAllocation useRegisterOrNonDoubleConstant(MDefinition* mir);
     130             : 
     131             :     inline LUse useRegisterForTypedLoad(MDefinition* mir, MIRType type);
     132             : 
     133             : #ifdef JS_NUNBOX32
     134             :     inline LUse useType(MDefinition* mir, LUse::Policy policy);
     135             :     inline LUse usePayload(MDefinition* mir, LUse::Policy policy);
     136             :     inline LUse usePayloadAtStart(MDefinition* mir, LUse::Policy policy);
     137             :     inline LUse usePayloadInRegisterAtStart(MDefinition* mir);
     138             : 
     139             :     // Adds a box input to an instruction, setting operand |n| to the type and
     140             :     // |n+1| to the payload. Does not modify the operands, instead expecting a
     141             :     // policy to already be set.
     142             :     inline void fillBoxUses(LInstruction* lir, size_t n, MDefinition* mir);
     143             : #endif
     144             : 
     145             :     // These create temporary register requests.
     146             :     inline LDefinition temp(LDefinition::Type type = LDefinition::GENERAL,
     147             :                             LDefinition::Policy policy = LDefinition::REGISTER);
     148             :     inline LInt64Definition tempInt64(LDefinition::Policy policy = LDefinition::REGISTER);
     149             :     inline LDefinition tempFloat32();
     150             :     inline LDefinition tempDouble();
     151             :     inline LDefinition tempCopy(MDefinition* input, uint32_t reusedInput);
     152             : 
     153             :     // Note that the fixed register has a GENERAL type.
     154             :     inline LDefinition tempFixed(Register reg);
     155             : 
     156             :     template <size_t Ops, size_t Temps>
     157             :     inline void defineFixed(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir,
     158             :                             const LAllocation& output);
     159             : 
     160             :     template <size_t Ops, size_t Temps>
     161             :     inline void defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir,
     162             :                           LDefinition::Policy policy = LDefinition::REGISTER);
     163             : 
     164             :     template <size_t Ops, size_t Temps>
     165             :     inline void defineInt64(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir,
     166             :                             LDefinition::Policy policy = LDefinition::REGISTER);
     167             : 
     168             :     template <size_t Ops, size_t Temps>
     169             :     inline void defineInt64Fixed(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir,
     170             :                                  const LInt64Allocation& output);
     171             : 
     172             :     template <size_t Ops, size_t Temps>
     173             :     inline void defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefinition *mir,
     174             :                              LDefinition::Policy policy = LDefinition::REGISTER);
     175             : 
     176             :     inline void defineSharedStubReturn(LInstruction* lir, MDefinition* mir);
     177             :     inline void defineReturn(LInstruction* lir, MDefinition* mir);
     178             : 
     179             :     template <size_t X>
     180             :     inline void define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
     181             :                        LDefinition::Policy policy = LDefinition::REGISTER);
     182             :     template <size_t X>
     183             :     inline void define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
     184             :                        const LDefinition& def);
     185             : 
     186             :     template <size_t Ops, size_t Temps>
     187             :     inline void defineReuseInput(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir,
     188             :                                  uint32_t operand);
     189             : 
     190             :     template <size_t Ops, size_t Temps>
     191             :     inline void defineInt64ReuseInput(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir,
     192             :                                       MDefinition* mir, uint32_t operand);
     193             : 
     194             :     // Returns a box allocation for a Value-typed instruction.
     195             :     inline LBoxAllocation useBox(MDefinition* mir, LUse::Policy policy = LUse::REGISTER,
     196             :                                  bool useAtStart = false);
     197             : 
     198             :     // Returns a box allocation. The use is either typed, a Value, or
     199             :     // a constant (if useConstant is true).
     200             :     inline LBoxAllocation useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant);
     201             :     inline LBoxAllocation useBoxOrTyped(MDefinition* mir);
     202             : 
     203             :     // Returns an int64 allocation for an Int64-typed instruction.
     204             :     inline LInt64Allocation useInt64(MDefinition* mir, LUse::Policy policy, bool useAtStart);
     205             :     inline LInt64Allocation useInt64(MDefinition* mir, bool useAtStart = false);
     206             :     inline LInt64Allocation useInt64AtStart(MDefinition* mir);
     207             :     inline LInt64Allocation useInt64OrConstant(MDefinition* mir, bool useAtStart = false);
     208             :     inline LInt64Allocation useInt64Register(MDefinition* mir, bool useAtStart = false);
     209             :     inline LInt64Allocation useInt64RegisterOrConstant(MDefinition* mir, bool useAtStart = false);
     210             :     inline LInt64Allocation useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtStart = false);
     211             :     inline LInt64Allocation useInt64FixedAtStart(MDefinition* mir, Register64 regs);
     212             : 
     213           0 :     LInt64Allocation useInt64RegisterAtStart(MDefinition* mir) {
     214           0 :         return useInt64Register(mir, /* useAtStart = */ true);
     215             :     }
     216           0 :     LInt64Allocation useInt64RegisterOrConstantAtStart(MDefinition* mir) {
     217           0 :         return useInt64RegisterOrConstant(mir, /* useAtStart = */ true);
     218             :     }
     219           0 :     LInt64Allocation useInt64OrConstantAtStart(MDefinition* mir) {
     220           0 :         return useInt64OrConstant(mir, /* useAtStart = */ true);
     221             :     }
     222             : 
     223             :     // Rather than defining a new virtual register, sets |ins| to have the same
     224             :     // virtual register as |as|.
     225             :     inline void redefine(MDefinition* ins, MDefinition* as);
     226             : 
     227             :     // Redefine a sin/cos call to sincos.
     228             :     inline void redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func);
     229             : 
     230        1564 :     TempAllocator& alloc() const {
     231        1564 :         return graph.alloc();
     232             :     }
     233             : 
     234        1062 :     uint32_t getVirtualRegister() {
     235        1062 :         uint32_t vreg = lirGraph_.getVirtualRegister();
     236             : 
     237             :         // If we run out of virtual registers, mark code generation as having
     238             :         // failed and return a dummy vreg. Include a + 1 here for NUNBOX32
     239             :         // platforms that expect Value vregs to be adjacent.
     240        1062 :         if (vreg + 1 >= MAX_VIRTUAL_REGISTERS) {
     241           0 :             abort(AbortReason::Alloc, "max virtual registers");
     242           0 :             return 1;
     243             :         }
     244        1062 :         return vreg;
     245             :     }
     246             : 
     247             :     template <typename T> void annotate(T* ins);
     248             :     template <typename T> void add(T* ins, MInstruction* mir = nullptr);
     249             : 
     250             :     void lowerTypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     251             :     void defineTypedPhi(MPhi* phi, size_t lirIndex);
     252             : 
     253        1411 :     LOsiPoint* popOsiPoint() {
     254        1411 :         LOsiPoint* tmp = osiPoint_;
     255        1411 :         osiPoint_ = nullptr;
     256        1411 :         return tmp;
     257             :     }
     258             : 
     259             :     LRecoverInfo* getRecoverInfo(MResumePoint* rp);
     260             :     LSnapshot* buildSnapshot(LInstruction* ins, MResumePoint* rp, BailoutKind kind);
     261             :     bool assignPostSnapshot(MInstruction* mir, LInstruction* ins);
     262             : 
     263             :     // Marks this instruction as fallible, meaning that before it performs
     264             :     // effects (if any), it may check pre-conditions and bailout if they do not
     265             :     // hold. This function informs the register allocator that it will need to
     266             :     // capture appropriate state.
     267             :     void assignSnapshot(LInstruction* ins, BailoutKind kind);
     268             : 
     269             :     // Marks this instruction as needing to call into either the VM or GC. This
     270             :     // function may build a snapshot that captures the result of its own
     271             :     // instruction, and as such, should generally be called after define*().
     272             :     void assignSafepoint(LInstruction* ins, MInstruction* mir,
     273             :                          BailoutKind kind = Bailout_DuringVMCall);
     274             : 
     275             :   public:
     276           0 :     void lowerConstantDouble(double d, MInstruction* mir) {
     277           0 :         define(new(alloc()) LDouble(d), mir);
     278           0 :     }
     279           0 :     void lowerConstantFloat32(float f, MInstruction* mir) {
     280           0 :         define(new(alloc()) LFloat32(f), mir);
     281           0 :     }
     282             : 
     283             :     void visitConstant(MConstant* ins) override;
     284             :     void visitWasmFloatConstant(MWasmFloatConstant* ins) override;
     285             : 
     286             :     // Whether to generate typed reads for element accesses with hole checks.
     287           1 :     static bool allowTypedElementHoleCheck() {
     288           1 :         return false;
     289             :     }
     290             : 
     291             :     // Whether to generate typed array accesses on statically known objects.
     292           0 :     static bool allowStaticTypedArrayAccesses() {
     293           0 :         return false;
     294             :     }
     295             : 
     296             :     // Provide NYI default implementations of the SIMD visitor functions.
     297             :     // Many targets don't implement SIMD at all, and we don't want to duplicate
     298             :     // these stubs in the specific sub-classes.
     299             :     // Some SIMD visitors are implemented in LIRGenerator in Lowering.cpp. These
     300             :     // shared implementations are not included here.
     301           0 :     void visitSimdInsertElement(MSimdInsertElement*) override { MOZ_CRASH("NYI"); }
     302           0 :     void visitSimdExtractElement(MSimdExtractElement*) override { MOZ_CRASH("NYI"); }
     303           0 :     void visitSimdBinaryArith(MSimdBinaryArith*) override { MOZ_CRASH("NYI"); }
     304           0 :     void visitSimdSelect(MSimdSelect*) override { MOZ_CRASH("NYI"); }
     305           0 :     void visitSimdSplat(MSimdSplat*) override { MOZ_CRASH("NYI"); }
     306           0 :     void visitSimdValueX4(MSimdValueX4*) override { MOZ_CRASH("NYI"); }
     307           0 :     void visitSimdBinarySaturating(MSimdBinarySaturating*) override { MOZ_CRASH("NYI"); }
     308           0 :     void visitSimdSwizzle(MSimdSwizzle*) override { MOZ_CRASH("NYI"); }
     309           0 :     void visitSimdShuffle(MSimdShuffle*) override { MOZ_CRASH("NYI"); }
     310           0 :     void visitSimdGeneralShuffle(MSimdGeneralShuffle*) override { MOZ_CRASH("NYI"); }
     311             : };
     312             : 
     313             : } // namespace jit
     314             : } // namespace js
     315             : 
     316             : #endif /* jit_shared_Lowering_shared_h */

Generated by: LCOV version 1.13