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