Commit 3276e1df authored by joransiu's avatar joransiu Committed by Commit bot

S390: Initial Impl of Crankshaft features

S390 specific implementations of crankshaft functions.

R=danno@chromium.org,jkummerow@chromium.org,jochen@chromium.org,jyan@ca.ibm.com,michael_dawson@ca.ibm.com,mbrandy@us.ibm.com
BUG=

Review URL: https://codereview.chromium.org/1763233003

Cr-Commit-Position: refs/heads/master@{#34543}
parent 22938040
......@@ -1644,6 +1644,12 @@ source_set("v8_base") {
"src/compiler/s390/instruction-codes-s390.h",
"src/compiler/s390/instruction-scheduler-s390.cc",
"src/compiler/s390/instruction-selector-s390.cc",
"src/crankshaft/s390/lithium-codegen-s390.cc",
"src/crankshaft/s390/lithium-codegen-s390.h",
"src/crankshaft/s390/lithium-gap-resolver-s390.cc",
"src/crankshaft/s390/lithium-gap-resolver-s390.h",
"src/crankshaft/s390/lithium-s390.cc",
"src/crankshaft/s390/lithium-s390.h",
"src/debug/s390/debug-s390.cc",
"src/full-codegen/s390/full-codegen-s390.cc",
"src/ic/s390/access-compiler-s390.cc",
......
......@@ -25,6 +25,8 @@
#include "src/crankshaft/mips/lithium-mips.h" // NOLINT
#elif V8_TARGET_ARCH_MIPS64
#include "src/crankshaft/mips64/lithium-mips64.h" // NOLINT
#elif V8_TARGET_ARCH_S390
#include "src/crankshaft/s390/lithium-s390.h" // NOLINT
#elif V8_TARGET_ARCH_X87
#include "src/crankshaft/x87/lithium-x87.h" // NOLINT
#else
......
......@@ -58,6 +58,8 @@
#include "src/crankshaft/mips/lithium-codegen-mips.h" // NOLINT
#elif V8_TARGET_ARCH_MIPS64
#include "src/crankshaft/mips64/lithium-codegen-mips64.h" // NOLINT
#elif V8_TARGET_ARCH_S390
#include "src/crankshaft/s390/lithium-codegen-s390.h" // NOLINT
#elif V8_TARGET_ARCH_X87
#include "src/crankshaft/x87/lithium-codegen-x87.h" // NOLINT
#else
......
......@@ -21,6 +21,8 @@
#include "src/crankshaft/mips/lithium-mips.h" // NOLINT
#elif V8_TARGET_ARCH_MIPS64
#include "src/crankshaft/mips64/lithium-mips64.h" // NOLINT
#elif V8_TARGET_ARCH_S390
#include "src/crankshaft/s390/lithium-s390.h" // NOLINT
#elif V8_TARGET_ARCH_X87
#include "src/crankshaft/x87/lithium-x87.h" // NOLINT
#else
......
......@@ -30,6 +30,9 @@
#elif V8_TARGET_ARCH_PPC
#include "src/crankshaft/ppc/lithium-ppc.h" // NOLINT
#include "src/crankshaft/ppc/lithium-codegen-ppc.h" // NOLINT
#elif V8_TARGET_ARCH_S390
#include "src/crankshaft/s390/lithium-s390.h" // NOLINT
#include "src/crankshaft/s390/lithium-codegen-s390.h" // NOLINT
#else
#error Unsupported target architecture.
#endif
......
......@@ -21,6 +21,8 @@
#include "src/crankshaft/mips64/lithium-mips64.h" // NOLINT
#elif V8_TARGET_ARCH_PPC
#include "src/crankshaft/ppc/lithium-ppc.h" // NOLINT
#elif V8_TARGET_ARCH_S390
#include "src/crankshaft/s390/lithium-s390.h" // NOLINT
#elif V8_TARGET_ARCH_X87
#include "src/crankshaft/x87/lithium-x87.h" // NOLINT
#else
......
......@@ -30,6 +30,9 @@
#elif V8_TARGET_ARCH_X87
#include "src/crankshaft/x87/lithium-x87.h" // NOLINT
#include "src/crankshaft/x87/lithium-codegen-x87.h" // NOLINT
#elif V8_TARGET_ARCH_S390
#include "src/crankshaft/s390/lithium-s390.h" // NOLINT
#include "src/crankshaft/s390/lithium-codegen-s390.h" // NOLINT
#else
#error "Unknown architecture."
#endif
......
This source diff could not be displayed because it is too large. You can view the blob instead.
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_CRANKSHAFT_S390_LITHIUM_CODEGEN_S390_H_
#define V8_CRANKSHAFT_S390_LITHIUM_CODEGEN_S390_H_
#include "src/ast/scopes.h"
#include "src/crankshaft/lithium-codegen.h"
#include "src/crankshaft/s390/lithium-gap-resolver-s390.h"
#include "src/crankshaft/s390/lithium-s390.h"
#include "src/deoptimizer.h"
#include "src/safepoint-table.h"
#include "src/utils.h"
namespace v8 {
namespace internal {
// Forward declarations.
class LDeferredCode;
class SafepointGenerator;
class LCodeGen : public LCodeGenBase {
public:
LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
: LCodeGenBase(chunk, assembler, info),
jump_table_(4, info->zone()),
scope_(info->scope()),
deferred_(8, info->zone()),
frame_is_built_(false),
safepoints_(info->zone()),
resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) {
PopulateDeoptimizationLiteralsWithInlinedFunctions();
}
int LookupDestination(int block_id) const {
return chunk()->LookupDestination(block_id);
}
bool IsNextEmittedBlock(int block_id) const {
return LookupDestination(block_id) == GetNextEmittedBlock();
}
bool NeedsEagerFrame() const {
return HasAllocatedStackSlots() || info()->is_non_deferred_calling() ||
!info()->IsStub() || info()->requires_frame();
}
bool NeedsDeferredFrame() const {
return !NeedsEagerFrame() && info()->is_deferred_calling();
}
LinkRegisterStatus GetLinkRegisterState() const {
return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved;
}
// Support for converting LOperands to assembler types.
// LOperand must be a register.
Register ToRegister(LOperand* op) const;
// LOperand is loaded into scratch, unless already a register.
Register EmitLoadRegister(LOperand* op, Register scratch);
// LConstantOperand must be an Integer32 or Smi
void EmitLoadIntegerConstant(LConstantOperand* const_op, Register dst);
// LOperand must be a double register.
DoubleRegister ToDoubleRegister(LOperand* op) const;
intptr_t ToRepresentation(LConstantOperand* op,
const Representation& r) const;
int32_t ToInteger32(LConstantOperand* op) const;
Smi* ToSmi(LConstantOperand* op) const;
double ToDouble(LConstantOperand* op) const;
Operand ToOperand(LOperand* op);
MemOperand ToMemOperand(LOperand* op) const;
// Returns a MemOperand pointing to the high word of a DoubleStackSlot.
MemOperand ToHighMemOperand(LOperand* op) const;
bool IsInteger32(LConstantOperand* op) const;
bool IsSmi(LConstantOperand* op) const;
Handle<Object> ToHandle(LConstantOperand* op) const;
// Try to generate code for the entire chunk, but it may fail if the
// chunk contains constructs we cannot handle. Returns true if the
// code generation attempt succeeded.
bool GenerateCode();
// Finish the code by setting stack height, safepoint, and bailout
// information on it.
void FinishCode(Handle<Code> code);
// Deferred code support.
void DoDeferredNumberTagD(LNumberTagD* instr);
enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
void DoDeferredNumberTagIU(LInstruction* instr, LOperand* value,
LOperand* temp1, LOperand* temp2,
IntegerSignedness signedness);
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocate(LAllocate* instr);
void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, Register result,
Register object, Register index);
// Parallel move support.
void DoParallelMove(LParallelMove* move);
void DoGap(LGap* instr);
MemOperand PrepareKeyedOperand(Register key, Register base,
bool key_is_constant, bool key_is_tagged,
int constant_key, int element_size_shift,
int base_offset);
// Emit frame translation commands for an environment.
void WriteTranslation(LEnvironment* environment, Translation* translation);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
private:
LanguageMode language_mode() const { return info()->language_mode(); }
Scope* scope() const { return scope_; }
Register scratch0() { return kLithiumScratch; }
DoubleRegister double_scratch0() { return kScratchDoubleReg; }
LInstruction* GetNextInstruction();
void EmitClassOfTest(Label* if_true, Label* if_false,
Handle<String> class_name, Register input,
Register temporary, Register temporary2);
bool HasAllocatedStackSlots() const {
return chunk()->HasAllocatedStackSlots();
}
int GetStackSlotCount() const { return chunk()->GetSpillSlotCount(); }
int GetTotalFrameSlotCount() const {
return chunk()->GetTotalFrameSlotCount();
}
void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
void SaveCallerDoubles();
void RestoreCallerDoubles();
// Code generation passes. Returns true if code generation should
// continue.
void GenerateBodyInstructionPre(LInstruction* instr) override;
bool GeneratePrologue();
bool GenerateDeferredCode();
bool GenerateJumpTable();
bool GenerateSafepointTable();
// Generates the custom OSR entrypoint and sets the osr_pc_offset.
void GenerateOsrPrologue();
enum SafepointMode {
RECORD_SIMPLE_SAFEPOINT,
RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
};
void CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr);
void CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode,
LInstruction* instr, SafepointMode safepoint_mode);
void CallRuntime(const Runtime::Function* function, int num_arguments,
LInstruction* instr,
SaveFPRegsMode save_doubles = kDontSaveFPRegs);
void CallRuntime(Runtime::FunctionId id, int num_arguments,
LInstruction* instr) {
const Runtime::Function* function = Runtime::FunctionForId(id);
CallRuntime(function, num_arguments, instr);
}
void CallRuntime(Runtime::FunctionId id, LInstruction* instr) {
const Runtime::Function* function = Runtime::FunctionForId(id);
CallRuntime(function, function->nargs, instr);
}
void LoadContextFromDeferred(LOperand* context);
void CallRuntimeFromDeferred(Runtime::FunctionId id, int argc,
LInstruction* instr, LOperand* context);
// Generate a direct call to a known function. Expects the function
// to be in r4.
void CallKnownFunction(Handle<JSFunction> function,
int formal_parameter_count, int arity,
LInstruction* instr);
void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
Safepoint::DeoptMode mode);
void DeoptimizeIf(Condition condition, LInstruction* instr,
Deoptimizer::DeoptReason deopt_reason,
Deoptimizer::BailoutType bailout_type, CRegister cr = cr7);
void DeoptimizeIf(Condition condition, LInstruction* instr,
Deoptimizer::DeoptReason deopt_reason, CRegister cr = cr7);
void AddToTranslation(LEnvironment* environment, Translation* translation,
LOperand* op, bool is_tagged, bool is_uint32,
int* object_index_pointer,
int* dematerialized_index_pointer);
Register ToRegister(int index) const;
DoubleRegister ToDoubleRegister(int index) const;
MemOperand BuildSeqStringOperand(Register string, LOperand* index,
String::Encoding encoding);
void EmitMathAbs(LMathAbs* instr);
#if V8_TARGET_ARCH_S390X
void EmitInteger32MathAbs(LMathAbs* instr);
#endif
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind,
int arguments, Safepoint::DeoptMode mode);
void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
void RecordSafepoint(Safepoint::DeoptMode mode);
void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments,
Safepoint::DeoptMode mode);
void RecordAndWritePosition(int position) override;
static Condition TokenToCondition(Token::Value op);
void EmitGoto(int block);
// EmitBranch expects to be the last instruction of a block.
template <class InstrType>
void EmitBranch(InstrType instr, Condition condition);
template <class InstrType>
void EmitTrueBranch(InstrType instr, Condition condition);
template <class InstrType>
void EmitFalseBranch(InstrType instr, Condition condition);
void EmitNumberUntagD(LNumberUntagD* instr, Register input,
DoubleRegister result, NumberUntagDMode mode);
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitTypeofIs(Label* true_label, Label* false_label, Register input,
Handle<String> type_name);
// Emits optimized code for %_IsString(x). Preserves input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitIsString(Register input, Register temp1, Label* is_not_string,
SmiCheck check_needed);
// Emits optimized code to deep-copy the contents of statically known
// object graphs (e.g. object literal boilerplate).
void EmitDeepCopy(Handle<JSObject> object, Register result, Register source,
int* offset, AllocationSiteMode mode);
void EnsureSpaceForLazyDeopt(int space_needed) override;
void DoLoadKeyedExternalArray(LLoadKeyed* instr);
void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
void DoLoadKeyedFixedArray(LLoadKeyed* instr);
void DoStoreKeyedExternalArray(LStoreKeyed* instr);
void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
void DoStoreKeyedFixedArray(LStoreKeyed* instr);
template <class T>
void EmitVectorLoadICRegisters(T* instr);
template <class T>
void EmitVectorStoreICRegisters(T* instr);
ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
Scope* const scope_;
ZoneList<LDeferredCode*> deferred_;
bool frame_is_built_;
// Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code.
SafepointTableBuilder safepoints_;
// Compiler from a set of parallel moves to a sequential list of moves.
LGapResolver resolver_;
Safepoint::Kind expected_safepoint_kind_;
class PushSafepointRegistersScope final BASE_EMBEDDED {
public:
explicit PushSafepointRegistersScope(LCodeGen* codegen)
: codegen_(codegen) {
DCHECK(codegen_->info()->is_calling());
DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
StoreRegistersStateStub stub(codegen_->isolate());
codegen_->masm_->CallStub(&stub);
}
~PushSafepointRegistersScope() {
DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
RestoreRegistersStateStub stub(codegen_->isolate());
codegen_->masm_->CallStub(&stub);
codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
}
private:
LCodeGen* codegen_;
};
friend class LDeferredCode;
friend class LEnvironment;
friend class SafepointGenerator;
DISALLOW_COPY_AND_ASSIGN(LCodeGen);
};
class LDeferredCode : public ZoneObject {
public:
explicit LDeferredCode(LCodeGen* codegen)
: codegen_(codegen),
external_exit_(NULL),
instruction_index_(codegen->current_instruction_) {
codegen->AddDeferredCode(this);
}
virtual ~LDeferredCode() {}
virtual void Generate() = 0;
virtual LInstruction* instr() = 0;
void SetExit(Label* exit) { external_exit_ = exit; }
Label* entry() { return &entry_; }
Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
int instruction_index() const { return instruction_index_; }
protected:
LCodeGen* codegen() const { return codegen_; }
MacroAssembler* masm() const { return codegen_->masm(); }
private:
LCodeGen* codegen_;
Label entry_;
Label exit_;
Label* external_exit_;
int instruction_index_;
};
} // namespace internal
} // namespace v8
#endif // V8_CRANKSHAFT_S390_LITHIUM_CODEGEN_S390_H_
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/crankshaft/s390/lithium-gap-resolver-s390.h"
#include "src/crankshaft/s390/lithium-codegen-s390.h"
namespace v8 {
namespace internal {
static const Register kSavedValueRegister = {1};
LGapResolver::LGapResolver(LCodeGen* owner)
: cgen_(owner),
moves_(32, owner->zone()),
root_index_(0),
in_cycle_(false),
saved_destination_(NULL) {}
void LGapResolver::Resolve(LParallelMove* parallel_move) {
DCHECK(moves_.is_empty());
// Build up a worklist of moves.
BuildInitialMoveList(parallel_move);
for (int i = 0; i < moves_.length(); ++i) {
LMoveOperands move = moves_[i];
// Skip constants to perform them last. They don't block other moves
// and skipping such moves with register destinations keeps those
// registers free for the whole algorithm.
if (!move.IsEliminated() && !move.source()->IsConstantOperand()) {
root_index_ = i; // Any cycle is found when by reaching this move again.
PerformMove(i);
if (in_cycle_) {
RestoreValue();
}
}
}
// Perform the moves with constant sources.
for (int i = 0; i < moves_.length(); ++i) {
if (!moves_[i].IsEliminated()) {
DCHECK(moves_[i].source()->IsConstantOperand());
EmitMove(i);
}
}
moves_.Rewind(0);
}
void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) {
// Perform a linear sweep of the moves to add them to the initial list of
// moves to perform, ignoring any move that is redundant (the source is
// the same as the destination, the destination is ignored and
// unallocated, or the move was already eliminated).
const ZoneList<LMoveOperands>* moves = parallel_move->move_operands();
for (int i = 0; i < moves->length(); ++i) {
LMoveOperands move = moves->at(i);
if (!move.IsRedundant()) moves_.Add(move, cgen_->zone());
}
Verify();
}
void LGapResolver::PerformMove(int index) {
// Each call to this function performs a move and deletes it from the move
// graph. We first recursively perform any move blocking this one. We
// mark a move as "pending" on entry to PerformMove in order to detect
// cycles in the move graph.
// We can only find a cycle, when doing a depth-first traversal of moves,
// be encountering the starting move again. So by spilling the source of
// the starting move, we break the cycle. All moves are then unblocked,
// and the starting move is completed by writing the spilled value to
// its destination. All other moves from the spilled source have been
// completed prior to breaking the cycle.
// An additional complication is that moves to MemOperands with large
// offsets (more than 1K or 4K) require us to spill this spilled value to
// the stack, to free up the register.
DCHECK(!moves_[index].IsPending());
DCHECK(!moves_[index].IsRedundant());
// Clear this move's destination to indicate a pending move. The actual
// destination is saved in a stack allocated local. Multiple moves can
// be pending because this function is recursive.
DCHECK(moves_[index].source() != NULL); // Or else it will look eliminated.
LOperand* destination = moves_[index].destination();
moves_[index].set_destination(NULL);
// Perform a depth-first traversal of the move graph to resolve
// dependencies. Any unperformed, unpending move with a source the same
// as this one's destination blocks this one so recursively perform all
// such moves.
for (int i = 0; i < moves_.length(); ++i) {
LMoveOperands other_move = moves_[i];
if (other_move.Blocks(destination) && !other_move.IsPending()) {
PerformMove(i);
// If there is a blocking, pending move it must be moves_[root_index_]
// and all other moves with the same source as moves_[root_index_] are
// sucessfully executed (because they are cycle-free) by this loop.
}
}
// We are about to resolve this move and don't need it marked as
// pending, so restore its destination.
moves_[index].set_destination(destination);
// The move may be blocked on a pending move, which must be the starting move.
// In this case, we have a cycle, and we save the source of this move to
// a scratch register to break it.
LMoveOperands other_move = moves_[root_index_];
if (other_move.Blocks(destination)) {
DCHECK(other_move.IsPending());
BreakCycle(index);
return;
}
// This move is no longer blocked.
EmitMove(index);
}
void LGapResolver::Verify() {
#ifdef ENABLE_SLOW_DCHECKS
// No operand should be the destination for more than one move.
for (int i = 0; i < moves_.length(); ++i) {
LOperand* destination = moves_[i].destination();
for (int j = i + 1; j < moves_.length(); ++j) {
SLOW_DCHECK(!destination->Equals(moves_[j].destination()));
}
}
#endif
}
#define __ ACCESS_MASM(cgen_->masm())
void LGapResolver::BreakCycle(int index) {
// We save in a register the value that should end up in the source of
// moves_[root_index]. After performing all moves in the tree rooted
// in that move, we save the value to that source.
DCHECK(moves_[index].destination()->Equals(moves_[root_index_].source()));
DCHECK(!in_cycle_);
in_cycle_ = true;
LOperand* source = moves_[index].source();
saved_destination_ = moves_[index].destination();
if (source->IsRegister()) {
__ LoadRR(kSavedValueRegister, cgen_->ToRegister(source));
} else if (source->IsStackSlot()) {
__ LoadP(kSavedValueRegister, cgen_->ToMemOperand(source));
} else if (source->IsDoubleRegister()) {
__ ldr(kScratchDoubleReg, cgen_->ToDoubleRegister(source));
} else if (source->IsDoubleStackSlot()) {
__ LoadDouble(kScratchDoubleReg, cgen_->ToMemOperand(source));
} else {
UNREACHABLE();
}
// This move will be done by restoring the saved value to the destination.
moves_[index].Eliminate();
}
void LGapResolver::RestoreValue() {
DCHECK(in_cycle_);
DCHECK(saved_destination_ != NULL);
// Spilled value is in kSavedValueRegister or kSavedDoubleValueRegister.
if (saved_destination_->IsRegister()) {
__ LoadRR(cgen_->ToRegister(saved_destination_), kSavedValueRegister);
} else if (saved_destination_->IsStackSlot()) {
__ StoreP(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_));
} else if (saved_destination_->IsDoubleRegister()) {
__ ldr(cgen_->ToDoubleRegister(saved_destination_), kScratchDoubleReg);
} else if (saved_destination_->IsDoubleStackSlot()) {
__ StoreDouble(kScratchDoubleReg, cgen_->ToMemOperand(saved_destination_));
} else {
UNREACHABLE();
}
in_cycle_ = false;
saved_destination_ = NULL;
}
void LGapResolver::EmitMove(int index) {
LOperand* source = moves_[index].source();
LOperand* destination = moves_[index].destination();
// Dispatch on the source and destination operand kinds. Not all
// combinations are possible.
if (source->IsRegister()) {
Register source_register = cgen_->ToRegister(source);
if (destination->IsRegister()) {
__ LoadRR(cgen_->ToRegister(destination), source_register);
} else {
DCHECK(destination->IsStackSlot());
__ StoreP(source_register, cgen_->ToMemOperand(destination));
}
} else if (source->IsStackSlot()) {
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsRegister()) {
__ LoadP(cgen_->ToRegister(destination), source_operand);
} else {
DCHECK(destination->IsStackSlot());
MemOperand destination_operand = cgen_->ToMemOperand(destination);
if (in_cycle_) {
__ LoadP(ip, source_operand);
__ StoreP(ip, destination_operand);
} else {
__ LoadP(kSavedValueRegister, source_operand);
__ StoreP(kSavedValueRegister, destination_operand);
}
}
} else if (source->IsConstantOperand()) {
LConstantOperand* constant_source = LConstantOperand::cast(source);
if (destination->IsRegister()) {
Register dst = cgen_->ToRegister(destination);
if (cgen_->IsInteger32(constant_source)) {
cgen_->EmitLoadIntegerConstant(constant_source, dst);
} else {
__ Move(dst, cgen_->ToHandle(constant_source));
}
} else if (destination->IsDoubleRegister()) {
DoubleRegister result = cgen_->ToDoubleRegister(destination);
double v = cgen_->ToDouble(constant_source);
__ LoadDoubleLiteral(result, v, ip);
} else {
DCHECK(destination->IsStackSlot());
DCHECK(!in_cycle_); // Constant moves happen after all cycles are gone.
if (cgen_->IsInteger32(constant_source)) {
cgen_->EmitLoadIntegerConstant(constant_source, kSavedValueRegister);
} else {
__ Move(kSavedValueRegister, cgen_->ToHandle(constant_source));
}
__ StoreP(kSavedValueRegister, cgen_->ToMemOperand(destination));
}
} else if (source->IsDoubleRegister()) {
DoubleRegister source_register = cgen_->ToDoubleRegister(source);
if (destination->IsDoubleRegister()) {
__ ldr(cgen_->ToDoubleRegister(destination), source_register);
} else {
DCHECK(destination->IsDoubleStackSlot());
__ StoreDouble(source_register, cgen_->ToMemOperand(destination));
}
} else if (source->IsDoubleStackSlot()) {
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsDoubleRegister()) {
__ LoadDouble(cgen_->ToDoubleRegister(destination), source_operand);
} else {
DCHECK(destination->IsDoubleStackSlot());
MemOperand destination_operand = cgen_->ToMemOperand(destination);
if (in_cycle_) {
// kSavedDoubleValueRegister was used to break the cycle,
// but kSavedValueRegister is free.
#if V8_TARGET_ARCH_S390X
__ lg(kSavedValueRegister, source_operand);
__ stg(kSavedValueRegister, destination_operand);
#else
MemOperand source_high_operand = cgen_->ToHighMemOperand(source);
MemOperand destination_high_operand =
cgen_->ToHighMemOperand(destination);
__ LoadlW(kSavedValueRegister, source_operand);
__ StoreW(kSavedValueRegister, destination_operand);
__ LoadlW(kSavedValueRegister, source_high_operand);
__ StoreW(kSavedValueRegister, destination_high_operand);
#endif
} else {
__ LoadDouble(kScratchDoubleReg, source_operand);
__ StoreDouble(kScratchDoubleReg, destination_operand);
}
}
} else {
UNREACHABLE();
}
moves_[index].Eliminate();
}
#undef __
} // namespace internal
} // namespace v8
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_CRANKSHAFT_S390_LITHIUM_GAP_RESOLVER_S390_H_
#define V8_CRANKSHAFT_S390_LITHIUM_GAP_RESOLVER_S390_H_
#include "src/crankshaft/lithium.h"
namespace v8 {
namespace internal {
class LCodeGen;
class LGapResolver;
class LGapResolver final BASE_EMBEDDED {
public:
explicit LGapResolver(LCodeGen* owner);
// Resolve a set of parallel moves, emitting assembler instructions.
void Resolve(LParallelMove* parallel_move);
private:
// Build the initial list of moves.
void BuildInitialMoveList(LParallelMove* parallel_move);
// Perform the move at the moves_ index in question (possibly requiring
// other moves to satisfy dependencies).
void PerformMove(int index);
// If a cycle is found in the series of moves, save the blocking value to
// a scratch register. The cycle must be found by hitting the root of the
// depth-first search.
void BreakCycle(int index);
// After a cycle has been resolved, restore the value from the scratch
// register to its proper destination.
void RestoreValue();
// Emit a move and remove it from the move graph.
void EmitMove(int index);
// Verify the move list before performing moves.
void Verify();
LCodeGen* cgen_;
// List of moves not yet resolved.
ZoneList<LMoveOperands> moves_;
int root_index_;
bool in_cycle_;
LOperand* saved_destination_;
};
} // namespace internal
} // namespace v8
#endif // V8_CRANKSHAFT_S390_LITHIUM_GAP_RESOLVER_S390_H_
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/crankshaft/s390/lithium-s390.h"
#include <sstream>
#include "src/crankshaft/hydrogen-osr.h"
#include "src/crankshaft/lithium-inl.h"
#include "src/crankshaft/s390/lithium-codegen-s390.h"
namespace v8 {
namespace internal {
#define DEFINE_COMPILE(type) \
void L##type::CompileToNative(LCodeGen* generator) { \
generator->Do##type(this); \
}
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
#undef DEFINE_COMPILE
#ifdef DEBUG
void LInstruction::VerifyCall() {
// Call instructions can use only fixed registers as temporaries and
// outputs because all registers are blocked by the calling convention.
// Inputs operands must use a fixed register or use-at-start policy or
// a non-register policy.
DCHECK(Output() == NULL || LUnallocated::cast(Output())->HasFixedPolicy() ||
!LUnallocated::cast(Output())->HasRegisterPolicy());
for (UseIterator it(this); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
DCHECK(operand->HasFixedPolicy() || operand->IsUsedAtStart());
}
for (TempIterator it(this); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
DCHECK(operand->HasFixedPolicy() || !operand->HasRegisterPolicy());
}
}
#endif
void LInstruction::PrintTo(StringStream* stream) {
stream->Add("%s ", this->Mnemonic());
PrintOutputOperandTo(stream);
PrintDataTo(stream);
if (HasEnvironment()) {
stream->Add(" ");
environment()->PrintTo(stream);
}
if (HasPointerMap()) {
stream->Add(" ");
pointer_map()->PrintTo(stream);
}
}
void LInstruction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
for (int i = 0; i < InputCount(); i++) {
if (i > 0) stream->Add(" ");
if (InputAt(i) == NULL) {
stream->Add("NULL");
} else {
InputAt(i)->PrintTo(stream);
}
}
}
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
if (HasResult()) result()->PrintTo(stream);
}
void LLabel::PrintDataTo(StringStream* stream) {
LGap::PrintDataTo(stream);
LLabel* rep = replacement();
if (rep != NULL) {
stream->Add(" Dead block replaced with B%d", rep->block_id());
}
}
bool LGap::IsRedundant() const {
for (int i = 0; i < 4; i++) {
if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
return false;
}
}
return true;
}
void LGap::PrintDataTo(StringStream* stream) {
for (int i = 0; i < 4; i++) {
stream->Add("(");
if (parallel_moves_[i] != NULL) {
parallel_moves_[i]->PrintDataTo(stream);
}
stream->Add(") ");
}
}
const char* LArithmeticD::Mnemonic() const {
switch (op()) {
case Token::ADD:
return "add-d";
case Token::SUB:
return "sub-d";
case Token::MUL:
return "mul-d";
case Token::DIV:
return "div-d";
case Token::MOD:
return "mod-d";
default:
UNREACHABLE();
return NULL;
}
}
const char* LArithmeticT::Mnemonic() const {
switch (op()) {
case Token::ADD:
return "add-t";
case Token::SUB:
return "sub-t";
case Token::MUL:
return "mul-t";
case Token::MOD:
return "mod-t";
case Token::DIV:
return "div-t";
case Token::BIT_AND:
return "bit-and-t";
case Token::BIT_OR:
return "bit-or-t";
case Token::BIT_XOR:
return "bit-xor-t";
case Token::ROR:
return "ror-t";
case Token::SHL:
return "shl-t";
case Token::SAR:
return "sar-t";
case Token::SHR:
return "shr-t";
default:
UNREACHABLE();
return NULL;
}
}
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
return !gen->IsNextEmittedBlock(block_id());
}
void LGoto::PrintDataTo(StringStream* stream) {
stream->Add("B%d", block_id());
}
void LBranch::PrintDataTo(StringStream* stream) {
stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
value()->PrintTo(stream);
}
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
left()->PrintTo(stream);
stream->Add(" %s ", Token::String(op()));
right()->PrintTo(stream);
stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_string(");
value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_undetectable(");
value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if string_compare(");
left()->PrintTo(stream);
right()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_cached_array_index(");
value()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if class_of_test(");
value()->PrintTo(stream);
stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(),
true_block_id(), false_block_id());
}
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if typeof ");
value()->PrintTo(stream);
stream->Add(" == \"%s\" then B%d else B%d",
hydrogen()->type_literal()->ToCString().get(), true_block_id(),
false_block_id());
}
void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
stream->Add(" = ");
function()->PrintTo(stream);
stream->Add(".code_entry = ");
code_object()->PrintTo(stream);
}
void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
stream->Add(" = ");
base_object()->PrintTo(stream);
stream->Add(" + ");
offset()->PrintTo(stream);
}
void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
for (int i = 0; i < InputCount(); i++) {
InputAt(i)->PrintTo(stream);
stream->Add(" ");
}
stream->Add("#%d / ", arity());
}
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
}
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d] <- ", slot_index());
value()->PrintTo(stream);
}
void LInvokeFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
ElementsKind kind = hydrogen()->elements_kind();
stream->Add(" (%s) ", ElementsKindToString(kind));
}
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream);
stream->Add(" length ");
length()->PrintTo(stream);
stream->Add(" index ");
index()->PrintTo(stream);
}
void LStoreNamedField::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
std::ostringstream os;
os << hydrogen()->access() << " <- ";
stream->Add(os.str().c_str());
value()->PrintTo(stream);
}
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add(".");
stream->Add(String::cast(*name())->ToCString().get());
stream->Add(" <- ");
value()->PrintTo(stream);
}
void LLoadKeyed::PrintDataTo(StringStream* stream) {
elements()->PrintTo(stream);
stream->Add("[");
key()->PrintTo(stream);
if (hydrogen()->IsDehoisted()) {
stream->Add(" + %d]", base_offset());
} else {
stream->Add("]");
}
}
void LStoreKeyed::PrintDataTo(StringStream* stream) {
elements()->PrintTo(stream);
stream->Add("[");
key()->PrintTo(stream);
if (hydrogen()->IsDehoisted()) {
stream->Add(" + %d] <-", base_offset());
} else {
stream->Add("] <- ");
}
if (value() == NULL) {
DCHECK(hydrogen()->IsConstantHoleStore() &&
hydrogen()->value()->representation().IsDouble());
stream->Add("<the hole(nan)>");
} else {
value()->PrintTo(stream);
}
}
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add("[");
key()->PrintTo(stream);
stream->Add("] <- ");
value()->PrintTo(stream);
}
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add(" %p -> %p", *original_map(), *transitioned_map());
}
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
// Skip a slot if for a double-width slot.
if (kind == DOUBLE_REGISTERS) current_frame_slots_++;
return current_frame_slots_++;
}
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
int index = GetNextSpillIndex(kind);
if (kind == DOUBLE_REGISTERS) {
return LDoubleStackSlot::Create(index, zone());
} else {
DCHECK(kind == GENERAL_REGISTERS);
return LStackSlot::Create(index, zone());
}
}
LPlatformChunk* LChunkBuilder::Build() {
DCHECK(is_unused());
chunk_ = new (zone()) LPlatformChunk(info(), graph());
LPhase phase("L_Building chunk", chunk_);
status_ = BUILDING;
// If compiling for OSR, reserve space for the unoptimized frame,
// which will be subsumed into this frame.
if (graph()->has_osr()) {
for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
}
}
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
for (int i = 0; i < blocks->length(); i++) {
HBasicBlock* next = NULL;
if (i < blocks->length() - 1) next = blocks->at(i + 1);
DoBasicBlock(blocks->at(i), next);
if (is_aborted()) return NULL;
}
status_ = DONE;
return chunk_;
}
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
}
LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
return new (zone())
LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
}
LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
return Use(value, ToUnallocated(fixed_register));
}
LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
return Use(value, ToUnallocated(reg));
}
LOperand* LChunkBuilder::UseRegister(HValue* value) {
return Use(value,
new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
return Use(value, new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
LUnallocated::USED_AT_START));
}
LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
return Use(value, new (zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
}
LOperand* LChunkBuilder::Use(HValue* value) {
return Use(value, new (zone()) LUnallocated(LUnallocated::NONE));
}
LOperand* LChunkBuilder::UseAtStart(HValue* value) {
return Use(value, new (zone()) LUnallocated(LUnallocated::NONE,
LUnallocated::USED_AT_START));
}
LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
return value->IsConstant()
? chunk_->DefineConstantOperand(HConstant::cast(value))
: Use(value);
}
LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
return value->IsConstant()
? chunk_->DefineConstantOperand(HConstant::cast(value))
: UseAtStart(value);
}
LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
return value->IsConstant()
? chunk_->DefineConstantOperand(HConstant::cast(value))
: UseRegister(value);
}
LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
return value->IsConstant()
? chunk_->DefineConstantOperand(HConstant::cast(value))
: UseRegisterAtStart(value);
}
LOperand* LChunkBuilder::UseConstant(HValue* value) {
return chunk_->DefineConstantOperand(HConstant::cast(value));
}
LOperand* LChunkBuilder::UseAny(HValue* value) {
return value->IsConstant()
? chunk_->DefineConstantOperand(HConstant::cast(value))
: Use(value, new (zone()) LUnallocated(LUnallocated::ANY));
}
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
if (value->EmitAtUses()) {
HInstruction* instr = HInstruction::cast(value);
VisitInstruction(instr);
}
operand->set_virtual_register(value->id());
return operand;
}
LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result) {
result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
return instr;
}
LInstruction* LChunkBuilder::DefineAsRegister(
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
LInstruction* LChunkBuilder::DefineAsSpilled(
LTemplateResultInstruction<1>* instr, int index) {
return Define(instr,
new (zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
}
LInstruction* LChunkBuilder::DefineSameAsFirst(
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new (zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
}
LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
Register reg) {
return Define(instr, ToUnallocated(reg));
}
LInstruction* LChunkBuilder::DefineFixedDouble(
LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
return Define(instr, ToUnallocated(reg));
}
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(
hydrogen_env, &argument_index_accumulator, &objects_to_materialize));
return instr;
}
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize) {
info()->MarkAsNonDeferredCalling();
#ifdef DEBUG
instr->VerifyCall();
#endif
instr->MarkAsCall();
instr = AssignPointerMap(instr);
// If instruction does not have side-effects lazy deoptimization
// after the call will try to deoptimize to the point before the call.
// Thus we still need to attach environment to this call even if
// call sequence can not deoptimize eagerly.
bool needs_environment = (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
!hinstr->HasObservableSideEffects();
if (needs_environment && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
// We can't really figure out if the environment is needed or not.
instr->environment()->set_has_been_used();
}
return instr;
}
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
DCHECK(!instr->HasPointerMap());
instr->set_pointer_map(new (zone()) LPointerMap(zone()));
return instr;
}
LUnallocated* LChunkBuilder::TempRegister() {
LUnallocated* operand =
new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
int vreg = allocator_->GetVirtualRegister();
if (!allocator_->AllocationOk()) {
Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
vreg = 0;
}
operand->set_virtual_register(vreg);
return operand;
}
LUnallocated* LChunkBuilder::TempDoubleRegister() {
LUnallocated* operand =
new (zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
int vreg = allocator_->GetVirtualRegister();
if (!allocator_->AllocationOk()) {
Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
vreg = 0;
}
operand->set_virtual_register(vreg);
return operand;
}
LOperand* LChunkBuilder::FixedTemp(Register reg) {
LUnallocated* operand = ToUnallocated(reg);
DCHECK(operand->HasFixedPolicy());
return operand;
}
LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
LUnallocated* operand = ToUnallocated(reg);
DCHECK(operand->HasFixedPolicy());
return operand;
}
LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
return new (zone()) LLabel(instr->block());
}
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
return DefineAsRegister(new (zone()) LDummyUse(UseAny(instr->value())));
}
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
UNREACHABLE();
return NULL;
}
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
return AssignEnvironment(new (zone()) LDeoptimize);
}
LInstruction* LChunkBuilder::DoShift(Token::Value op,
HBitwiseBinaryOperation* instr) {
if (instr->representation().IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
HValue* right_value = instr->right();
LOperand* right = NULL;
int constant_value = 0;
bool does_deopt = false;
if (right_value->IsConstant()) {
HConstant* constant = HConstant::cast(right_value);
right = chunk_->DefineConstantOperand(constant);
constant_value = constant->Integer32Value() & 0x1f;
// Left shifts can deoptimize if we shift by > 0 and the result cannot be
// truncated to smi.
if (instr->representation().IsSmi() && constant_value > 0) {
does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
}
} else {
right = UseRegisterAtStart(right_value);
}
// Shift operations can only deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32.
if (op == Token::SHR && constant_value == 0) {
does_deopt = !instr->CheckFlag(HInstruction::kUint32);
}
LInstruction* result =
DefineAsRegister(new (zone()) LShiftI(op, left, right, does_deopt));
return does_deopt ? AssignEnvironment(result) : result;
} else {
return DoArithmeticT(op, instr);
}
}
LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
HArithmeticBinaryOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->left()->representation().IsDouble());
DCHECK(instr->right()->representation().IsDouble());
if (op == Token::MOD) {
LOperand* left = UseFixedDouble(instr->left(), d1);
LOperand* right = UseFixedDouble(instr->right(), d2);
LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
// We call a C function for double modulo. It can't trigger a GC. We need
// to use fixed result register for the call.
// TODO(fschneider): Allow any register as input registers.
return MarkAsCall(DefineFixedDouble(result, d1), instr);
} else {
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
return DefineSameAsFirst(result);
}
}
LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
HBinaryOperation* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
DCHECK(left->representation().IsTagged());
DCHECK(right->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), cp);
LOperand* left_operand = UseFixed(left, r3);
LOperand* right_operand = UseFixed(right, r2);
LArithmeticT* result =
new (zone()) LArithmeticT(op, context, left_operand, right_operand);
return MarkAsCall(DefineFixed(result, r2), instr);
}
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
DCHECK(is_building());
current_block_ = block;
next_block_ = next_block;
if (block->IsStartBlock()) {
block->UpdateEnvironment(graph_->start_environment());
argument_count_ = 0;
} else if (block->predecessors()->length() == 1) {
// We have a single predecessor => copy environment and outgoing
// argument count from the predecessor.
DCHECK(block->phis()->length() == 0);
HBasicBlock* pred = block->predecessors()->at(0);
HEnvironment* last_environment = pred->last_environment();
DCHECK(last_environment != NULL);
// Only copy the environment, if it is later used again.
if (pred->end()->SecondSuccessor() == NULL) {
DCHECK(pred->end()->FirstSuccessor() == block);
} else {
if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
last_environment = last_environment->Copy();
}
}
block->UpdateEnvironment(last_environment);
DCHECK(pred->argument_count() >= 0);
argument_count_ = pred->argument_count();
} else {
// We are at a state join => process phis.
HBasicBlock* pred = block->predecessors()->at(0);
// No need to copy the environment, it cannot be used later.
HEnvironment* last_environment = pred->last_environment();
for (int i = 0; i < block->phis()->length(); ++i) {
HPhi* phi = block->phis()->at(i);
if (phi->HasMergedIndex()) {
last_environment->SetValueAt(phi->merged_index(), phi);
}
}
for (int i = 0; i < block->deleted_phis()->length(); ++i) {
if (block->deleted_phis()->at(i) < last_environment->length()) {
last_environment->SetValueAt(block->deleted_phis()->at(i),
graph_->GetConstantUndefined());
}
}
block->UpdateEnvironment(last_environment);
// Pick up the outgoing argument count of one of the predecessors.
argument_count_ = pred->argument_count();
}
HInstruction* current = block->first();
int start = chunk_->instructions()->length();
while (current != NULL && !is_aborted()) {
// Code for constants in registers is generated lazily.
if (!current->EmitAtUses()) {
VisitInstruction(current);
}
current = current->next();
}
int end = chunk_->instructions()->length() - 1;
if (end >= start) {
block->set_first_instruction_index(start);
block->set_last_instruction_index(end);
}
block->set_argument_count(argument_count_);
next_block_ = NULL;
current_block_ = NULL;
}
void LChunkBuilder::VisitInstruction(HInstruction* current) {
HInstruction* old_current = current_instruction_;
current_instruction_ = current;
LInstruction* instr = NULL;
if (current->CanReplaceWithDummyUses()) {
if (current->OperandCount() == 0) {
instr = DefineAsRegister(new (zone()) LDummy());
} else {
DCHECK(!current->OperandAt(0)->IsControlInstruction());
instr = DefineAsRegister(new (zone())
LDummyUse(UseAny(current->OperandAt(0))));
}
for (int i = 1; i < current->OperandCount(); ++i) {
if (current->OperandAt(i)->IsControlInstruction()) continue;
LInstruction* dummy =
new (zone()) LDummyUse(UseAny(current->OperandAt(i)));
dummy->set_hydrogen_value(current);
chunk_->AddInstruction(dummy, current_block_);
}
} else {
HBasicBlock* successor;
if (current->IsControlInstruction() &&
HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
successor != NULL) {
instr = new (zone()) LGoto(successor);
} else {
instr = current->CompileToLithium(this);
}
}
argument_count_ += current->argument_delta();
DCHECK(argument_count_ >= 0);
if (instr != NULL) {
AddInstruction(instr, current);
}
current_instruction_ = old_current;
}
void LChunkBuilder::AddInstruction(LInstruction* instr,
HInstruction* hydrogen_val) {
// Associate the hydrogen instruction first, since we may need it for
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
instr->set_hydrogen_value(hydrogen_val);
#if DEBUG
// Make sure that the lithium instruction has either no fixed register
// constraints in temps or the result OR no uses that are only used at
// start. If this invariant doesn't hold, the register allocator can decide
// to insert a split of a range immediately before the instruction due to an
// already allocated register needing to be used for the instruction's fixed
// register constraint. In this case, The register allocator won't see an
// interference between the split child and the use-at-start (it would if
// the it was just a plain use), so it is free to move the split child into
// the same register that is used for the use-at-start.
// See https://code.google.com/p/chromium/issues/detail?id=201590
if (!(instr->ClobbersRegisters() &&
instr->ClobbersDoubleRegisters(isolate()))) {
int fixed = 0;
int used_at_start = 0;
for (UseIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->IsUsedAtStart()) ++used_at_start;
}
if (instr->Output() != NULL) {
if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
}
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
DCHECK(fixed == 0 || used_at_start == 0);
}
#endif
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr);
}
if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall() || instr->IsPrologue()) {
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new (zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
}
LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
return new (zone()) LPrologue();
}
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
return new (zone()) LGoto(instr->FirstSuccessor());
}
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LInstruction* branch = new (zone()) LBranch(UseRegister(value));
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}
return branch;
}
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
return new (zone()) LDebugBreak();
}
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
DCHECK(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value());
LOperand* temp = TempRegister();
return new (zone()) LCmpMapAndBranch(value, temp);
}
LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
info()->MarkAsRequiresFrame();
LOperand* value = UseRegister(instr->value());
return DefineAsRegister(new (zone()) LArgumentsLength(value));
}
LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
info()->MarkAsRequiresFrame();
return DefineAsRegister(new (zone()) LArgumentsElements);
}
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
LOperand* left =
UseFixed(instr->left(), InstanceOfDescriptor::LeftRegister());
LOperand* right =
UseFixed(instr->right(), InstanceOfDescriptor::RightRegister());
LOperand* context = UseFixed(instr->context(), cp);
LInstanceOf* result = new (zone()) LInstanceOf(context, left, right);
return MarkAsCall(DefineFixed(result, r2), instr);
}
LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
HHasInPrototypeChainAndBranch* instr) {
LOperand* object = UseRegister(instr->object());
LOperand* prototype = UseRegister(instr->prototype());
LHasInPrototypeChainAndBranch* result =
new (zone()) LHasInPrototypeChainAndBranch(object, prototype);
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
LOperand* receiver = UseRegisterAtStart(instr->receiver());
LOperand* function = UseRegisterAtStart(instr->function());
LWrapReceiver* result = new (zone()) LWrapReceiver(receiver, function);
return AssignEnvironment(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
LOperand* function = UseFixed(instr->function(), r3);
LOperand* receiver = UseFixed(instr->receiver(), r2);
LOperand* length = UseFixed(instr->length(), r4);
LOperand* elements = UseFixed(instr->elements(), r5);
LApplyArguments* result =
new (zone()) LApplyArguments(function, receiver, length, elements);
return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
}
LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
int argc = instr->OperandCount();
for (int i = 0; i < argc; ++i) {
LOperand* argument = Use(instr->argument(i));
AddInstruction(new (zone()) LPushArgument(argument), instr);
}
return NULL;
}
LInstruction* LChunkBuilder::DoStoreCodeEntry(
HStoreCodeEntry* store_code_entry) {
LOperand* function = UseRegister(store_code_entry->function());
LOperand* code_object = UseTempRegister(store_code_entry->code_object());
return new (zone()) LStoreCodeEntry(function, code_object);
}
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
HInnerAllocatedObject* instr) {
LOperand* base_object = UseRegisterAtStart(instr->base_object());
LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
return DefineAsRegister(new (zone())
LInnerAllocatedObject(base_object, offset));
}
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
return instr->HasNoUses() ? NULL
: DefineAsRegister(new (zone()) LThisFunction);
}
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
if (instr->HasNoUses()) return NULL;
if (info()->IsStub()) {
return DefineFixed(new (zone()) LContext, cp);
}
return DefineAsRegister(new (zone()) LContext);
}
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
LOperand* context = UseFixed(instr->context(), cp);
return MarkAsCall(new (zone()) LDeclareGlobals(context), instr);
}
LInstruction* LChunkBuilder::DoCallWithDescriptor(HCallWithDescriptor* instr) {
CallInterfaceDescriptor descriptor = instr->descriptor();
LOperand* target = UseRegisterOrConstantAtStart(instr->target());
ZoneList<LOperand*> ops(instr->OperandCount(), zone());
// Target
ops.Add(target, zone());
// Context
LOperand* op = UseFixed(instr->OperandAt(1), cp);
ops.Add(op, zone());
// Other register parameters
for (int i = LCallWithDescriptor::kImplicitRegisterParameterCount;
i < instr->OperandCount(); i++) {
op =
UseFixed(instr->OperandAt(i),
descriptor.GetRegisterParameter(
i - LCallWithDescriptor::kImplicitRegisterParameterCount));
ops.Add(op, zone());
}
LCallWithDescriptor* result =
new (zone()) LCallWithDescriptor(descriptor, ops, zone());
return MarkAsCall(DefineFixed(result, r2), instr);
}
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), r3);
LInvokeFunction* result = new (zone()) LInvokeFunction(context, function);
return MarkAsCall(DefineFixed(result, r2), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
switch (instr->op()) {
case kMathFloor:
return DoMathFloor(instr);
case kMathRound:
return DoMathRound(instr);
case kMathFround:
return DoMathFround(instr);
case kMathAbs:
return DoMathAbs(instr);
case kMathLog:
return DoMathLog(instr);
case kMathExp:
return DoMathExp(instr);
case kMathSqrt:
return DoMathSqrt(instr);
case kMathPowHalf:
return DoMathPowHalf(instr);
case kMathClz32:
return DoMathClz32(instr);
default:
UNREACHABLE();
return NULL;
}
}
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
LOperand* input = UseRegister(instr->value());
LMathFloor* result = new (zone()) LMathFloor(input);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
LOperand* input = UseRegister(instr->value());
LOperand* temp = TempDoubleRegister();
LMathRound* result = new (zone()) LMathRound(input, temp);
return AssignEnvironment(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
LOperand* input = UseRegister(instr->value());
LMathFround* result = new (zone()) LMathFround(input);
return DefineAsRegister(result);
}
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
Representation r = instr->value()->representation();
LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
? NULL
: UseFixed(instr->context(), cp);
LOperand* input = UseRegister(instr->value());
LInstruction* result =
DefineAsRegister(new (zone()) LMathAbs(context, input));
if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
if (!r.IsDouble()) result = AssignEnvironment(result);
return result;
}
LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseFixedDouble(instr->value(), d1);
return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), d1), instr);
}
LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
LMathClz32* result = new (zone()) LMathClz32(input);
return DefineAsRegister(result);
}
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* double_temp = TempDoubleRegister();
LMathExp* result = new (zone()) LMathExp(input, double_temp, temp1, temp2);
return DefineAsRegister(result);
}
LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
LMathSqrt* result = new (zone()) LMathSqrt(input);
return DefineAsRegister(result);
}
LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
LMathPowHalf* result = new (zone()) LMathPowHalf(input);
return DefineAsRegister(result);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), r3);
LCallNewArray* result = new (zone()) LCallNewArray(context, constructor);
return MarkAsCall(DefineFixed(result, r2), instr);
}
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
LOperand* context = UseFixed(instr->context(), cp);
return MarkAsCall(DefineFixed(new (zone()) LCallRuntime(context), r2), instr);
}
LInstruction* LChunkBuilder::DoRor(HRor* instr) {
return DoShift(Token::ROR, instr);
}
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
return DoShift(Token::SHR, instr);
}
LInstruction* LChunkBuilder::DoSar(HSar* instr) {
return DoShift(Token::SAR, instr);
}
LInstruction* LChunkBuilder::DoShl(HShl* instr) {
return DoShift(Token::SHL, instr);
}
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
if (instr->representation().IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
return DefineAsRegister(new (zone()) LBitI(left, right));
} else {
return DoArithmeticT(instr->op(), instr);
}
}
LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
DCHECK(instr->representation().IsSmiOrInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineAsRegister(new (zone()) LDivByPowerOf2I(dividend, divisor));
if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
(!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
divisor != 1 && divisor != -1)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
DCHECK(instr->representation().IsInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineAsRegister(new (zone()) LDivByConstI(dividend, divisor));
if (divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
DCHECK(instr->representation().IsSmiOrInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LInstruction* result =
DefineAsRegister(new (zone()) LDivI(dividend, divisor));
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
(instr->CheckFlag(HValue::kCanOverflow) &&
!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) ||
(!instr->IsMathFloorOfDiv() &&
!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
if (instr->RightIsPowerOf2()) {
return DoDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoDivByConstI(instr);
} else {
return DoDivI(instr);
}
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
} else {
return DoArithmeticT(Token::DIV, instr);
}
}
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineAsRegister(new (zone()) LFlooringDivByPowerOf2I(dividend, divisor));
if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
DCHECK(instr->representation().IsInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LOperand* temp =
((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
(divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive)))
? NULL
: TempRegister();
LInstruction* result = DefineAsRegister(
new (zone()) LFlooringDivByConstI(dividend, divisor, temp));
if (divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
DCHECK(instr->representation().IsSmiOrInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LInstruction* result =
DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
(instr->CheckFlag(HValue::kCanOverflow) &&
!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
return DoFlooringDivI(instr);
}
}
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
DCHECK(instr->representation().IsSmiOrInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineSameAsFirst(new (zone()) LModByPowerOf2I(dividend, divisor));
if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
DCHECK(instr->representation().IsSmiOrInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineAsRegister(new (zone()) LModByConstI(dividend, divisor));
if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
DCHECK(instr->representation().IsSmiOrInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LInstruction* result =
DefineAsRegister(new (zone()) LModI(dividend, divisor));
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsSmiOrInteger32()) {
if (instr->RightIsPowerOf2()) {
return DoModByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoModByConstI(instr);
} else {
return DoModI(instr);
}
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {
return DoArithmeticT(Token::MOD, instr);
}
}
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
if (instr->representation().IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
HValue* left = instr->BetterLeftOperand();
HValue* right = instr->BetterRightOperand();
LOperand* left_op;
LOperand* right_op;
bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
int32_t constant_value = 0;
if (right->IsConstant()) {
HConstant* constant = HConstant::cast(right);
constant_value = constant->Integer32Value();
// Constants -1, 0 and 1 can be optimized if the result can overflow.
// For other constants, it can be optimized only without overflow.
if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
left_op = UseRegisterAtStart(left);
right_op = UseConstant(right);
} else {
if (bailout_on_minus_zero) {
left_op = UseRegister(left);
} else {
left_op = UseRegisterAtStart(left);
}
right_op = UseRegister(right);
}
} else {
if (bailout_on_minus_zero) {
left_op = UseRegister(left);
} else {
left_op = UseRegisterAtStart(left);
}
right_op = UseRegister(right);
}
LMulI* mul = new (zone()) LMulI(left_op, right_op);
if (right_op->IsConstantOperand()
? ((can_overflow && constant_value == -1) ||
(bailout_on_minus_zero && constant_value <= 0))
: (can_overflow || bailout_on_minus_zero)) {
AssignEnvironment(mul);
}
return DefineAsRegister(mul);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MUL, instr);
} else {
return DoArithmeticT(Token::MUL, instr);
}
}
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
if (instr->representation().IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
if (instr->left()->IsConstant() &&
!instr->CheckFlag(HValue::kCanOverflow)) {
// If lhs is constant, do reverse subtraction instead.
return DoRSub(instr);
}
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
LSubI* sub = new (zone()) LSubI(left, right);
LInstruction* result = DefineAsRegister(sub);
if (instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
return result;
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::SUB, instr);
} else {
return DoArithmeticT(Token::SUB, instr);
}
}
LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
DCHECK(instr->representation().IsSmiOrInteger32());
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
// Note: The lhs of the subtraction becomes the rhs of the
// reverse-subtraction.
LOperand* left = UseRegisterAtStart(instr->right());
LOperand* right = UseOrConstantAtStart(instr->left());
LRSubI* rsb = new (zone()) LRSubI(left, right);
LInstruction* result = DefineAsRegister(rsb);
return result;
}
LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
LOperand* multiplier_op = UseRegister(mul->left());
LOperand* multiplicand_op = UseRegister(mul->right());
LOperand* addend_op = UseRegister(addend);
return DefineAsRegister(
new (zone()) LMultiplyAddD(addend_op, multiplier_op, multiplicand_op));
}
LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
LOperand* minuend_op = UseRegister(minuend);
LOperand* multiplier_op = UseRegister(mul->left());
LOperand* multiplicand_op = UseRegister(mul->right());
return DefineAsRegister(
new (zone()) LMultiplySubD(minuend_op, multiplier_op, multiplicand_op));
}
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
if (instr->representation().IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
LAddI* add = new (zone()) LAddI(left, right);
LInstruction* result = DefineAsRegister(add);
if (instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
return result;
} else if (instr->representation().IsExternal()) {
DCHECK(instr->IsConsistentExternalRepresentation());
DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
LAddI* add = new (zone()) LAddI(left, right);
LInstruction* result = DefineAsRegister(add);
return result;
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::ADD, instr);
} else {
return DoArithmeticT(Token::ADD, instr);
}
}
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
LOperand* left = NULL;
LOperand* right = NULL;
if (instr->representation().IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
left = UseRegisterAtStart(instr->BetterLeftOperand());
right = UseOrConstantAtStart(instr->BetterRightOperand());
} else {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->left()->representation().IsDouble());
DCHECK(instr->right()->representation().IsDouble());
left = UseRegister(instr->left());
right = UseRegister(instr->right());
}
return DefineAsRegister(new (zone()) LMathMinMax(left, right));
}
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
DCHECK(instr->representation().IsDouble());
// We call a C function for double power. It can't trigger a GC.
// We need to use fixed result register for the call.
Representation exponent_type = instr->right()->representation();
DCHECK(instr->left()->representation().IsDouble());
LOperand* left = UseFixedDouble(instr->left(), d1);
LOperand* right = exponent_type.IsDouble()
? UseFixedDouble(instr->right(), d2)
: UseFixed(instr->right(), r4);
LPower* result = new (zone()) LPower(left, right);
return MarkAsCall(DefineFixedDouble(result, d3), instr,
CAN_DEOPTIMIZE_EAGERLY);
}
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
DCHECK(instr->left()->representation().IsTagged());
DCHECK(instr->right()->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), cp);
LOperand* left = UseFixed(instr->left(), r3);
LOperand* right = UseFixed(instr->right(), r2);
LCmpT* result = new (zone()) LCmpT(context, left, right);
return MarkAsCall(DefineFixed(result, r2), instr);
}
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
HCompareNumericAndBranch* instr) {
Representation r = instr->representation();
if (r.IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(r));
DCHECK(instr->right()->representation().Equals(r));
LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseRegisterOrConstantAtStart(instr->right());
return new (zone()) LCompareNumericAndBranch(left, right);
} else {
DCHECK(r.IsDouble());
DCHECK(instr->left()->representation().IsDouble());
DCHECK(instr->right()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
return new (zone()) LCompareNumericAndBranch(left, right);
}
}
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
HCompareObjectEqAndBranch* instr) {
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
return new (zone()) LCmpObjectEqAndBranch(left, right);
}
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
HCompareHoleAndBranch* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
return new (zone()) LCmpHoleAndBranch(value);
}
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
DCHECK(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* temp = TempRegister();
return new (zone()) LIsStringAndBranch(value, temp);
}
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
DCHECK(instr->value()->representation().IsTagged());
return new (zone()) LIsSmiAndBranch(Use(instr->value()));
}
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
HIsUndetectableAndBranch* instr) {
DCHECK(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
return new (zone()) LIsUndetectableAndBranch(value, TempRegister());
}
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
HStringCompareAndBranch* instr) {
DCHECK(instr->left()->representation().IsTagged());
DCHECK(instr->right()->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), cp);
LOperand* left = UseFixed(instr->left(), r3);
LOperand* right = UseFixed(instr->right(), r2);
LStringCompareAndBranch* result =
new (zone()) LStringCompareAndBranch(context, left, right);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
DCHECK(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
return new (zone()) LHasInstanceTypeAndBranch(value);
}
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
HGetCachedArrayIndex* instr) {
DCHECK(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
return DefineAsRegister(new (zone()) LGetCachedArrayIndex(value));
}
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
HHasCachedArrayIndexAndBranch* instr) {
DCHECK(instr->value()->representation().IsTagged());
return new (zone())
LHasCachedArrayIndexAndBranch(UseRegisterAtStart(instr->value()));
}
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
HClassOfTestAndBranch* instr) {
DCHECK(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value());
return new (zone()) LClassOfTestAndBranch(value, TempRegister());
}
LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
LOperand* string = UseRegisterAtStart(instr->string());
LOperand* index = UseRegisterOrConstantAtStart(instr->index());
return DefineAsRegister(new (zone()) LSeqStringGetChar(string, index));
}
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegisterAtStart(instr->string());
LOperand* index = FLAG_debug_code
? UseRegisterAtStart(instr->index())
: UseRegisterOrConstantAtStart(instr->index());
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
return new (zone()) LSeqStringSetChar(context, string, index, value);
}
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
if (!FLAG_debug_code && instr->skip_check()) return NULL;
LOperand* index = UseRegisterOrConstantAtStart(instr->index());
LOperand* length = !index->IsConstantOperand()
? UseRegisterOrConstantAtStart(instr->length())
: UseRegisterAtStart(instr->length());
LInstruction* result = new (zone()) LBoundsCheck(index, length);
if (!FLAG_debug_code || !instr->skip_check()) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
HBoundsCheckBaseIndexInformation* instr) {
UNREACHABLE();
return NULL;
}
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
// The control instruction marking the end of a block that completed
// abruptly (e.g., threw an exception). There is nothing specific to do.
return NULL;
}
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { return NULL; }
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
// All HForceRepresentation instructions should be eliminated in the
// representation change phase of Hydrogen.
UNREACHABLE();
return NULL;
}
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
Representation from = instr->from();
Representation to = instr->to();
HValue* val = instr->value();
if (from.IsSmi()) {
if (to.IsTagged()) {
LOperand* value = UseRegister(val);
return DefineSameAsFirst(new (zone()) LDummyUse(value));
}
from = Representation::Tagged();
}
if (from.IsTagged()) {
if (to.IsDouble()) {
LOperand* value = UseRegister(val);
LInstruction* result =
DefineAsRegister(new (zone()) LNumberUntagD(value));
if (!val->representation().IsSmi()) result = AssignEnvironment(result);
return result;
} else if (to.IsSmi()) {
LOperand* value = UseRegister(val);
if (val->type().IsSmi()) {
return DefineSameAsFirst(new (zone()) LDummyUse(value));
}
return AssignEnvironment(
DefineSameAsFirst(new (zone()) LCheckSmi(value)));
} else {
DCHECK(to.IsInteger32());
if (val->type().IsSmi() || val->representation().IsSmi()) {
LOperand* value = UseRegisterAtStart(val);
return DefineAsRegister(new (zone()) LSmiUntag(value, false));
} else {
LOperand* value = UseRegister(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempDoubleRegister();
LInstruction* result =
DefineSameAsFirst(new (zone()) LTaggedToI(value, temp1, temp2));
if (!val->representation().IsSmi()) result = AssignEnvironment(result);
return result;
}
}
} else if (from.IsDouble()) {
if (to.IsTagged()) {
info()->MarkAsDeferredCalling();
LOperand* value = UseRegister(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LUnallocated* result_temp = TempRegister();
LNumberTagD* result = new (zone()) LNumberTagD(value, temp1, temp2);
return AssignPointerMap(Define(result, result_temp));
} else if (to.IsSmi()) {
LOperand* value = UseRegister(val);
return AssignEnvironment(
DefineAsRegister(new (zone()) LDoubleToSmi(value)));
} else {
DCHECK(to.IsInteger32());
LOperand* value = UseRegister(val);
LInstruction* result = DefineAsRegister(new (zone()) LDoubleToI(value));
if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
return result;
}
} else if (from.IsInteger32()) {
info()->MarkAsDeferredCalling();
if (to.IsTagged()) {
if (!instr->CheckFlag(HValue::kCanOverflow)) {
LOperand* value = UseRegisterAtStart(val);
return DefineAsRegister(new (zone()) LSmiTag(value));
} else if (val->CheckFlag(HInstruction::kUint32)) {
LOperand* value = UseRegisterAtStart(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LNumberTagU* result = new (zone()) LNumberTagU(value, temp1, temp2);
return AssignPointerMap(DefineAsRegister(result));
} else {
LOperand* value = UseRegisterAtStart(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LNumberTagI* result = new (zone()) LNumberTagI(value, temp1, temp2);
return AssignPointerMap(DefineAsRegister(result));
}
} else if (to.IsSmi()) {
LOperand* value = UseRegister(val);
LInstruction* result = DefineAsRegister(new (zone()) LSmiTag(value));
if (instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
return result;
} else {
DCHECK(to.IsDouble());
if (val->CheckFlag(HInstruction::kUint32)) {
return DefineAsRegister(new (zone()) LUint32ToDouble(UseRegister(val)));
} else {
return DefineAsRegister(new (zone()) LInteger32ToDouble(Use(val)));
}
}
}
UNREACHABLE();
return NULL;
}
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LInstruction* result = new (zone()) LCheckNonSmi(value);
if (!instr->value()->type().IsHeapObject()) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
return AssignEnvironment(new (zone()) LCheckSmi(value));
}
LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
HCheckArrayBufferNotNeutered* instr) {
LOperand* view = UseRegisterAtStart(instr->value());
LCheckArrayBufferNotNeutered* result =
new (zone()) LCheckArrayBufferNotNeutered(view);
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LInstruction* result = new (zone()) LCheckInstanceType(value);
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
return AssignEnvironment(new (zone()) LCheckValue(value));
}
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
if (instr->IsStabilityCheck()) return new (zone()) LCheckMaps;
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* temp = TempRegister();
LInstruction* result =
AssignEnvironment(new (zone()) LCheckMaps(value, temp));
if (instr->HasMigrationTarget()) {
info()->MarkAsDeferredCalling();
result = AssignPointerMap(result);
}
return result;
}
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
HValue* value = instr->value();
Representation input_rep = value->representation();
LOperand* reg = UseRegister(value);
if (input_rep.IsDouble()) {
return DefineAsRegister(new (zone()) LClampDToUint8(reg));
} else if (input_rep.IsInteger32()) {
return DefineAsRegister(new (zone()) LClampIToUint8(reg));
} else {
DCHECK(input_rep.IsSmiOrTagged());
LClampTToUint8* result =
new (zone()) LClampTToUint8(reg, TempDoubleRegister());
return AssignEnvironment(DefineAsRegister(result));
}
}
LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) {
HValue* value = instr->value();
DCHECK(value->representation().IsDouble());
return DefineAsRegister(new (zone()) LDoubleBits(UseRegister(value)));
}
LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) {
LOperand* lo = UseRegister(instr->lo());
LOperand* hi = UseRegister(instr->hi());
return DefineAsRegister(new (zone()) LConstructDouble(hi, lo));
}
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) : NULL;
LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
return new (zone())
LReturn(UseFixed(instr->value(), r2), context, parameter_count);
}
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
Representation r = instr->representation();
if (r.IsSmi()) {
return DefineAsRegister(new (zone()) LConstantS);
} else if (r.IsInteger32()) {
return DefineAsRegister(new (zone()) LConstantI);
} else if (r.IsDouble()) {
return DefineAsRegister(new (zone()) LConstantD);
} else if (r.IsExternal()) {
return DefineAsRegister(new (zone()) LConstantE);
} else if (r.IsTagged()) {
return DefineAsRegister(new (zone()) LConstantT);
} else {
UNREACHABLE();
return NULL;
}
}
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* global_object =
UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
LOperand* vector = NULL;
if (instr->HasVectorAndSlot()) {
vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
}
LLoadGlobalGeneric* result =
new (zone()) LLoadGlobalGeneric(context, global_object, vector);
return MarkAsCall(DefineFixed(result, r2), instr);
}
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
LInstruction* result =
DefineAsRegister(new (zone()) LLoadContextSlot(context));
if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
LOperand* context;
LOperand* value;
if (instr->NeedsWriteBarrier()) {
context = UseTempRegister(instr->context());
value = UseTempRegister(instr->value());
} else {
context = UseRegister(instr->context());
value = UseRegister(instr->value());
}
LInstruction* result = new (zone()) LStoreContextSlot(context, value);
if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
LOperand* obj = UseRegisterAtStart(instr->object());
return DefineAsRegister(new (zone()) LLoadNamedField(obj));
}
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* object =
UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
LOperand* vector = NULL;
if (instr->HasVectorAndSlot()) {
vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
}
LInstruction* result =
DefineFixed(new (zone()) LLoadNamedGeneric(context, object, vector), r2);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
HLoadFunctionPrototype* instr) {
return AssignEnvironment(DefineAsRegister(
new (zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
}
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
return DefineAsRegister(new (zone()) LLoadRoot);
}
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
DCHECK(instr->key()->representation().IsSmiOrInteger32());
ElementsKind elements_kind = instr->elements_kind();
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LInstruction* result = NULL;
if (!instr->is_fixed_typed_array()) {
LOperand* obj = NULL;
if (instr->representation().IsDouble()) {
obj = UseRegister(instr->elements());
} else {
obj = UseRegisterAtStart(instr->elements());
}
result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
} else {
DCHECK((instr->representation().IsInteger32() &&
!IsDoubleOrFloatElementsKind(elements_kind)) ||
(instr->representation().IsDouble() &&
IsDoubleOrFloatElementsKind(elements_kind)));
LOperand* backing_store = UseRegister(instr->elements());
LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
result = DefineAsRegister(
new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
}
bool needs_environment;
if (instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
needs_environment = elements_kind == UINT32_ELEMENTS &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
// LCodeGen::DoLoadKeyedFixedArray
needs_environment =
instr->RequiresHoleCheck() ||
(instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
}
if (needs_environment) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* object =
UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
LOperand* vector = NULL;
if (instr->HasVectorAndSlot()) {
vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
}
LInstruction* result = DefineFixed(
new (zone()) LLoadKeyedGeneric(context, object, key, vector), r2);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
if (!instr->is_fixed_typed_array()) {
DCHECK(instr->elements()->representation().IsTagged());
bool needs_write_barrier = instr->NeedsWriteBarrier();
LOperand* object = NULL;
LOperand* key = NULL;
LOperand* val = NULL;
if (instr->value()->representation().IsDouble()) {
object = UseRegisterAtStart(instr->elements());
val = UseRegister(instr->value());
key = UseRegisterOrConstantAtStart(instr->key());
} else {
if (needs_write_barrier) {
object = UseTempRegister(instr->elements());
val = UseTempRegister(instr->value());
key = UseTempRegister(instr->key());
} else {
object = UseRegisterAtStart(instr->elements());
val = UseRegisterAtStart(instr->value());
key = UseRegisterOrConstantAtStart(instr->key());
}
}
return new (zone()) LStoreKeyed(object, key, val, nullptr);
}
DCHECK((instr->value()->representation().IsInteger32() &&
!IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
(instr->value()->representation().IsDouble() &&
IsDoubleOrFloatElementsKind(instr->elements_kind())));
DCHECK(instr->elements()->representation().IsExternal());
LOperand* val = UseRegister(instr->value());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LOperand* backing_store = UseRegister(instr->elements());
LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
}
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* obj =
UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
LOperand* key = UseFixed(instr->key(), StoreDescriptor::NameRegister());
LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
DCHECK(instr->object()->representation().IsTagged());
DCHECK(instr->key()->representation().IsTagged());
DCHECK(instr->value()->representation().IsTagged());
LOperand* slot = NULL;
LOperand* vector = NULL;
if (instr->HasVectorAndSlot()) {
slot = FixedTemp(VectorStoreICDescriptor::SlotRegister());
vector = FixedTemp(VectorStoreICDescriptor::VectorRegister());
}
LStoreKeyedGeneric* result =
new (zone()) LStoreKeyedGeneric(context, obj, key, val, slot, vector);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoTransitionElementsKind(
HTransitionElementsKind* instr) {
if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
LOperand* object = UseRegister(instr->object());
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
new (zone()) LTransitionElementsKind(object, NULL, new_map_reg);
return result;
} else {
LOperand* object = UseFixed(instr->object(), r2);
LOperand* context = UseFixed(instr->context(), cp);
LTransitionElementsKind* result =
new (zone()) LTransitionElementsKind(object, context, NULL);
return MarkAsCall(result, instr);
}
}
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
HTrapAllocationMemento* instr) {
LOperand* object = UseRegister(instr->object());
LOperand* temp = TempRegister();
LTrapAllocationMemento* result =
new (zone()) LTrapAllocationMemento(object, temp);
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
info()->MarkAsDeferredCalling();
LOperand* context = UseFixed(instr->context(), cp);
LOperand* object = Use(instr->object());
LOperand* elements = Use(instr->elements());
LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
LMaybeGrowElements* result = new (zone())
LMaybeGrowElements(context, object, elements, key, current_capacity);
DefineFixed(result, r2);
return AssignPointerMap(AssignEnvironment(result));
}
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_in_object = instr->access().IsInobject();
bool needs_write_barrier = instr->NeedsWriteBarrier();
bool needs_write_barrier_for_map =
instr->has_transition() && instr->NeedsWriteBarrierForMap();
LOperand* obj;
if (needs_write_barrier) {
obj = is_in_object ? UseRegister(instr->object())
: UseTempRegister(instr->object());
} else {
obj = needs_write_barrier_for_map ? UseRegister(instr->object())
: UseRegisterAtStart(instr->object());
}
LOperand* val;
if (needs_write_barrier) {
val = UseTempRegister(instr->value());
} else if (instr->field_representation().IsDouble()) {
val = UseRegisterAtStart(instr->value());
} else {
val = UseRegister(instr->value());
}
// We need a temporary register for write barrier of the map field.
LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
return new (zone()) LStoreNamedField(obj, val, temp);
}
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* obj =
UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
LOperand* slot = NULL;
LOperand* vector = NULL;
if (instr->HasVectorAndSlot()) {
slot = FixedTemp(VectorStoreICDescriptor::SlotRegister());
vector = FixedTemp(VectorStoreICDescriptor::VectorRegister());
}
LStoreNamedGeneric* result =
new (zone()) LStoreNamedGeneric(context, obj, val, slot, vector);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* left = UseFixed(instr->left(), r3);
LOperand* right = UseFixed(instr->right(), r2);
return MarkAsCall(
DefineFixed(new (zone()) LStringAdd(context, left, right), r2), instr);
}
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
LOperand* string = UseTempRegister(instr->string());
LOperand* index = UseTempRegister(instr->index());
LOperand* context = UseAny(instr->context());
LStringCharCodeAt* result =
new (zone()) LStringCharCodeAt(context, string, index);
return AssignPointerMap(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
LOperand* char_code = UseRegister(instr->value());
LOperand* context = UseAny(instr->context());
LStringCharFromCode* result =
new (zone()) LStringCharFromCode(context, char_code);
return AssignPointerMap(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
info()->MarkAsDeferredCalling();
LOperand* context = UseAny(instr->context());
LOperand* size = UseRegisterOrConstant(instr->size());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LAllocate* result = new (zone()) LAllocate(context, size, temp1, temp2);
return AssignPointerMap(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
DCHECK(argument_count_ == 0);
allocator_->MarkAsOsrEntry();
current_block_->last_environment()->set_ast_id(instr->ast_id());
return AssignEnvironment(new (zone()) LOsrEntry);
}
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
LParameter* result = new (zone()) LParameter;
if (instr->kind() == HParameter::STACK_PARAMETER) {
int spill_index = chunk()->GetParameterStackSlot(instr->index());
return DefineAsSpilled(result, spill_index);
} else {
DCHECK(info()->IsStub());
CallInterfaceDescriptor descriptor = graph()->descriptor();
int index = static_cast<int>(instr->index());
Register reg = descriptor.GetRegisterParameter(index);
return DefineFixed(result, reg);
}
}
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
// Use an index that corresponds to the location in the unoptimized frame,
// which the optimized frame will subsume.
int env_index = instr->index();
int spill_index = 0;
if (instr->environment()->is_parameter_index(env_index)) {
spill_index = chunk()->GetParameterStackSlot(env_index);
} else {
spill_index = env_index - instr->environment()->first_local_index();
if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
Retry(kTooManySpillSlotsNeededForOSR);
spill_index = 0;
}
spill_index += StandardFrameConstants::kFixedSlotCount;
}
return DefineAsSpilled(new (zone()) LUnknownOSRValue, spill_index);
}
LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
// There are no real uses of the arguments object.
// arguments.length and element access are supported directly on
// stack arguments, and any real arguments object use causes a bailout.
// So this value is never used.
return NULL;
}
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
instr->ReplayEnvironment(current_block_->last_environment());
// There are no real uses of a captured object.
return NULL;
}
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
info()->MarkAsRequiresFrame();
LOperand* args = UseRegister(instr->arguments());
LOperand* length = UseRegisterOrConstantAtStart(instr->length());
LOperand* index = UseRegisterOrConstantAtStart(instr->index());
return DefineAsRegister(new (zone()) LAccessArgumentsAt(args, length, index));
}
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
LOperand* object = UseFixed(instr->value(), r2);
LToFastProperties* result = new (zone()) LToFastProperties(object);
return MarkAsCall(DefineFixed(result, r2), instr);
}
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* value = UseFixed(instr->value(), r5);
LTypeof* result = new (zone()) LTypeof(context, value);
return MarkAsCall(DefineFixed(result, r2), instr);
}
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
return new (zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
}
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
instr->ReplayEnvironment(current_block_->last_environment());
return NULL;
}
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
if (instr->is_function_entry()) {
LOperand* context = UseFixed(instr->context(), cp);
return MarkAsCall(new (zone()) LStackCheck(context), instr);
} else {
DCHECK(instr->is_backwards_branch());
LOperand* context = UseAny(instr->context());
return AssignEnvironment(
AssignPointerMap(new (zone()) LStackCheck(context)));
}
}
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
HEnvironment* outer = current_block_->last_environment();
outer->set_ast_id(instr->ReturnId());
HConstant* undefined = graph()->GetConstantUndefined();
HEnvironment* inner = outer->CopyForInlining(
instr->closure(), instr->arguments_count(), instr->function(), undefined,
instr->inlining_kind());
// Only replay binding of arguments object if it wasn't removed from graph.
if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
inner->Bind(instr->arguments_var(), instr->arguments_object());
}
inner->BindContext(instr->closure_context());
inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedFunction(instr->shared());
return NULL;
}
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
LInstruction* pop = NULL;
HEnvironment* env = current_block_->last_environment();
if (env->entry()->arguments_pushed()) {
int argument_count = env->arguments_environment()->parameter_count();
pop = new (zone()) LDrop(argument_count);
DCHECK(instr->argument_delta() == -argument_count);
}
HEnvironment* outer =
current_block_->last_environment()->DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
return pop;
}
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* object = UseFixed(instr->enumerable(), r2);
LForInPrepareMap* result = new (zone()) LForInPrepareMap(context, object);
return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
}
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
LOperand* map = UseRegister(instr->map());
return AssignEnvironment(
DefineAsRegister(new (zone()) LForInCacheArray(map)));
}
LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* map = UseRegisterAtStart(instr->map());
return AssignEnvironment(new (zone()) LCheckMapValue(value, map));
}
LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
LOperand* object = UseRegister(instr->object());
LOperand* index = UseTempRegister(instr->index());
LLoadFieldByIndex* load = new (zone()) LLoadFieldByIndex(object, index);
LInstruction* result = DefineSameAsFirst(load);
return AssignPointerMap(result);
}
LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext* instr) {
LOperand* context = UseRegisterAtStart(instr->context());
return new (zone()) LStoreFrameContext(context);
}
} // namespace internal
} // namespace v8
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_CRANKSHAFT_S390_LITHIUM_S390_H_
#define V8_CRANKSHAFT_S390_LITHIUM_S390_H_
#include "src/crankshaft/hydrogen.h"
#include "src/crankshaft/lithium.h"
#include "src/crankshaft/lithium-allocator.h"
#include "src/safepoint-table.h"
#include "src/utils.h"
namespace v8 {
namespace internal {
// Forward declarations.
class LCodeGen;
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
V(AccessArgumentsAt) \
V(AddI) \
V(Allocate) \
V(ApplyArguments) \
V(ArgumentsElements) \
V(ArgumentsLength) \
V(ArithmeticD) \
V(ArithmeticT) \
V(BitI) \
V(BoundsCheck) \
V(Branch) \
V(CallWithDescriptor) \
V(CallNewArray) \
V(CallRuntime) \
V(CheckArrayBufferNotNeutered) \
V(CheckInstanceType) \
V(CheckNonSmi) \
V(CheckMaps) \
V(CheckMapValue) \
V(CheckSmi) \
V(CheckValue) \
V(ClampDToUint8) \
V(ClampIToUint8) \
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
V(ConstantD) \
V(ConstantE) \
V(ConstantI) \
V(ConstantS) \
V(ConstantT) \
V(ConstructDouble) \
V(Context) \
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByConstI) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleBits) \
V(DoubleToI) \
V(DoubleToSmi) \
V(Drop) \
V(Dummy) \
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(GetCachedArrayIndex) \
V(Goto) \
V(HasCachedArrayIndexAndBranch) \
V(HasInPrototypeChainAndBranch) \
V(HasInstanceTypeAndBranch) \
V(InnerAllocatedObject) \
V(InstanceOf) \
V(InstructionGap) \
V(Integer32ToDouble) \
V(InvokeFunction) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
V(LoadRoot) \
V(LoadFieldByIndex) \
V(LoadFunctionPrototype) \
V(LoadGlobalGeneric) \
V(LoadKeyed) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(MathAbs) \
V(MathClz32) \
V(MathExp) \
V(MathFloor) \
V(MathFround) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(MaybeGrowElements) \
V(ModByConstI) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
V(MultiplyAddD) \
V(MultiplySubD) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberTagU) \
V(NumberUntagD) \
V(OsrEntry) \
V(Parameter) \
V(Power) \
V(Prologue) \
V(PushArgument) \
V(Return) \
V(SeqStringGetChar) \
V(SeqStringSetChar) \
V(ShiftI) \
V(SmiTag) \
V(SmiUntag) \
V(StackCheck) \
V(StoreCodeEntry) \
V(StoreContextSlot) \
V(StoreFrameContext) \
V(StoreKeyed) \
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StringAdd) \
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringCompareAndBranch) \
V(SubI) \
V(RSubI) \
V(TaggedToI) \
V(ThisFunction) \
V(ToFastProperties) \
V(TransitionElementsKind) \
V(TrapAllocationMemento) \
V(Typeof) \
V(TypeofIsAndBranch) \
V(Uint32ToDouble) \
V(UnknownOSRValue) \
V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
Opcode opcode() const final { return LInstruction::k##type; } \
void CompileToNative(LCodeGen* generator) final; \
const char* Mnemonic() const final { return mnemonic; } \
static L##type* cast(LInstruction* instr) { \
DCHECK(instr->Is##type()); \
return reinterpret_cast<L##type*>(instr); \
}
#define DECLARE_HYDROGEN_ACCESSOR(type) \
H##type* hydrogen() const { return H##type::cast(hydrogen_value()); }
class LInstruction : public ZoneObject {
public:
LInstruction()
: environment_(NULL),
hydrogen_value_(NULL),
bit_field_(IsCallBits::encode(false)) {}
virtual ~LInstruction() {}
virtual void CompileToNative(LCodeGen* generator) = 0;
virtual const char* Mnemonic() const = 0;
virtual void PrintTo(StringStream* stream);
virtual void PrintDataTo(StringStream* stream);
virtual void PrintOutputOperandTo(StringStream* stream);
enum Opcode {
// Declare a unique enum value for each instruction.
#define DECLARE_OPCODE(type) k##type,
LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE) kNumberOfInstructions
#undef DECLARE_OPCODE
};
virtual Opcode opcode() const = 0;
// Declare non-virtual type testers for all leaf IR classes.
#define DECLARE_PREDICATE(type) \
bool Is##type() const { return opcode() == k##type; }
LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
#undef DECLARE_PREDICATE
// Declare virtual predicates for instructions that don't have
// an opcode.
virtual bool IsGap() const { return false; }
virtual bool IsControl() const { return false; }
// Try deleting this instruction if possible.
virtual bool TryDelete() { return false; }
void set_environment(LEnvironment* env) { environment_ = env; }
LEnvironment* environment() const { return environment_; }
bool HasEnvironment() const { return environment_ != NULL; }
void set_pointer_map(LPointerMap* p) { pointer_map_.set(p); }
LPointerMap* pointer_map() const { return pointer_map_.get(); }
bool HasPointerMap() const { return pointer_map_.is_set(); }
void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
HValue* hydrogen_value() const { return hydrogen_value_; }
void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
bool IsCall() const { return IsCallBits::decode(bit_field_); }
// Interface to the register allocator and iterators.
bool ClobbersTemps() const { return IsCall(); }
bool ClobbersRegisters() const { return IsCall(); }
virtual bool ClobbersDoubleRegisters(Isolate* isolate) const {
return IsCall();
}
// Interface to the register allocator and iterators.
bool IsMarkedAsCall() const { return IsCall(); }
virtual bool HasResult() const = 0;
virtual LOperand* result() const = 0;
LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; }
virtual bool HasInterestingComment(LCodeGen* gen) const { return true; }
#ifdef DEBUG
void VerifyCall();
#endif
virtual int InputCount() = 0;
virtual LOperand* InputAt(int i) = 0;
private:
// Iterator support.
friend class InputIterator;
friend class TempIterator;
virtual int TempCount() = 0;
virtual LOperand* TempAt(int i) = 0;
class IsCallBits : public BitField<bool, 0, 1> {};
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
HValue* hydrogen_value_;
int bit_field_;
};
// R = number of result operands (0 or 1).
template <int R>
class LTemplateResultInstruction : public LInstruction {
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
bool HasResult() const final { return R != 0 && result() != NULL; }
void set_result(LOperand* operand) { results_[0] = operand; }
LOperand* result() const override { return results_[0]; }
protected:
EmbeddedContainer<LOperand*, R> results_;
};
// R = number of result operands (0 or 1).
// I = number of input operands.
// T = number of temporary operands.
template <int R, int I, int T>
class LTemplateInstruction : public LTemplateResultInstruction<R> {
protected:
EmbeddedContainer<LOperand*, I> inputs_;
EmbeddedContainer<LOperand*, T> temps_;
private:
// Iterator support.
int InputCount() final { return I; }
LOperand* InputAt(int i) final { return inputs_[i]; }
int TempCount() final { return T; }
LOperand* TempAt(int i) final { return temps_[i]; }
};
class LGap : public LTemplateInstruction<0, 0, 0> {
public:
explicit LGap(HBasicBlock* block) : block_(block) {
parallel_moves_[BEFORE] = NULL;
parallel_moves_[START] = NULL;
parallel_moves_[END] = NULL;
parallel_moves_[AFTER] = NULL;
}
// Can't use the DECLARE-macro here because of sub-classes.
bool IsGap() const override { return true; }
void PrintDataTo(StringStream* stream) override;
static LGap* cast(LInstruction* instr) {
DCHECK(instr->IsGap());
return reinterpret_cast<LGap*>(instr);
}
bool IsRedundant() const;
HBasicBlock* block() const { return block_; }
enum InnerPosition {
BEFORE,
START,
END,
AFTER,
FIRST_INNER_POSITION = BEFORE,
LAST_INNER_POSITION = AFTER
};
LParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone) {
if (parallel_moves_[pos] == NULL) {
parallel_moves_[pos] = new (zone) LParallelMove(zone);
}
return parallel_moves_[pos];
}
LParallelMove* GetParallelMove(InnerPosition pos) {
return parallel_moves_[pos];
}
private:
LParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
HBasicBlock* block_;
};
class LInstructionGap final : public LGap {
public:
explicit LInstructionGap(HBasicBlock* block) : LGap(block) {}
bool HasInterestingComment(LCodeGen* gen) const override {
return !IsRedundant();
}
DECLARE_CONCRETE_INSTRUCTION(InstructionGap, "gap")
};
class LGoto final : public LTemplateInstruction<0, 0, 0> {
public:
explicit LGoto(HBasicBlock* block) : block_(block) {}
bool HasInterestingComment(LCodeGen* gen) const override;
DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
void PrintDataTo(StringStream* stream) override;
bool IsControl() const override { return true; }
int block_id() const { return block_->block_id(); }
private:
HBasicBlock* block_;
};
class LPrologue final : public LTemplateInstruction<0, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(Prologue, "prologue")
};
class LLazyBailout final : public LTemplateInstruction<0, 0, 0> {
public:
LLazyBailout() : gap_instructions_size_(0) {}
DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout")
void set_gap_instructions_size(int gap_instructions_size) {
gap_instructions_size_ = gap_instructions_size;
}
int gap_instructions_size() { return gap_instructions_size_; }
private:
int gap_instructions_size_;
};
class LDummy final : public LTemplateInstruction<1, 0, 0> {
public:
LDummy() {}
DECLARE_CONCRETE_INSTRUCTION(Dummy, "dummy")
};
class LDummyUse final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LDummyUse(LOperand* value) { inputs_[0] = value; }
DECLARE_CONCRETE_INSTRUCTION(DummyUse, "dummy-use")
};
class LDeoptimize final : public LTemplateInstruction<0, 0, 0> {
public:
bool IsControl() const override { return true; }
DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
};
class LLabel final : public LGap {
public:
explicit LLabel(HBasicBlock* block) : LGap(block), replacement_(NULL) {}
bool HasInterestingComment(LCodeGen* gen) const override { return false; }
DECLARE_CONCRETE_INSTRUCTION(Label, "label")
void PrintDataTo(StringStream* stream) override;
int block_id() const { return block()->block_id(); }
bool is_loop_header() const { return block()->IsLoopHeader(); }
bool is_osr_entry() const { return block()->is_osr_entry(); }
Label* label() { return &label_; }
LLabel* replacement() const { return replacement_; }
void set_replacement(LLabel* label) { replacement_ = label; }
bool HasReplacement() const { return replacement_ != NULL; }
private:
Label label_;
LLabel* replacement_;
};
class LParameter final : public LTemplateInstruction<1, 0, 0> {
public:
virtual bool HasInterestingComment(LCodeGen* gen) const { return false; }
DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
};
class LUnknownOSRValue final : public LTemplateInstruction<1, 0, 0> {
public:
bool HasInterestingComment(LCodeGen* gen) const override { return false; }
DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
};
template <int I, int T>
class LControlInstruction : public LTemplateInstruction<0, I, T> {
public:
LControlInstruction() : false_label_(NULL), true_label_(NULL) {}
bool IsControl() const final { return true; }
int SuccessorCount() { return hydrogen()->SuccessorCount(); }
HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
int TrueDestination(LChunk* chunk) {
return chunk->LookupDestination(true_block_id());
}
int FalseDestination(LChunk* chunk) {
return chunk->LookupDestination(false_block_id());
}
Label* TrueLabel(LChunk* chunk) {
if (true_label_ == NULL) {
true_label_ = chunk->GetAssemblyLabel(TrueDestination(chunk));
}
return true_label_;
}
Label* FalseLabel(LChunk* chunk) {
if (false_label_ == NULL) {
false_label_ = chunk->GetAssemblyLabel(FalseDestination(chunk));
}
return false_label_;
}
protected:
int true_block_id() { return SuccessorAt(0)->block_id(); }
int false_block_id() { return SuccessorAt(1)->block_id(); }
private:
HControlInstruction* hydrogen() {
return HControlInstruction::cast(this->hydrogen_value());
}
Label* false_label_;
Label* true_label_;
};
class LWrapReceiver final : public LTemplateInstruction<1, 2, 0> {
public:
LWrapReceiver(LOperand* receiver, LOperand* function) {
inputs_[0] = receiver;
inputs_[1] = function;
}
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
DECLARE_HYDROGEN_ACCESSOR(WrapReceiver)
LOperand* receiver() { return inputs_[0]; }
LOperand* function() { return inputs_[1]; }
};
class LApplyArguments final : public LTemplateInstruction<1, 4, 0> {
public:
LApplyArguments(LOperand* function, LOperand* receiver, LOperand* length,
LOperand* elements) {
inputs_[0] = function;
inputs_[1] = receiver;
inputs_[2] = length;
inputs_[3] = elements;
}
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
LOperand* function() { return inputs_[0]; }
LOperand* receiver() { return inputs_[1]; }
LOperand* length() { return inputs_[2]; }
LOperand* elements() { return inputs_[3]; }
};
class LAccessArgumentsAt final : public LTemplateInstruction<1, 3, 0> {
public:
LAccessArgumentsAt(LOperand* arguments, LOperand* length, LOperand* index) {
inputs_[0] = arguments;
inputs_[1] = length;
inputs_[2] = index;
}
DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
LOperand* arguments() { return inputs_[0]; }
LOperand* length() { return inputs_[1]; }
LOperand* index() { return inputs_[2]; }
void PrintDataTo(StringStream* stream) override;
};
class LArgumentsLength final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LArgumentsLength(LOperand* elements) { inputs_[0] = elements; }
LOperand* elements() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length")
};
class LArgumentsElements final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
class LModByPowerOf2I final : public LTemplateInstruction<1, 1, 0> {
public:
LModByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(ModByPowerOf2I, "mod-by-power-of-2-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
private:
int32_t divisor_;
};
class LModByConstI final : public LTemplateInstruction<1, 1, 0> {
public:
LModByConstI(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(ModByConstI, "mod-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
private:
int32_t divisor_;
};
class LModI final : public LTemplateInstruction<1, 2, 0> {
public:
LModI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
};
class LDivByPowerOf2I final : public LTemplateInstruction<1, 1, 0> {
public:
LDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(DivByPowerOf2I, "div-by-power-of-2-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
private:
int32_t divisor_;
};
class LDivByConstI final : public LTemplateInstruction<1, 1, 0> {
public:
LDivByConstI(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(DivByConstI, "div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
private:
int32_t divisor_;
};
class LDivI final : public LTemplateInstruction<1, 2, 0> {
public:
LDivI(LOperand* dividend, LOperand* divisor) {
inputs_[0] = dividend;
inputs_[1] = divisor;
}
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
};
class LFlooringDivByPowerOf2I final : public LTemplateInstruction<1, 1, 0> {
public:
LFlooringDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByPowerOf2I,
"flooring-div-by-power-of-2-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
class LFlooringDivByConstI final : public LTemplateInstruction<1, 1, 1> {
public:
LFlooringDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
class LFlooringDivI final : public LTemplateInstruction<1, 2, 0> {
public:
LFlooringDivI(LOperand* dividend, LOperand* divisor) {
inputs_[0] = dividend;
inputs_[1] = divisor;
}
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
};
class LMulI final : public LTemplateInstruction<1, 2, 0> {
public:
LMulI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
DECLARE_HYDROGEN_ACCESSOR(Mul)
};
// Instruction for computing multiplier * multiplicand + addend.
class LMultiplyAddD final : public LTemplateInstruction<1, 3, 0> {
public:
LMultiplyAddD(LOperand* addend, LOperand* multiplier,
LOperand* multiplicand) {
inputs_[0] = addend;
inputs_[1] = multiplier;
inputs_[2] = multiplicand;
}
LOperand* addend() { return inputs_[0]; }
LOperand* multiplier() { return inputs_[1]; }
LOperand* multiplicand() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MultiplyAddD, "multiply-add-d")
};
// Instruction for computing minuend - multiplier * multiplicand.
class LMultiplySubD final : public LTemplateInstruction<1, 3, 0> {
public:
LMultiplySubD(LOperand* minuend, LOperand* multiplier,
LOperand* multiplicand) {
inputs_[0] = minuend;
inputs_[1] = multiplier;
inputs_[2] = multiplicand;
}
LOperand* minuend() { return inputs_[0]; }
LOperand* multiplier() { return inputs_[1]; }
LOperand* multiplicand() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MultiplySubD, "multiply-sub-d")
};
class LDebugBreak final : public LTemplateInstruction<0, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break")
};
class LCompareNumericAndBranch final : public LControlInstruction<2, 0> {
public:
LCompareNumericAndBranch(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch,
"compare-numeric-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareNumericAndBranch)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const { return hydrogen()->representation().IsDouble(); }
void PrintDataTo(StringStream* stream) override;
};
class LMathFloor final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathFloor(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathRound final : public LTemplateInstruction<1, 1, 1> {
public:
LMathRound(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathFround final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathFround(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFround, "math-fround")
};
class LMathAbs final : public LTemplateInstruction<1, 2, 0> {
public:
LMathAbs(LOperand* context, LOperand* value) {
inputs_[1] = context;
inputs_[0] = value;
}
LOperand* context() { return inputs_[1]; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathLog final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathLog(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
};
class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathClz32(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
};
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
public:
LMathExp(LOperand* value, LOperand* double_temp, LOperand* temp1,
LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
temps_[2] = double_temp;
ExternalReference::InitializeMathExpData();
}
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
LOperand* double_temp() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
};
class LMathSqrt final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathSqrt(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
};
class LMathPowHalf final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LMathPowHalf(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
};
class LCmpObjectEqAndBranch final : public LControlInstruction<2, 0> {
public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch)
};
class LCmpHoleAndBranch final : public LControlInstruction<1, 0> {
public:
explicit LCmpHoleAndBranch(LOperand* object) { inputs_[0] = object; }
LOperand* object() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CmpHoleAndBranch, "cmp-hole-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareHoleAndBranch)
};
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
public:
LIsStringAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
void PrintDataTo(StringStream* stream) override;
};
class LIsSmiAndBranch final : public LControlInstruction<1, 0> {
public:
explicit LIsSmiAndBranch(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
void PrintDataTo(StringStream* stream) override;
};
class LIsUndetectableAndBranch final : public LControlInstruction<1, 1> {
public:
explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
"is-undetectable-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
void PrintDataTo(StringStream* stream) override;
};
class LStringCompareAndBranch final : public LControlInstruction<3, 0> {
public:
LStringCompareAndBranch(LOperand* context, LOperand* left, LOperand* right) {
inputs_[0] = context;
inputs_[1] = left;
inputs_[2] = right;
}
LOperand* context() { return inputs_[0]; }
LOperand* left() { return inputs_[1]; }
LOperand* right() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
"string-compare-and-branch")
DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
Token::Value op() const { return hydrogen()->token(); }
void PrintDataTo(StringStream* stream) override;
};
class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 0> {
public:
explicit LHasInstanceTypeAndBranch(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
"has-instance-type-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
void PrintDataTo(StringStream* stream) override;
};
class LGetCachedArrayIndex final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LGetCachedArrayIndex(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index")
DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex)
};
class LHasCachedArrayIndexAndBranch final : public LControlInstruction<1, 0> {
public:
explicit LHasCachedArrayIndexAndBranch(LOperand* value) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
"has-cached-array-index-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
void PrintDataTo(StringStream* stream) override;
};
class LClassOfTestAndBranch final : public LControlInstruction<1, 1> {
public:
LClassOfTestAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
void PrintDataTo(StringStream* stream) override;
};
class LCmpT final : public LTemplateInstruction<1, 3, 0> {
public:
LCmpT(LOperand* context, LOperand* left, LOperand* right) {
inputs_[0] = context;
inputs_[1] = left;
inputs_[2] = right;
}
LOperand* context() { return inputs_[0]; }
LOperand* left() { return inputs_[1]; }
LOperand* right() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
Token::Value op() const { return hydrogen()->token(); }
};
class LInstanceOf final : public LTemplateInstruction<1, 3, 0> {
public:
LInstanceOf(LOperand* context, LOperand* left, LOperand* right) {
inputs_[0] = context;
inputs_[1] = left;
inputs_[2] = right;
}
LOperand* context() const { return inputs_[0]; }
LOperand* left() const { return inputs_[1]; }
LOperand* right() const { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
};
class LHasInPrototypeChainAndBranch final : public LControlInstruction<2, 0> {
public:
LHasInPrototypeChainAndBranch(LOperand* object, LOperand* prototype) {
inputs_[0] = object;
inputs_[1] = prototype;
}
LOperand* object() const { return inputs_[0]; }
LOperand* prototype() const { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch,
"has-in-prototype-chain-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasInPrototypeChainAndBranch)
};
class LBoundsCheck final : public LTemplateInstruction<0, 2, 0> {
public:
LBoundsCheck(LOperand* index, LOperand* length) {
inputs_[0] = index;
inputs_[1] = length;
}
LOperand* index() { return inputs_[0]; }
LOperand* length() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
DECLARE_HYDROGEN_ACCESSOR(BoundsCheck)
};
class LBitI final : public LTemplateInstruction<1, 2, 0> {
public:
LBitI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
Token::Value op() const { return hydrogen()->op(); }
DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i")
DECLARE_HYDROGEN_ACCESSOR(Bitwise)
};
class LShiftI final : public LTemplateInstruction<1, 2, 0> {
public:
LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt)
: op_(op), can_deopt_(can_deopt) {
inputs_[0] = left;
inputs_[1] = right;
}
Token::Value op() const { return op_; }
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
bool can_deopt() const { return can_deopt_; }
DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i")
private:
Token::Value op_;
bool can_deopt_;
};
class LSubI final : public LTemplateInstruction<1, 2, 0> {
public:
LSubI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i")
DECLARE_HYDROGEN_ACCESSOR(Sub)
};
class LRSubI final : public LTemplateInstruction<1, 2, 0> {
public:
LRSubI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(RSubI, "rsub-i")
DECLARE_HYDROGEN_ACCESSOR(Sub)
};
class LConstantI final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i")
DECLARE_HYDROGEN_ACCESSOR(Constant)
int32_t value() const { return hydrogen()->Integer32Value(); }
};
class LConstantS final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s")
DECLARE_HYDROGEN_ACCESSOR(Constant)
Smi* value() const { return Smi::FromInt(hydrogen()->Integer32Value()); }
};
class LConstantD final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
DECLARE_HYDROGEN_ACCESSOR(Constant)
double value() const { return hydrogen()->DoubleValue(); }
uint64_t bits() const { return hydrogen()->DoubleValueAsBits(); }
};
class LConstantE final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e")
DECLARE_HYDROGEN_ACCESSOR(Constant)
ExternalReference value() const {
return hydrogen()->ExternalReferenceValue();
}
};
class LConstantT final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
DECLARE_HYDROGEN_ACCESSOR(Constant)
Handle<Object> value(Isolate* isolate) const {
return hydrogen()->handle(isolate);
}
};
class LBranch final : public LControlInstruction<1, 0> {
public:
explicit LBranch(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
DECLARE_HYDROGEN_ACCESSOR(Branch)
void PrintDataTo(StringStream* stream) override;
};
class LCmpMapAndBranch final : public LControlInstruction<1, 1> {
public:
LCmpMapAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareMap)
Handle<Map> map() const { return hydrogen()->map().handle(); }
};
class LSeqStringGetChar final : public LTemplateInstruction<1, 2, 0> {
public:
LSeqStringGetChar(LOperand* string, LOperand* index) {
inputs_[0] = string;
inputs_[1] = index;
}
LOperand* string() const { return inputs_[0]; }
LOperand* index() const { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar, "seq-string-get-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringGetChar)
};
class LSeqStringSetChar final : public LTemplateInstruction<1, 4, 0> {
public:
LSeqStringSetChar(LOperand* context, LOperand* string, LOperand* index,
LOperand* value) {
inputs_[0] = context;
inputs_[1] = string;
inputs_[2] = index;
inputs_[3] = value;
}
LOperand* string() { return inputs_[1]; }
LOperand* index() { return inputs_[2]; }
LOperand* value() { return inputs_[3]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
};
class LAddI final : public LTemplateInstruction<1, 2, 0> {
public:
LAddI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
DECLARE_HYDROGEN_ACCESSOR(Add)
};
class LMathMinMax final : public LTemplateInstruction<1, 2, 0> {
public:
LMathMinMax(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
};
class LPower final : public LTemplateInstruction<1, 2, 0> {
public:
LPower(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(Power, "power")
DECLARE_HYDROGEN_ACCESSOR(Power)
};
class LArithmeticD final : public LTemplateInstruction<1, 2, 0> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right) : op_(op) {
inputs_[0] = left;
inputs_[1] = right;
}
Token::Value op() const { return op_; }
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
Opcode opcode() const override { return LInstruction::kArithmeticD; }
void CompileToNative(LCodeGen* generator) override;
const char* Mnemonic() const override;
private:
Token::Value op_;
};
class LArithmeticT final : public LTemplateInstruction<1, 3, 0> {
public:
LArithmeticT(Token::Value op, LOperand* context, LOperand* left,
LOperand* right)
: op_(op) {
inputs_[0] = context;
inputs_[1] = left;
inputs_[2] = right;
}
LOperand* context() { return inputs_[0]; }
LOperand* left() { return inputs_[1]; }
LOperand* right() { return inputs_[2]; }
Token::Value op() const { return op_; }
Opcode opcode() const override { return LInstruction::kArithmeticT; }
void CompileToNative(LCodeGen* generator) override;
const char* Mnemonic() const override;
DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
private:
Token::Value op_;
};
class LReturn final : public LTemplateInstruction<0, 3, 0> {
public:
LReturn(LOperand* value, LOperand* context, LOperand* parameter_count) {
inputs_[0] = value;
inputs_[1] = context;
inputs_[2] = parameter_count;
}
LOperand* value() { return inputs_[0]; }
bool has_constant_parameter_count() {
return parameter_count()->IsConstantOperand();
}
LConstantOperand* constant_parameter_count() {
DCHECK(has_constant_parameter_count());
return LConstantOperand::cast(parameter_count());
}
LOperand* parameter_count() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(Return, "return")
};
class LLoadNamedField final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadNamedField(LOperand* object) { inputs_[0] = object; }
LOperand* object() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
};
class LLoadNamedGeneric final : public LTemplateInstruction<1, 2, 1> {
public:
LLoadNamedGeneric(LOperand* context, LOperand* object, LOperand* vector) {
inputs_[0] = context;
inputs_[1] = object;
temps_[0] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
LOperand* temp_vector() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
Handle<Object> name() const { return hydrogen()->name(); }
};
class LLoadFunctionPrototype final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadFunctionPrototype(LOperand* function) { inputs_[0] = function; }
LOperand* function() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
};
class LLoadRoot final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(LoadRoot, "load-root")
DECLARE_HYDROGEN_ACCESSOR(LoadRoot)
Heap::RootListIndex index() const { return hydrogen()->index(); }
};
class LLoadKeyed final : public LTemplateInstruction<1, 3, 0> {
public:
LLoadKeyed(LOperand* elements, LOperand* key, LOperand* backing_store_owner) {
inputs_[0] = elements;
inputs_[1] = key;
inputs_[2] = backing_store_owner;
}
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* backing_store_owner() { return inputs_[2]; }
ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
void PrintDataTo(StringStream* stream) override;
uint32_t base_offset() const { return hydrogen()->base_offset(); }
};
class LLoadKeyedGeneric final : public LTemplateInstruction<1, 3, 1> {
public:
LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key,
LOperand* vector) {
inputs_[0] = context;
inputs_[1] = object;
inputs_[2] = key;
temps_[0] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
LOperand* key() { return inputs_[2]; }
LOperand* temp_vector() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedGeneric)
};
class LLoadGlobalGeneric final : public LTemplateInstruction<1, 2, 1> {
public:
LLoadGlobalGeneric(LOperand* context, LOperand* global_object,
LOperand* vector) {
inputs_[0] = context;
inputs_[1] = global_object;
temps_[0] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* global_object() { return inputs_[1]; }
LOperand* temp_vector() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
Handle<Object> name() const { return hydrogen()->name(); }
TypeofMode typeof_mode() const { return hydrogen()->typeof_mode(); }
};
class LLoadContextSlot final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) { inputs_[0] = context; }
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot")
DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot)
int slot_index() { return hydrogen()->slot_index(); }
void PrintDataTo(StringStream* stream) override;
};
class LStoreContextSlot final : public LTemplateInstruction<0, 2, 0> {
public:
LStoreContextSlot(LOperand* context, LOperand* value) {
inputs_[0] = context;
inputs_[1] = value;
}
LOperand* context() { return inputs_[0]; }
LOperand* value() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot")
DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot)
int slot_index() { return hydrogen()->slot_index(); }
void PrintDataTo(StringStream* stream) override;
};
class LPushArgument final : public LTemplateInstruction<0, 1, 0> {
public:
explicit LPushArgument(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument")
};
class LDrop final : public LTemplateInstruction<0, 0, 0> {
public:
explicit LDrop(int count) : count_(count) {}
int count() const { return count_; }
DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
private:
int count_;
};
class LStoreCodeEntry final : public LTemplateInstruction<0, 2, 0> {
public:
LStoreCodeEntry(LOperand* function, LOperand* code_object) {
inputs_[0] = function;
inputs_[1] = code_object;
}
LOperand* function() { return inputs_[0]; }
LOperand* code_object() { return inputs_[1]; }
void PrintDataTo(StringStream* stream) override;
DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
};
class LInnerAllocatedObject final : public LTemplateInstruction<1, 2, 0> {
public:
LInnerAllocatedObject(LOperand* base_object, LOperand* offset) {
inputs_[0] = base_object;
inputs_[1] = offset;
}
LOperand* base_object() const { return inputs_[0]; }
LOperand* offset() const { return inputs_[1]; }
void PrintDataTo(StringStream* stream) override;
DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
};
class LThisFunction final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
DECLARE_HYDROGEN_ACCESSOR(ThisFunction)
};
class LContext final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(Context, "context")
DECLARE_HYDROGEN_ACCESSOR(Context)
};
class LDeclareGlobals final : public LTemplateInstruction<0, 1, 0> {
public:
explicit LDeclareGlobals(LOperand* context) { inputs_[0] = context; }
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals")
DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals)
};
class LCallWithDescriptor final : public LTemplateResultInstruction<1> {
public:
LCallWithDescriptor(CallInterfaceDescriptor descriptor,
const ZoneList<LOperand*>& operands, Zone* zone)
: descriptor_(descriptor),
inputs_(descriptor.GetRegisterParameterCount() +
kImplicitRegisterParameterCount,
zone) {
DCHECK(descriptor.GetRegisterParameterCount() +
kImplicitRegisterParameterCount ==
operands.length());
inputs_.AddAll(operands, zone);
}
LOperand* target() const { return inputs_[0]; }
const CallInterfaceDescriptor descriptor() { return descriptor_; }
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
// The target and context are passed as implicit parameters that are not
// explicitly listed in the descriptor.
static const int kImplicitRegisterParameterCount = 2;
private:
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
CallInterfaceDescriptor descriptor_;
ZoneList<LOperand*> inputs_;
// Iterator support.
int InputCount() final { return inputs_.length(); }
LOperand* InputAt(int i) final { return inputs_[i]; }
int TempCount() final { return 0; }
LOperand* TempAt(int i) final { return NULL; }
};
class LInvokeFunction final : public LTemplateInstruction<1, 2, 0> {
public:
LInvokeFunction(LOperand* context, LOperand* function) {
inputs_[0] = context;
inputs_[1] = function;
}
LOperand* context() { return inputs_[0]; }
LOperand* function() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNewArray final : public LTemplateInstruction<1, 2, 0> {
public:
LCallNewArray(LOperand* context, LOperand* constructor) {
inputs_[0] = context;
inputs_[1] = constructor;
}
LOperand* context() { return inputs_[0]; }
LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallRuntime final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LCallRuntime(LOperand* context) { inputs_[0] = context; }
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
bool ClobbersDoubleRegisters(Isolate* isolate) const override {
return save_doubles() == kDontSaveFPRegs;
}
const Runtime::Function* function() const { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count(); }
SaveFPRegsMode save_doubles() const { return hydrogen()->save_doubles(); }
};
class LInteger32ToDouble final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LInteger32ToDouble(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double")
};
class LUint32ToDouble final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LUint32ToDouble(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double")
};
class LNumberTagI final : public LTemplateInstruction<1, 1, 2> {
public:
LNumberTagI(LOperand* value, LOperand* temp1, LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i")
};
class LNumberTagU final : public LTemplateInstruction<1, 1, 2> {
public:
LNumberTagU(LOperand* value, LOperand* temp1, LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u")
};
class LNumberTagD final : public LTemplateInstruction<1, 1, 2> {
public:
LNumberTagD(LOperand* value, LOperand* temp, LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp;
temps_[1] = temp2;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
class LDoubleToSmi final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LDoubleToSmi(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
bool truncating() { return hydrogen()->CanTruncateToInt32(); }
};
// Sometimes truncating conversion from a tagged value to an int32.
class LDoubleToI final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LDoubleToI(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i")
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
bool truncating() { return hydrogen()->CanTruncateToInt32(); }
};
// Truncating conversion from a tagged value to an int32.
class LTaggedToI final : public LTemplateInstruction<1, 1, 2> {
public:
LTaggedToI(LOperand* value, LOperand* temp, LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp;
temps_[1] = temp2;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i")
DECLARE_HYDROGEN_ACCESSOR(Change)
bool truncating() { return hydrogen()->CanTruncateToInt32(); }
};
class LSmiTag final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LSmiTag(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
class LNumberUntagD final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LNumberUntagD(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
class LSmiUntag final : public LTemplateInstruction<1, 1, 0> {
public:
LSmiUntag(LOperand* value, bool needs_check) : needs_check_(needs_check) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
bool needs_check() const { return needs_check_; }
DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag")
private:
bool needs_check_;
};
class LStoreNamedField final : public LTemplateInstruction<0, 2, 1> {
public:
LStoreNamedField(LOperand* object, LOperand* value, LOperand* temp) {
inputs_[0] = object;
inputs_[1] = value;
temps_[0] = temp;
}
LOperand* object() { return inputs_[0]; }
LOperand* value() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
void PrintDataTo(StringStream* stream) override;
Representation representation() const {
return hydrogen()->field_representation();
}
};
class LStoreNamedGeneric final : public LTemplateInstruction<0, 3, 2> {
public:
LStoreNamedGeneric(LOperand* context, LOperand* object, LOperand* value,
LOperand* slot, LOperand* vector) {
inputs_[0] = context;
inputs_[1] = object;
inputs_[2] = value;
temps_[0] = slot;
temps_[1] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
LOperand* temp_slot() { return temps_[0]; }
LOperand* temp_vector() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
void PrintDataTo(StringStream* stream) override;
Handle<Object> name() const { return hydrogen()->name(); }
LanguageMode language_mode() { return hydrogen()->language_mode(); }
};
class LStoreKeyed final : public LTemplateInstruction<0, 4, 0> {
public:
LStoreKeyed(LOperand* object, LOperand* key, LOperand* value,
LOperand* backing_store_owner) {
inputs_[0] = object;
inputs_[1] = key;
inputs_[2] = value;
inputs_[3] = backing_store_owner;
}
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
LOperand* backing_store_owner() { return inputs_[3]; }
ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
void PrintDataTo(StringStream* stream) override;
bool NeedsCanonicalization() {
if (hydrogen()->value()->IsAdd() || hydrogen()->value()->IsSub() ||
hydrogen()->value()->IsMul() || hydrogen()->value()->IsDiv()) {
return false;
}
return hydrogen()->NeedsCanonicalization();
}
uint32_t base_offset() const { return hydrogen()->base_offset(); }
};
class LStoreKeyedGeneric final : public LTemplateInstruction<0, 4, 2> {
public:
LStoreKeyedGeneric(LOperand* context, LOperand* object, LOperand* key,
LOperand* value, LOperand* slot, LOperand* vector) {
inputs_[0] = context;
inputs_[1] = object;
inputs_[2] = key;
inputs_[3] = value;
temps_[0] = slot;
temps_[1] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
LOperand* key() { return inputs_[2]; }
LOperand* value() { return inputs_[3]; }
LOperand* temp_slot() { return temps_[0]; }
LOperand* temp_vector() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
void PrintDataTo(StringStream* stream) override;
LanguageMode language_mode() { return hydrogen()->language_mode(); }
};
class LTransitionElementsKind final : public LTemplateInstruction<0, 2, 1> {
public:
LTransitionElementsKind(LOperand* object, LOperand* context,
LOperand* new_map_temp) {
inputs_[0] = object;
inputs_[1] = context;
temps_[0] = new_map_temp;
}
LOperand* context() { return inputs_[1]; }
LOperand* object() { return inputs_[0]; }
LOperand* new_map_temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind,
"transition-elements-kind")
DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
void PrintDataTo(StringStream* stream) override;
Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
Handle<Map> transitioned_map() {
return hydrogen()->transitioned_map().handle();
}
ElementsKind from_kind() { return hydrogen()->from_kind(); }
ElementsKind to_kind() { return hydrogen()->to_kind(); }
};
class LTrapAllocationMemento final : public LTemplateInstruction<0, 1, 1> {
public:
LTrapAllocationMemento(LOperand* object, LOperand* temp) {
inputs_[0] = object;
temps_[0] = temp;
}
LOperand* object() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento, "trap-allocation-memento")
};
class LMaybeGrowElements final : public LTemplateInstruction<1, 5, 0> {
public:
LMaybeGrowElements(LOperand* context, LOperand* object, LOperand* elements,
LOperand* key, LOperand* current_capacity) {
inputs_[0] = context;
inputs_[1] = object;
inputs_[2] = elements;
inputs_[3] = key;
inputs_[4] = current_capacity;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
LOperand* elements() { return inputs_[2]; }
LOperand* key() { return inputs_[3]; }
LOperand* current_capacity() { return inputs_[4]; }
DECLARE_HYDROGEN_ACCESSOR(MaybeGrowElements)
DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements, "maybe-grow-elements")
};
class LStringAdd final : public LTemplateInstruction<1, 3, 0> {
public:
LStringAdd(LOperand* context, LOperand* left, LOperand* right) {
inputs_[0] = context;
inputs_[1] = left;
inputs_[2] = right;
}
LOperand* context() { return inputs_[0]; }
LOperand* left() { return inputs_[1]; }
LOperand* right() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add")
DECLARE_HYDROGEN_ACCESSOR(StringAdd)
};
class LStringCharCodeAt final : public LTemplateInstruction<1, 3, 0> {
public:
LStringCharCodeAt(LOperand* context, LOperand* string, LOperand* index) {
inputs_[0] = context;
inputs_[1] = string;
inputs_[2] = index;
}
LOperand* context() { return inputs_[0]; }
LOperand* string() { return inputs_[1]; }
LOperand* index() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at")
DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt)
};
class LStringCharFromCode final : public LTemplateInstruction<1, 2, 0> {
public:
explicit LStringCharFromCode(LOperand* context, LOperand* char_code) {
inputs_[0] = context;
inputs_[1] = char_code;
}
LOperand* context() { return inputs_[0]; }
LOperand* char_code() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
};
class LCheckValue final : public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckValue(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value")
DECLARE_HYDROGEN_ACCESSOR(CheckValue)
};
class LCheckArrayBufferNotNeutered final
: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckArrayBufferNotNeutered(LOperand* view) { inputs_[0] = view; }
LOperand* view() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered,
"check-array-buffer-not-neutered")
DECLARE_HYDROGEN_ACCESSOR(CheckArrayBufferNotNeutered)
};
class LCheckInstanceType final : public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckInstanceType(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type")
DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType)
};
class LCheckMaps final : public LTemplateInstruction<0, 1, 1> {
public:
explicit LCheckMaps(LOperand* value = NULL, LOperand* temp = NULL) {
inputs_[0] = value;
temps_[0] = temp;
}
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
};
class LCheckSmi final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LCheckSmi(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi")
};
class LCheckNonSmi final : public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckNonSmi(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
};
class LClampDToUint8 final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LClampDToUint8(LOperand* unclamped) { inputs_[0] = unclamped; }
LOperand* unclamped() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ClampDToUint8, "clamp-d-to-uint8")
};
class LClampIToUint8 final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LClampIToUint8(LOperand* unclamped) { inputs_[0] = unclamped; }
LOperand* unclamped() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ClampIToUint8, "clamp-i-to-uint8")
};
class LClampTToUint8 final : public LTemplateInstruction<1, 1, 1> {
public:
LClampTToUint8(LOperand* unclamped, LOperand* temp) {
inputs_[0] = unclamped;
temps_[0] = temp;
}
LOperand* unclamped() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8")
};
class LDoubleBits final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LDoubleBits(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DoubleBits, "double-bits")
DECLARE_HYDROGEN_ACCESSOR(DoubleBits)
};
class LConstructDouble final : public LTemplateInstruction<1, 2, 0> {
public:
LConstructDouble(LOperand* hi, LOperand* lo) {
inputs_[0] = hi;
inputs_[1] = lo;
}
LOperand* hi() { return inputs_[0]; }
LOperand* lo() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(ConstructDouble, "construct-double")
};
class LAllocate final : public LTemplateInstruction<1, 2, 2> {
public:
LAllocate(LOperand* context, LOperand* size, LOperand* temp1,
LOperand* temp2) {
inputs_[0] = context;
inputs_[1] = size;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* context() { return inputs_[0]; }
LOperand* size() { return inputs_[1]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(Allocate, "allocate")
DECLARE_HYDROGEN_ACCESSOR(Allocate)
};
class LToFastProperties final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LToFastProperties(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
};
class LTypeof final : public LTemplateInstruction<1, 2, 0> {
public:
LTypeof(LOperand* context, LOperand* value) {
inputs_[0] = context;
inputs_[1] = value;
}
LOperand* context() { return inputs_[0]; }
LOperand* value() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
};
class LTypeofIsAndBranch final : public LControlInstruction<1, 0> {
public:
explicit LTypeofIsAndBranch(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch)
Handle<String> type_literal() { return hydrogen()->type_literal(); }
void PrintDataTo(StringStream* stream) override;
};
class LOsrEntry final : public LTemplateInstruction<0, 0, 0> {
public:
LOsrEntry() {}
bool HasInterestingComment(LCodeGen* gen) const override { return false; }
DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
};
class LStackCheck final : public LTemplateInstruction<0, 1, 0> {
public:
explicit LStackCheck(LOperand* context) { inputs_[0] = context; }
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
DECLARE_HYDROGEN_ACCESSOR(StackCheck)
Label* done_label() { return &done_label_; }
private:
Label done_label_;
};
class LForInPrepareMap final : public LTemplateInstruction<1, 2, 0> {
public:
LForInPrepareMap(LOperand* context, LOperand* object) {
inputs_[0] = context;
inputs_[1] = object;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap, "for-in-prepare-map")
};
class LForInCacheArray final : public LTemplateInstruction<1, 1, 0> {
public:
explicit LForInCacheArray(LOperand* map) { inputs_[0] = map; }
LOperand* map() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray, "for-in-cache-array")
int idx() { return HForInCacheArray::cast(this->hydrogen_value())->idx(); }
};
class LCheckMapValue final : public LTemplateInstruction<0, 2, 0> {
public:
LCheckMapValue(LOperand* value, LOperand* map) {
inputs_[0] = value;
inputs_[1] = map;
}
LOperand* value() { return inputs_[0]; }
LOperand* map() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CheckMapValue, "check-map-value")
};
class LLoadFieldByIndex final : public LTemplateInstruction<1, 2, 0> {
public:
LLoadFieldByIndex(LOperand* object, LOperand* index) {
inputs_[0] = object;
inputs_[1] = index;
}
LOperand* object() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex, "load-field-by-index")
};
class LStoreFrameContext : public LTemplateInstruction<0, 1, 0> {
public:
explicit LStoreFrameContext(LOperand* context) { inputs_[0] = context; }
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext, "store-frame-context")
};
class LChunkBuilder;
class LPlatformChunk final : public LChunk {
public:
LPlatformChunk(CompilationInfo* info, HGraph* graph) : LChunk(info, graph) {}
int GetNextSpillIndex(RegisterKind kind);
LOperand* GetNextSpillSlot(RegisterKind kind);
};
class LChunkBuilder final : public LChunkBuilderBase {
public:
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
: LChunkBuilderBase(info, graph),
current_instruction_(NULL),
current_block_(NULL),
next_block_(NULL),
allocator_(allocator) {}
// Build the sequence for the graph.
LPlatformChunk* Build();
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) LInstruction* Do##type(H##type* node);
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
LInstruction* DoMultiplySub(HValue* minuend, HMul* mul);
LInstruction* DoRSub(HSub* instr);
static bool HasMagicNumberForDivisor(int32_t divisor);
LInstruction* DoMathFloor(HUnaryMathOperation* instr);
LInstruction* DoMathRound(HUnaryMathOperation* instr);
LInstruction* DoMathFround(HUnaryMathOperation* instr);
LInstruction* DoMathAbs(HUnaryMathOperation* instr);
LInstruction* DoMathLog(HUnaryMathOperation* instr);
LInstruction* DoMathExp(HUnaryMathOperation* instr);
LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivByConstI(HDiv* instr);
LInstruction* DoDivI(HDiv* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModByConstI(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
private:
// Methods for getting operands for Use / Define / Temp.
LUnallocated* ToUnallocated(Register reg);
LUnallocated* ToUnallocated(DoubleRegister reg);
// Methods for setting up define-use relationships.
MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand);
MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
DoubleRegister fixed_register);
// A value that is guaranteed to be allocated to a register.
// Operand created by UseRegister is guaranteed to be live until the end of
// instruction. This means that register allocator will not reuse it's
// register for any other operand inside instruction.
// Operand created by UseRegisterAtStart is guaranteed to be live only at
// instruction start. Register allocator is free to assign the same register
// to some other operand used inside instruction (i.e. temporary or
// output).
MUST_USE_RESULT LOperand* UseRegister(HValue* value);
MUST_USE_RESULT LOperand* UseRegisterAtStart(HValue* value);
// An input operand in a register that may be trashed.
MUST_USE_RESULT LOperand* UseTempRegister(HValue* value);
// An input operand in a register or stack slot.
MUST_USE_RESULT LOperand* Use(HValue* value);
MUST_USE_RESULT LOperand* UseAtStart(HValue* value);
// An input operand in a register, stack slot or a constant operand.
MUST_USE_RESULT LOperand* UseOrConstant(HValue* value);
MUST_USE_RESULT LOperand* UseOrConstantAtStart(HValue* value);
// An input operand in a register or a constant operand.
MUST_USE_RESULT LOperand* UseRegisterOrConstant(HValue* value);
MUST_USE_RESULT LOperand* UseRegisterOrConstantAtStart(HValue* value);
// An input operand in a constant operand.
MUST_USE_RESULT LOperand* UseConstant(HValue* value);
// An input operand in register, stack slot or a constant operand.
// Will not be moved to a register even if one is freely available.
MUST_USE_RESULT LOperand* UseAny(HValue* value) override;
// Temporary operand that must be in a register.
MUST_USE_RESULT LUnallocated* TempRegister();
MUST_USE_RESULT LUnallocated* TempDoubleRegister();
MUST_USE_RESULT LOperand* FixedTemp(Register reg);
MUST_USE_RESULT LOperand* FixedTemp(DoubleRegister reg);
// Methods for setting up define-use relationships.
// Return the same instruction that they are passed.
LInstruction* Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result);
LInstruction* DefineAsRegister(LTemplateResultInstruction<1>* instr);
LInstruction* DefineAsSpilled(LTemplateResultInstruction<1>* instr,
int index);
LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr, Register reg);
LInstruction* DefineFixedDouble(LTemplateResultInstruction<1>* instr,
DoubleRegister reg);
LInstruction* AssignEnvironment(LInstruction* instr);
LInstruction* AssignPointerMap(LInstruction* instr);
enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
// By default we assume that instruction sequences generated for calls
// cannot deoptimize eagerly and we do not attach environment to this
// instruction.
LInstruction* MarkAsCall(
LInstruction* instr, HInstruction* hinstr,
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
void VisitInstruction(HInstruction* current);
void AddInstruction(LInstruction* instr, HInstruction* current);
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
LInstruction* DoArithmeticD(Token::Value op,
HArithmeticBinaryOperation* instr);
LInstruction* DoArithmeticT(Token::Value op, HBinaryOperation* instr);
HInstruction* current_instruction_;
HBasicBlock* current_block_;
HBasicBlock* next_block_;
LAllocator* allocator_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
};
#undef DECLARE_HYDROGEN_ACCESSOR
#undef DECLARE_CONCRETE_INSTRUCTION
} // namespace internal
} // namespace v8
#endif // V8_CRANKSHAFT_S390_LITHIUM_S390_H_
......@@ -1564,6 +1564,12 @@
'../../src/compiler/s390/instruction-codes-s390.h',
'../../src/compiler/s390/instruction-scheduler-s390.cc',
'../../src/compiler/s390/instruction-selector-s390.cc',
'../../src/crankshaft/s390/lithium-codegen-s390.cc',
'../../src/crankshaft/s390/lithium-codegen-s390.h',
'../../src/crankshaft/s390/lithium-gap-resolver-s390.cc',
'../../src/crankshaft/s390/lithium-gap-resolver-s390.h',
'../../src/crankshaft/s390/lithium-s390.cc',
'../../src/crankshaft/s390/lithium-s390.h',
'../../src/debug/s390/debug-s390.cc',
'../../src/full-codegen/s390/full-codegen-s390.cc',
'../../src/ic/s390/access-compiler-s390.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment