michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_shared_Lowering_shared_h michael@0: #define jit_shared_Lowering_shared_h michael@0: michael@0: // This file declares the structures that are used for attaching LIR to a michael@0: // MIRGraph. michael@0: michael@0: #include "jit/LIR.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class MBasicBlock; michael@0: class MTableSwitch; michael@0: class MIRGenerator; michael@0: class MIRGraph; michael@0: class MDefinition; michael@0: class MInstruction; michael@0: class LOsiPoint; michael@0: michael@0: class LIRGeneratorShared : public MInstructionVisitorWithDefaults michael@0: { michael@0: protected: michael@0: MIRGenerator *gen; michael@0: MIRGraph &graph; michael@0: LIRGraph &lirGraph_; michael@0: LBlock *current; michael@0: MResumePoint *lastResumePoint_; michael@0: LRecoverInfo *cachedRecoverInfo_; michael@0: LOsiPoint *osiPoint_; michael@0: michael@0: public: michael@0: LIRGeneratorShared(MIRGenerator *gen, MIRGraph &graph, LIRGraph &lirGraph) michael@0: : gen(gen), michael@0: graph(graph), michael@0: lirGraph_(lirGraph), michael@0: lastResumePoint_(nullptr), michael@0: cachedRecoverInfo_(nullptr), michael@0: osiPoint_(nullptr) michael@0: { } michael@0: michael@0: MIRGenerator *mir() { michael@0: return gen; michael@0: } michael@0: michael@0: protected: michael@0: // A backend can decide that an instruction should be emitted at its uses, michael@0: // rather than at its definition. To communicate this, set the michael@0: // instruction's virtual register set to 0. When using the instruction, michael@0: // its virtual register is temporarily reassigned. To know to clear it michael@0: // after constructing the use information, the worklist bit is temporarily michael@0: // unset. michael@0: // michael@0: // The backend can use the worklist bit to determine whether or not a michael@0: // definition should be created. michael@0: inline bool emitAtUses(MInstruction *mir); michael@0: michael@0: // The lowest-level calls to use, those that do not wrap another call to michael@0: // use(), must prefix grabbing virtual register IDs by these calls. michael@0: inline bool ensureDefined(MDefinition *mir); michael@0: michael@0: // These all create a use of a virtual register, with an optional michael@0: // allocation policy. michael@0: inline LUse use(MDefinition *mir, LUse policy); michael@0: inline LUse use(MDefinition *mir); michael@0: inline LUse useAtStart(MDefinition *mir); michael@0: inline LUse useRegister(MDefinition *mir); michael@0: inline LUse useRegisterAtStart(MDefinition *mir); michael@0: inline LUse useFixed(MDefinition *mir, Register reg); michael@0: inline LUse useFixed(MDefinition *mir, FloatRegister reg); michael@0: inline LUse useFixed(MDefinition *mir, AnyRegister reg); michael@0: inline LUse useFixedAtStart(MDefinition *mir, Register reg); michael@0: inline LAllocation useOrConstant(MDefinition *mir); michael@0: // "Any" is architecture dependent, and will include registers and stack slots on X86, michael@0: // and only registers on ARM. michael@0: inline LAllocation useAny(MDefinition *mir); michael@0: inline LAllocation useAnyOrConstant(MDefinition *mir); michael@0: // "Storable" is architecture dependend, and will include registers and constants on X86 michael@0: // and only registers on ARM. michael@0: // this is a generic "things we can expect to write into memory in 1 instruction" michael@0: inline LAllocation useStorable(MDefinition *mir); michael@0: inline LAllocation useStorableAtStart(MDefinition *mir); michael@0: inline LAllocation useKeepaliveOrConstant(MDefinition *mir); michael@0: inline LAllocation useRegisterOrConstant(MDefinition *mir); michael@0: inline LAllocation useRegisterOrConstantAtStart(MDefinition *mir); michael@0: inline LAllocation useRegisterOrNonNegativeConstantAtStart(MDefinition *mir); michael@0: inline LAllocation useRegisterOrNonDoubleConstant(MDefinition *mir); michael@0: michael@0: #ifdef JS_NUNBOX32 michael@0: inline LUse useType(MDefinition *mir, LUse::Policy policy); michael@0: inline LUse usePayload(MDefinition *mir, LUse::Policy policy); michael@0: inline LUse usePayloadAtStart(MDefinition *mir, LUse::Policy policy); michael@0: inline LUse usePayloadInRegisterAtStart(MDefinition *mir); michael@0: michael@0: // Adds a box input to an instruction, setting operand |n| to the type and michael@0: // |n+1| to the payload. Does not modify the operands, instead expecting a michael@0: // policy to already be set. michael@0: inline bool fillBoxUses(LInstruction *lir, size_t n, MDefinition *mir); michael@0: #endif michael@0: michael@0: // These create temporary register requests. michael@0: inline LDefinition temp(LDefinition::Type type = LDefinition::GENERAL, michael@0: LDefinition::Policy policy = LDefinition::DEFAULT); michael@0: inline LDefinition tempFloat32(); michael@0: inline LDefinition tempDouble(); michael@0: inline LDefinition tempCopy(MDefinition *input, uint32_t reusedInput); michael@0: michael@0: // Note that the fixed register has a GENERAL type. michael@0: inline LDefinition tempFixed(Register reg); michael@0: michael@0: template michael@0: inline bool defineFixed(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, michael@0: const LAllocation &output); michael@0: michael@0: template michael@0: inline bool defineBox(LInstructionHelper *lir, MDefinition *mir, michael@0: LDefinition::Policy policy = LDefinition::DEFAULT); michael@0: michael@0: inline bool defineReturn(LInstruction *lir, MDefinition *mir); michael@0: michael@0: template michael@0: inline bool define(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, michael@0: const LDefinition &def); michael@0: michael@0: template michael@0: inline bool define(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, michael@0: LDefinition::Policy policy = LDefinition::DEFAULT); michael@0: michael@0: template michael@0: inline bool defineReuseInput(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, uint32_t operand); michael@0: michael@0: // Rather than defining a new virtual register, sets |ins| to have the same michael@0: // virtual register as |as|. michael@0: inline bool redefine(MDefinition *ins, MDefinition *as); michael@0: michael@0: // Defines an IR's output as the same as another IR. This is similar to michael@0: // redefine(), but used when creating new LIR. michael@0: inline bool defineAs(LInstruction *outLir, MDefinition *outMir, MDefinition *inMir); michael@0: michael@0: TempAllocator &alloc() const { michael@0: return graph.alloc(); michael@0: } michael@0: michael@0: uint32_t getVirtualRegister() { michael@0: return lirGraph_.getVirtualRegister(); michael@0: } michael@0: michael@0: template void annotate(T *ins); michael@0: template bool add(T *ins, MInstruction *mir = nullptr); michael@0: michael@0: void lowerTypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex); michael@0: bool defineTypedPhi(MPhi *phi, size_t lirIndex); michael@0: michael@0: LOsiPoint *popOsiPoint() { michael@0: LOsiPoint *tmp = osiPoint_; michael@0: osiPoint_ = nullptr; michael@0: return tmp; michael@0: } michael@0: michael@0: LRecoverInfo *getRecoverInfo(MResumePoint *rp); michael@0: LSnapshot *buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind); michael@0: bool assignPostSnapshot(MInstruction *mir, LInstruction *ins); michael@0: michael@0: // Marks this instruction as fallible, meaning that before it performs michael@0: // effects (if any), it may check pre-conditions and bailout if they do not michael@0: // hold. This function informs the register allocator that it will need to michael@0: // capture appropriate state. michael@0: bool assignSnapshot(LInstruction *ins, BailoutKind kind = Bailout_Normal); michael@0: michael@0: // Marks this instruction as needing to call into either the VM or GC. This michael@0: // function may build a snapshot that captures the result of its own michael@0: // instruction, and as such, should generally be called after define*(). michael@0: bool assignSafepoint(LInstruction *ins, MInstruction *mir); michael@0: michael@0: public: michael@0: bool visitConstant(MConstant *ins); michael@0: michael@0: // Whether to generate typed reads for element accesses with hole checks. michael@0: static bool allowTypedElementHoleCheck() { michael@0: return false; michael@0: } michael@0: michael@0: // Whether to generate typed array accesses on statically known objects. michael@0: static bool allowStaticTypedArrayAccesses() { michael@0: return false; michael@0: } michael@0: michael@0: // Whether we can emit Float32 specific optimizations. michael@0: static bool allowFloat32Optimizations() { michael@0: return false; michael@0: } michael@0: michael@0: // Whether we can inline ForkJoinGetSlice. michael@0: static bool allowInlineForkJoinGetSlice() { michael@0: return false; michael@0: } michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_shared_Lowering_shared_h */