Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc
index aba480d..c47a42e 100644
--- a/src/compiler/x64/instruction-selector-x64.cc
+++ b/src/compiler/x64/instruction-selector-x64.cc
@@ -2,24 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
+
+#include "src/base/adapters.h"
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
namespace compiler {
// Adds X64-specific methods for generating operands.
-class X64OperandGenerator FINAL : public OperandGenerator {
+class X64OperandGenerator final : public OperandGenerator {
public:
explicit X64OperandGenerator(InstructionSelector* selector)
: OperandGenerator(selector) {}
- InstructionOperand* TempRegister(Register reg) {
- return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
- Register::ToAllocationIndex(reg));
- }
-
bool CanBeImmediate(Node* node) {
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
@@ -28,6 +27,10 @@
const int64_t value = OpParameter<int64_t>(node);
return value == static_cast<int64_t>(static_cast<int32_t>(value));
}
+ case IrOpcode::kNumberConstant: {
+ const double value = OpParameter<double>(node);
+ return bit_cast<int64_t>(value) == 0;
+ }
default:
return false;
}
@@ -35,15 +38,15 @@
AddressingMode GenerateMemoryOperandInputs(Node* index, int scale_exponent,
Node* base, Node* displacement,
- InstructionOperand* inputs[],
+ InstructionOperand inputs[],
size_t* input_count) {
AddressingMode mode = kMode_MRI;
- if (base != NULL) {
+ if (base != nullptr) {
inputs[(*input_count)++] = UseRegister(base);
- if (index != NULL) {
+ if (index != nullptr) {
DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
inputs[(*input_count)++] = UseRegister(index);
- if (displacement != NULL) {
+ if (displacement != nullptr) {
inputs[(*input_count)++] = UseImmediate(displacement);
static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
kMode_MR4I, kMode_MR8I};
@@ -54,7 +57,7 @@
mode = kMRn_modes[scale_exponent];
}
} else {
- if (displacement == NULL) {
+ if (displacement == nullptr) {
mode = kMode_MR;
} else {
inputs[(*input_count)++] = UseImmediate(displacement);
@@ -62,10 +65,10 @@
}
}
} else {
- DCHECK(index != NULL);
+ DCHECK_NOT_NULL(index);
DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
inputs[(*input_count)++] = UseRegister(index);
- if (displacement != NULL) {
+ if (displacement != nullptr) {
inputs[(*input_count)++] = UseImmediate(displacement);
static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
kMode_M4I, kMode_M8I};
@@ -84,11 +87,11 @@
}
AddressingMode GetEffectiveAddressMemoryOperand(Node* operand,
- InstructionOperand* inputs[],
+ InstructionOperand inputs[],
size_t* input_count) {
BaseWithIndexAndDisplacement64Matcher m(operand, true);
DCHECK(m.matches());
- if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) {
+ if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
m.displacement(), inputs, input_count);
} else {
@@ -105,40 +108,39 @@
void InstructionSelector::VisitLoad(Node* node) {
- MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
- MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
+ LoadRepresentation load_rep = LoadRepresentationOf(node->op());
X64OperandGenerator g(this);
- ArchOpcode opcode;
- switch (rep) {
- case kRepFloat32:
+ ArchOpcode opcode = kArchNop;
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kFloat32:
opcode = kX64Movss;
break;
- case kRepFloat64:
+ case MachineRepresentation::kFloat64:
opcode = kX64Movsd;
break;
- case kRepBit: // Fall through.
- case kRepWord8:
- opcode = typ == kTypeInt32 ? kX64Movsxbl : kX64Movzxbl;
+ case MachineRepresentation::kBit: // Fall through.
+ case MachineRepresentation::kWord8:
+ opcode = load_rep.IsSigned() ? kX64Movsxbl : kX64Movzxbl;
break;
- case kRepWord16:
- opcode = typ == kTypeInt32 ? kX64Movsxwl : kX64Movzxwl;
+ case MachineRepresentation::kWord16:
+ opcode = load_rep.IsSigned() ? kX64Movsxwl : kX64Movzxwl;
break;
- case kRepWord32:
+ case MachineRepresentation::kWord32:
opcode = kX64Movl;
break;
- case kRepTagged: // Fall through.
- case kRepWord64:
+ case MachineRepresentation::kTagged: // Fall through.
+ case MachineRepresentation::kWord64:
opcode = kX64Movq;
break;
- default:
+ case MachineRepresentation::kNone:
UNREACHABLE();
return;
}
- InstructionOperand* outputs[1];
+ InstructionOperand outputs[1];
outputs[0] = g.DefineAsRegister(node);
- InstructionOperand* inputs[3];
+ InstructionOperand inputs[3];
size_t input_count = 0;
AddressingMode mode =
g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
@@ -153,83 +155,118 @@
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
- StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
- MachineType rep = RepresentationOf(store_rep.machine_type());
- if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
- DCHECK(rep == kRepTagged);
- // TODO(dcarney): refactor RecordWrite function to take temp registers
- // and pass them here instead of using fixed regs
- // TODO(dcarney): handle immediate indices.
- InstructionOperand* temps[] = {g.TempRegister(rcx), g.TempRegister(rdx)};
- Emit(kX64StoreWriteBarrier, NULL, g.UseFixed(base, rbx),
- g.UseFixed(index, rcx), g.UseFixed(value, rdx), arraysize(temps),
- temps);
- return;
+ StoreRepresentation store_rep = StoreRepresentationOf(node->op());
+ WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
+ MachineRepresentation rep = store_rep.representation();
+
+ if (write_barrier_kind != kNoWriteBarrier) {
+ DCHECK_EQ(MachineRepresentation::kTagged, rep);
+ AddressingMode addressing_mode;
+ InstructionOperand inputs[3];
+ size_t input_count = 0;
+ inputs[input_count++] = g.UseUniqueRegister(base);
+ if (g.CanBeImmediate(index)) {
+ inputs[input_count++] = g.UseImmediate(index);
+ addressing_mode = kMode_MRI;
+ } else {
+ inputs[input_count++] = g.UseUniqueRegister(index);
+ addressing_mode = kMode_MR1;
+ }
+ inputs[input_count++] = (write_barrier_kind == kMapWriteBarrier)
+ ? g.UseRegister(value)
+ : g.UseUniqueRegister(value);
+ RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
+ switch (write_barrier_kind) {
+ case kNoWriteBarrier:
+ UNREACHABLE();
+ break;
+ case kMapWriteBarrier:
+ record_write_mode = RecordWriteMode::kValueIsMap;
+ break;
+ case kPointerWriteBarrier:
+ record_write_mode = RecordWriteMode::kValueIsPointer;
+ break;
+ case kFullWriteBarrier:
+ record_write_mode = RecordWriteMode::kValueIsAny;
+ break;
+ }
+ InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
+ size_t const temp_count = arraysize(temps);
+ InstructionCode code = kArchStoreWithWriteBarrier;
+ code |= AddressingModeField::encode(addressing_mode);
+ code |= MiscField::encode(static_cast<int>(record_write_mode));
+ Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
+ } else {
+ ArchOpcode opcode = kArchNop;
+ switch (rep) {
+ case MachineRepresentation::kFloat32:
+ opcode = kX64Movss;
+ break;
+ case MachineRepresentation::kFloat64:
+ opcode = kX64Movsd;
+ break;
+ case MachineRepresentation::kBit: // Fall through.
+ case MachineRepresentation::kWord8:
+ opcode = kX64Movb;
+ break;
+ case MachineRepresentation::kWord16:
+ opcode = kX64Movw;
+ break;
+ case MachineRepresentation::kWord32:
+ opcode = kX64Movl;
+ break;
+ case MachineRepresentation::kTagged: // Fall through.
+ case MachineRepresentation::kWord64:
+ opcode = kX64Movq;
+ break;
+ case MachineRepresentation::kNone:
+ UNREACHABLE();
+ return;
+ }
+ InstructionOperand inputs[4];
+ size_t input_count = 0;
+ AddressingMode addressing_mode =
+ g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
+ InstructionCode code =
+ opcode | AddressingModeField::encode(addressing_mode);
+ InstructionOperand value_operand =
+ g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value);
+ inputs[input_count++] = value_operand;
+ Emit(code, 0, static_cast<InstructionOperand*>(nullptr), input_count,
+ inputs);
}
- DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
- ArchOpcode opcode;
- switch (rep) {
- case kRepFloat32:
- opcode = kX64Movss;
- break;
- case kRepFloat64:
- opcode = kX64Movsd;
- break;
- case kRepBit: // Fall through.
- case kRepWord8:
- opcode = kX64Movb;
- break;
- case kRepWord16:
- opcode = kX64Movw;
- break;
- case kRepWord32:
- opcode = kX64Movl;
- break;
- case kRepTagged: // Fall through.
- case kRepWord64:
- opcode = kX64Movq;
- break;
- default:
- UNREACHABLE();
- return;
- }
- InstructionOperand* inputs[4];
- size_t input_count = 0;
- AddressingMode mode =
- g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
- InstructionCode code = opcode | AddressingModeField::encode(mode);
- InstructionOperand* value_operand =
- g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value);
- inputs[input_count++] = value_operand;
- Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs);
}
void InstructionSelector::VisitCheckedLoad(Node* node) {
- MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
- MachineType typ = TypeOf(OpParameter<MachineType>(node));
+ CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
X64OperandGenerator g(this);
Node* const buffer = node->InputAt(0);
Node* const offset = node->InputAt(1);
Node* const length = node->InputAt(2);
- ArchOpcode opcode;
- switch (rep) {
- case kRepWord8:
- opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+ ArchOpcode opcode = kArchNop;
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kWord8:
+ opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
break;
- case kRepWord16:
- opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+ case MachineRepresentation::kWord16:
+ opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
break;
- case kRepWord32:
+ case MachineRepresentation::kWord32:
opcode = kCheckedLoadWord32;
break;
- case kRepFloat32:
+ case MachineRepresentation::kWord64:
+ opcode = kCheckedLoadWord64;
+ break;
+ case MachineRepresentation::kFloat32:
opcode = kCheckedLoadFloat32;
break;
- case kRepFloat64:
+ case MachineRepresentation::kFloat64:
opcode = kCheckedLoadFloat64;
break;
- default:
+ case MachineRepresentation::kBit:
+ case MachineRepresentation::kTagged:
+ case MachineRepresentation::kNone:
UNREACHABLE();
return;
}
@@ -245,7 +282,7 @@
return;
}
}
- InstructionOperand* length_operand =
+ InstructionOperand length_operand =
g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
g.UseRegister(offset), g.TempImmediate(0), length_operand);
@@ -253,34 +290,39 @@
void InstructionSelector::VisitCheckedStore(Node* node) {
- MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+ MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
X64OperandGenerator g(this);
Node* const buffer = node->InputAt(0);
Node* const offset = node->InputAt(1);
Node* const length = node->InputAt(2);
Node* const value = node->InputAt(3);
- ArchOpcode opcode;
+ ArchOpcode opcode = kArchNop;
switch (rep) {
- case kRepWord8:
+ case MachineRepresentation::kWord8:
opcode = kCheckedStoreWord8;
break;
- case kRepWord16:
+ case MachineRepresentation::kWord16:
opcode = kCheckedStoreWord16;
break;
- case kRepWord32:
+ case MachineRepresentation::kWord32:
opcode = kCheckedStoreWord32;
break;
- case kRepFloat32:
+ case MachineRepresentation::kWord64:
+ opcode = kCheckedStoreWord64;
+ break;
+ case MachineRepresentation::kFloat32:
opcode = kCheckedStoreFloat32;
break;
- case kRepFloat64:
+ case MachineRepresentation::kFloat64:
opcode = kCheckedStoreFloat64;
break;
- default:
+ case MachineRepresentation::kBit:
+ case MachineRepresentation::kTagged:
+ case MachineRepresentation::kNone:
UNREACHABLE();
return;
}
- InstructionOperand* value_operand =
+ InstructionOperand value_operand =
g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value);
if (offset->opcode() == IrOpcode::kInt32Add && CanCover(node, offset)) {
Int32Matcher mlength(length);
@@ -288,16 +330,16 @@
if (mlength.HasValue() && moffset.right().HasValue() &&
moffset.right().Value() >= 0 &&
mlength.Value() >= moffset.right().Value()) {
- Emit(opcode, nullptr, g.UseRegister(buffer),
+ Emit(opcode, g.NoOutput(), g.UseRegister(buffer),
g.UseRegister(moffset.left().node()),
g.UseImmediate(moffset.right().node()), g.UseImmediate(length),
value_operand);
return;
}
}
- InstructionOperand* length_operand =
+ InstructionOperand length_operand =
g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
- Emit(opcode, nullptr, g.UseRegister(buffer), g.UseRegister(offset),
+ Emit(opcode, g.NoOutput(), g.UseRegister(buffer), g.UseRegister(offset),
g.TempImmediate(0), length_operand, value_operand);
}
@@ -309,9 +351,9 @@
Int32BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
- InstructionOperand* inputs[4];
+ InstructionOperand inputs[4];
size_t input_count = 0;
- InstructionOperand* outputs[2];
+ InstructionOperand outputs[2];
size_t output_count = 0;
// TODO(turbofan): match complex addressing modes.
@@ -323,7 +365,7 @@
// mov rax, [rbp-0x10]
// add rax, [rbp-0x10]
// jo label
- InstructionOperand* const input = g.UseRegister(left);
+ InstructionOperand const input = g.UseRegister(left);
inputs[input_count++] = input;
inputs[input_count++] = input;
} else if (g.CanBeImmediate(right)) {
@@ -348,14 +390,13 @@
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
- DCHECK_NE(0, static_cast<int>(input_count));
- DCHECK_NE(0, static_cast<int>(output_count));
+ DCHECK_NE(0u, input_count);
+ DCHECK_NE(0u, output_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
- Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
- outputs, input_count, inputs);
- if (cont->IsBranch()) instr->MarkAsControl();
+ selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+ inputs);
}
@@ -368,7 +409,15 @@
void InstructionSelector::VisitWord32And(Node* node) {
- VisitBinop(this, node, kX64And32);
+ X64OperandGenerator g(this);
+ Uint32BinopMatcher m(node);
+ if (m.right().Is(0xff)) {
+ Emit(kX64Movzxbl, g.DefineAsRegister(node), g.Use(m.left().node()));
+ } else if (m.right().Is(0xffff)) {
+ Emit(kX64Movzxwl, g.DefineAsRegister(node), g.Use(m.left().node()));
+ } else {
+ VisitBinop(this, node, kX64And32);
+ }
}
@@ -460,15 +509,15 @@
Node* displacement) {
X64OperandGenerator g(selector);
- InstructionOperand* inputs[4];
+ InstructionOperand inputs[4];
size_t input_count = 0;
AddressingMode mode = g.GenerateMemoryOperandInputs(
index, scale, base, displacement, inputs, &input_count);
- DCHECK_NE(0, static_cast<int>(input_count));
+ DCHECK_NE(0u, input_count);
DCHECK_GE(arraysize(inputs), input_count);
- InstructionOperand* outputs[1];
+ InstructionOperand outputs[1];
outputs[0] = g.DefineAsRegister(result);
opcode = AddressingModeField::encode(mode) | opcode;
@@ -483,8 +532,8 @@
Int32ScaleMatcher m(node, true);
if (m.matches()) {
Node* index = node->InputAt(0);
- Node* base = m.power_of_two_plus_one() ? index : NULL;
- EmitLea(this, kX64Lea32, node, index, m.scale(), base, NULL);
+ Node* base = m.power_of_two_plus_one() ? index : nullptr;
+ EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr);
return;
}
VisitWord32Shift(this, node, kX64Shl32);
@@ -549,13 +598,49 @@
}
+void InstructionSelector::VisitWord64Clz(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitWord32Clz(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64Lzcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitWord64Ctz(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64Tzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitWord32Ctz(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64Tzcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitWord32Popcnt(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64Popcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitWord64Popcnt(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
void InstructionSelector::VisitInt32Add(Node* node) {
X64OperandGenerator g(this);
// Try to match the Add to a leal pattern
BaseWithIndexAndDisplacement32Matcher m(node);
if (m.matches() &&
- (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) {
+ (m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) {
EmitLea(this, kX64Lea32, node, m.index(), m.scale(), m.base(),
m.displacement());
return;
@@ -571,6 +656,16 @@
}
+void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
+ FlagsContinuation cont(kOverflow, ovf);
+ VisitBinop(this, node, kX64Add, &cont);
+ }
+ FlagsContinuation cont;
+ VisitBinop(this, node, kX64Add, &cont);
+}
+
+
void InstructionSelector::VisitInt32Sub(Node* node) {
X64OperandGenerator g(this);
Int32BinopMatcher m(node);
@@ -601,6 +696,16 @@
}
+void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
+ FlagsContinuation cont(kOverflow, ovf);
+ return VisitBinop(this, node, kX64Sub, &cont);
+ }
+ FlagsContinuation cont;
+ VisitBinop(this, node, kX64Sub, &cont);
+}
+
+
namespace {
void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
@@ -638,7 +743,7 @@
void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
X64OperandGenerator g(selector);
- InstructionOperand* temps[] = {g.TempRegister(rdx)};
+ InstructionOperand temps[] = {g.TempRegister(rdx)};
selector->Emit(
opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
@@ -659,8 +764,8 @@
Int32ScaleMatcher m(node, true);
if (m.matches()) {
Node* index = node->InputAt(0);
- Node* base = m.power_of_two_plus_one() ? index : NULL;
- EmitLea(this, kX64Lea32, node, index, m.scale(), base, NULL);
+ Node* base = m.power_of_two_plus_one() ? index : nullptr;
+ EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr);
return;
}
VisitMul(this, node, kX64Imul32);
@@ -724,7 +829,7 @@
void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
X64OperandGenerator g(this);
- Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+ Emit(kSSEFloat32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
}
@@ -752,6 +857,70 @@
}
+void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
+ InstructionOperand outputs[2];
+ size_t output_count = 0;
+ outputs[output_count++] = g.DefineAsRegister(node);
+
+ Node* success_output = NodeProperties::FindProjection(node, 1);
+ if (success_output) {
+ outputs[output_count++] = g.DefineAsRegister(success_output);
+ }
+
+ Emit(kSSEFloat32ToInt64, output_count, outputs, 1, inputs);
+}
+
+
+void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
+ InstructionOperand outputs[2];
+ size_t output_count = 0;
+ outputs[output_count++] = g.DefineAsRegister(node);
+
+ Node* success_output = NodeProperties::FindProjection(node, 1);
+ if (success_output) {
+ outputs[output_count++] = g.DefineAsRegister(success_output);
+ }
+
+ Emit(kSSEFloat64ToInt64, output_count, outputs, 1, inputs);
+}
+
+
+void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
+ InstructionOperand outputs[2];
+ size_t output_count = 0;
+ outputs[output_count++] = g.DefineAsRegister(node);
+
+ Node* success_output = NodeProperties::FindProjection(node, 1);
+ if (success_output) {
+ outputs[output_count++] = g.DefineAsRegister(success_output);
+ }
+
+ Emit(kSSEFloat32ToUint64, output_count, outputs, 1, inputs);
+}
+
+
+void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
+ InstructionOperand outputs[2];
+ size_t output_count = 0;
+ outputs[output_count++] = g.DefineAsRegister(node);
+
+ Node* success_output = NodeProperties::FindProjection(node, 1);
+ if (success_output) {
+ outputs[output_count++] = g.DefineAsRegister(success_output);
+ }
+
+ Emit(kSSEFloat64ToUint64, output_count, outputs, 1, inputs);
+}
+
+
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
X64OperandGenerator g(this);
Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@@ -795,9 +964,62 @@
}
+namespace {
+
+void VisitRO(InstructionSelector* selector, Node* node,
+ InstructionCode opcode) {
+ X64OperandGenerator g(selector);
+ selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void VisitRR(InstructionSelector* selector, Node* node,
+ InstructionCode opcode) {
+ X64OperandGenerator g(selector);
+ selector->Emit(opcode, g.DefineAsRegister(node),
+ g.UseRegister(node->InputAt(0)));
+}
+
+
+void VisitFloatBinop(InstructionSelector* selector, Node* node,
+ ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
+ X64OperandGenerator g(selector);
+ InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
+ InstructionOperand operand1 = g.Use(node->InputAt(1));
+ if (selector->IsSupported(AVX)) {
+ selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
+ } else {
+ selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
+ }
+}
+
+
+void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input,
+ ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
+ X64OperandGenerator g(selector);
+ if (selector->IsSupported(AVX)) {
+ selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input));
+ } else {
+ selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input));
+ }
+}
+
+} // namespace
+
+
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
- X64OperandGenerator g(this);
- Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+ VisitRO(this, node, kSSEFloat64ToFloat32);
+}
+
+
+void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
+ switch (TruncationModeOf(node->op())) {
+ case TruncationMode::kJavaScript:
+ return VisitRR(this, node, kArchTruncateDoubleToI);
+ case TruncationMode::kRoundToZero:
+ return VisitRO(this, node, kSSEFloat64ToInt32);
+ }
+ UNREACHABLE();
}
@@ -824,96 +1046,200 @@
}
-void InstructionSelector::VisitFloat64Add(Node* node) {
+void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) {
X64OperandGenerator g(this);
- if (IsSupported(AVX)) {
- Emit(kAVXFloat64Add, g.DefineAsRegister(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
- } else {
- Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+ Emit(kSSEInt64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kSSEInt64ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitRoundUint64ToFloat32(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand temps[] = {g.TempRegister()};
+ Emit(kSSEUint64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
+ arraysize(temps), temps);
+}
+
+
+void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand temps[] = {g.TempRegister()};
+ Emit(kSSEUint64ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
+ arraysize(temps), temps);
+}
+
+
+void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64BitcastFI, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitBitcastFloat64ToInt64(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64BitcastDL, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64BitcastIF, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kX64BitcastLD, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat32Add(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat32Add, kSSEFloat32Add);
+}
+
+
+void InstructionSelector::VisitFloat32Sub(Node* node) {
+ X64OperandGenerator g(this);
+ Float32BinopMatcher m(node);
+ if (m.left().IsMinusZero()) {
+ VisitFloatUnop(this, node, m.right().node(), kAVXFloat32Neg,
+ kSSEFloat32Neg);
+ return;
}
+ VisitFloatBinop(this, node, kAVXFloat32Sub, kSSEFloat32Sub);
+}
+
+
+void InstructionSelector::VisitFloat32Mul(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat32Mul, kSSEFloat32Mul);
+}
+
+
+void InstructionSelector::VisitFloat32Div(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat32Div, kSSEFloat32Div);
+}
+
+
+void InstructionSelector::VisitFloat32Max(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat32Max, kSSEFloat32Max);
+}
+
+
+void InstructionSelector::VisitFloat32Min(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat32Min, kSSEFloat32Min);
+}
+
+
+void InstructionSelector::VisitFloat32Abs(Node* node) {
+ VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs);
+}
+
+
+void InstructionSelector::VisitFloat32Sqrt(Node* node) {
+ VisitRO(this, node, kSSEFloat32Sqrt);
+}
+
+
+void InstructionSelector::VisitFloat64Add(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat64Add, kSSEFloat64Add);
}
void InstructionSelector::VisitFloat64Sub(Node* node) {
X64OperandGenerator g(this);
- if (IsSupported(AVX)) {
- Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
- } else {
- Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+ Float64BinopMatcher m(node);
+ if (m.left().IsMinusZero()) {
+ if (m.right().IsFloat64RoundDown() &&
+ CanCover(m.node(), m.right().node())) {
+ if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+ CanCover(m.right().node(), m.right().InputAt(0))) {
+ Float64BinopMatcher mright0(m.right().InputAt(0));
+ if (mright0.left().IsMinusZero()) {
+ Emit(kSSEFloat64Round | MiscField::encode(kRoundUp),
+ g.DefineAsRegister(node), g.UseRegister(mright0.right().node()));
+ return;
+ }
+ }
+ }
+ VisitFloatUnop(this, node, m.right().node(), kAVXFloat64Neg,
+ kSSEFloat64Neg);
+ return;
}
+ VisitFloatBinop(this, node, kAVXFloat64Sub, kSSEFloat64Sub);
}
void InstructionSelector::VisitFloat64Mul(Node* node) {
- X64OperandGenerator g(this);
- if (IsSupported(AVX)) {
- Emit(kAVXFloat64Mul, g.DefineAsRegister(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
- } else {
- Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
- }
+ VisitFloatBinop(this, node, kAVXFloat64Mul, kSSEFloat64Mul);
}
void InstructionSelector::VisitFloat64Div(Node* node) {
- X64OperandGenerator g(this);
- if (IsSupported(AVX)) {
- Emit(kAVXFloat64Div, g.DefineAsRegister(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
- } else {
- Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
- }
+ VisitFloatBinop(this, node, kAVXFloat64Div, kSSEFloat64Div);
}
void InstructionSelector::VisitFloat64Mod(Node* node) {
X64OperandGenerator g(this);
- InstructionOperand* temps[] = {g.TempRegister(rax)};
+ InstructionOperand temps[] = {g.TempRegister(rax)};
Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
temps);
}
+void InstructionSelector::VisitFloat64Max(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat64Max, kSSEFloat64Max);
+}
+
+
+void InstructionSelector::VisitFloat64Min(Node* node) {
+ VisitFloatBinop(this, node, kAVXFloat64Min, kSSEFloat64Min);
+}
+
+
+void InstructionSelector::VisitFloat64Abs(Node* node) {
+ VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
+}
+
+
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
- X64OperandGenerator g(this);
- Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+ VisitRO(this, node, kSSEFloat64Sqrt);
}
-namespace {
-
-void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
- Node* node) {
- X64OperandGenerator g(selector);
- selector->Emit(opcode, g.DefineAsRegister(node),
- g.UseRegister(node->InputAt(0)));
-}
-
-} // namespace
-
-
-void InstructionSelector::VisitFloat64Floor(Node* node) {
- DCHECK(CpuFeatures::IsSupported(SSE4_1));
- VisitRRFloat64(this, kSSEFloat64Floor, node);
+void InstructionSelector::VisitFloat32RoundDown(Node* node) {
+ VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundDown));
}
-void InstructionSelector::VisitFloat64Ceil(Node* node) {
- DCHECK(CpuFeatures::IsSupported(SSE4_1));
- VisitRRFloat64(this, kSSEFloat64Ceil, node);
+void InstructionSelector::VisitFloat64RoundDown(Node* node) {
+ VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
+}
+
+
+void InstructionSelector::VisitFloat32RoundUp(Node* node) {
+ VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundUp));
+}
+
+
+void InstructionSelector::VisitFloat64RoundUp(Node* node) {
+ VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundUp));
+}
+
+
+void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
+ VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToZero));
}
void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
- DCHECK(CpuFeatures::IsSupported(SSE4_1));
- VisitRRFloat64(this, kSSEFloat64RoundTruncate, node);
+ VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
}
@@ -922,64 +1248,70 @@
}
-void InstructionSelector::VisitCall(Node* node) {
- X64OperandGenerator g(this);
- const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
-
- FrameStateDescriptor* frame_state_descriptor = NULL;
- if (descriptor->NeedsFrameState()) {
- frame_state_descriptor = GetFrameStateDescriptor(
- node->InputAt(static_cast<int>(descriptor->InputCount())));
- }
-
- CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
-
- // Compute InstructionOperands for inputs and outputs.
- InitializeCallBuffer(node, &buffer, true, true);
-
- // Push any stack arguments.
- for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
- input != buffer.pushed_nodes.rend(); input++) {
- // TODO(titzer): handle pushing double parameters.
- Emit(kX64Push, NULL,
- g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
- }
-
- // Select the appropriate opcode based on the call type.
- InstructionCode opcode;
- switch (descriptor->kind()) {
- case CallDescriptor::kCallCodeObject: {
- opcode = kArchCallCodeObject;
- break;
- }
- case CallDescriptor::kCallJSFunction:
- opcode = kArchCallJSFunction;
- break;
- default:
- UNREACHABLE();
- return;
- }
- opcode |= MiscField::encode(descriptor->flags());
-
- // Emit the call instruction.
- InstructionOperand** first_output =
- buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
- Instruction* call_instr =
- Emit(opcode, buffer.outputs.size(), first_output,
- buffer.instruction_args.size(), &buffer.instruction_args.front());
- call_instr->MarkAsCall();
+void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
+ VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToNearest));
}
+void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
+ VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToNearest));
+}
+
+
+void InstructionSelector::EmitPrepareArguments(
+ ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
+ Node* node) {
+ X64OperandGenerator g(this);
+
+ // Prepare for C function call.
+ if (descriptor->IsCFunctionCall()) {
+ Emit(kArchPrepareCallCFunction |
+ MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
+ 0, nullptr, 0, nullptr);
+
+ // Poke any stack arguments.
+ for (size_t n = 0; n < arguments->size(); ++n) {
+ PushParameter input = (*arguments)[n];
+ if (input.node()) {
+ int slot = static_cast<int>(n);
+ InstructionOperand value = g.CanBeImmediate(input.node())
+ ? g.UseImmediate(input.node())
+ : g.UseRegister(input.node());
+ Emit(kX64Poke | MiscField::encode(slot), g.NoOutput(), value);
+ }
+ }
+ } else {
+ // Push any stack arguments.
+ for (PushParameter input : base::Reversed(*arguments)) {
+ // TODO(titzer): X64Push cannot handle stack->stack double moves
+ // because there is no way to encode fixed double slots.
+ InstructionOperand value =
+ g.CanBeImmediate(input.node())
+ ? g.UseImmediate(input.node())
+ : IsSupported(ATOM) ||
+ sequence()->IsFloat(GetVirtualRegister(input.node()))
+ ? g.UseRegister(input.node())
+ : g.Use(input.node());
+ Emit(kX64Push, g.NoOutput(), value);
+ }
+ }
+}
+
+
+bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
+
+
+namespace {
+
// Shared routine for multiple compare operations.
-static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
- InstructionOperand* left, InstructionOperand* right,
- FlagsContinuation* cont) {
+void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+ InstructionOperand left, InstructionOperand right,
+ FlagsContinuation* cont) {
X64OperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
- selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
- g.Label(cont->false_block()))->MarkAsControl();
+ selector->Emit(opcode, g.NoOutput(), left, right,
+ g.Label(cont->true_block()), g.Label(cont->false_block()));
} else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
@@ -988,9 +1320,9 @@
// Shared routine for multiple compare operations.
-static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
- Node* left, Node* right, FlagsContinuation* cont,
- bool commutative) {
+void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+ Node* left, Node* right, FlagsContinuation* cont,
+ bool commutative) {
X64OperandGenerator g(selector);
if (commutative && g.CanBeBetterLeftOperand(right)) {
std::swap(left, right);
@@ -1000,8 +1332,8 @@
// Shared routine for multiple word compare operations.
-static void VisitWordCompare(InstructionSelector* selector, Node* node,
- InstructionCode opcode, FlagsContinuation* cont) {
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+ InstructionCode opcode, FlagsContinuation* cont) {
X64OperandGenerator g(selector);
Node* const left = node->InputAt(0);
Node* const right = node->InputAt(1);
@@ -1019,22 +1351,65 @@
}
+// Shared routine for 64-bit word comparison operations.
+void VisitWord64Compare(InstructionSelector* selector, Node* node,
+ FlagsContinuation* cont) {
+ X64OperandGenerator g(selector);
+ Int64BinopMatcher m(node);
+ if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
+ LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
+ ExternalReference js_stack_limit =
+ ExternalReference::address_of_stack_limit(selector->isolate());
+ if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
+ // Compare(Load(js_stack_limit), LoadStackPointer)
+ if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
+ InstructionCode opcode = cont->Encode(kX64StackCheck);
+ if (cont->IsBranch()) {
+ selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
+ g.Label(cont->false_block()));
+ } else {
+ DCHECK(cont->IsSet());
+ selector->Emit(opcode, g.DefineAsRegister(cont->result()));
+ }
+ return;
+ }
+ }
+ VisitWordCompare(selector, node, kX64Cmp, cont);
+}
+
+
// Shared routine for comparison with zero.
-static void VisitCompareZero(InstructionSelector* selector, Node* node,
- InstructionCode opcode, FlagsContinuation* cont) {
+void VisitCompareZero(InstructionSelector* selector, Node* node,
+ InstructionCode opcode, FlagsContinuation* cont) {
X64OperandGenerator g(selector);
VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont);
}
-// Shared routine for multiple float64 compare operations.
-static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
- FlagsContinuation* cont) {
- VisitCompare(selector, kSSEFloat64Cmp, node->InputAt(0), node->InputAt(1),
- cont, node->op()->HasProperty(Operator::kCommutative));
+// Shared routine for multiple float32 compare operations (inputs commuted).
+void VisitFloat32Compare(InstructionSelector* selector, Node* node,
+ FlagsContinuation* cont) {
+ Node* const left = node->InputAt(0);
+ Node* const right = node->InputAt(1);
+ InstructionCode const opcode =
+ selector->IsSupported(AVX) ? kAVXFloat32Cmp : kSSEFloat32Cmp;
+ VisitCompare(selector, opcode, right, left, cont, false);
}
+// Shared routine for multiple float64 compare operations (inputs commuted).
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+ FlagsContinuation* cont) {
+ Node* const left = node->InputAt(0);
+ Node* const right = node->InputAt(1);
+ InstructionCode const opcode =
+ selector->IsSupported(AVX) ? kAVXFloat64Cmp : kSSEFloat64Cmp;
+ VisitCompare(selector, opcode, right, left, cont, false);
+}
+
+} // namespace
+
+
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) {
X64OperandGenerator g(this);
@@ -1044,25 +1419,12 @@
FlagsContinuation cont(kNotEqual, tbranch, fbranch);
// Try to combine with comparisons against 0 by simply inverting the branch.
- while (CanCover(user, value)) {
- if (value->opcode() == IrOpcode::kWord32Equal) {
- Int32BinopMatcher m(value);
- if (m.right().Is(0)) {
- user = value;
- value = m.left().node();
- cont.Negate();
- } else {
- break;
- }
- } else if (value->opcode() == IrOpcode::kWord64Equal) {
- Int64BinopMatcher m(value);
- if (m.right().Is(0)) {
- user = value;
- value = m.left().node();
- cont.Negate();
- } else {
- break;
- }
+ while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) {
+ Int32BinopMatcher m(value);
+ if (m.right().Is(0)) {
+ user = value;
+ value = m.left().node();
+ cont.Negate();
} else {
break;
}
@@ -1086,39 +1448,69 @@
case IrOpcode::kUint32LessThanOrEqual:
cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
return VisitWordCompare(this, value, kX64Cmp32, &cont);
- case IrOpcode::kWord64Equal:
+ case IrOpcode::kWord64Equal: {
cont.OverwriteAndNegateIfEqual(kEqual);
- return VisitWordCompare(this, value, kX64Cmp, &cont);
+ Int64BinopMatcher m(value);
+ if (m.right().Is(0)) {
+ // Try to combine the branch with a comparison.
+ Node* const user = m.node();
+ Node* const value = m.left().node();
+ if (CanCover(user, value)) {
+ switch (value->opcode()) {
+ case IrOpcode::kInt64Sub:
+ return VisitWord64Compare(this, value, &cont);
+ case IrOpcode::kWord64And:
+ return VisitWordCompare(this, value, kX64Test, &cont);
+ default:
+ break;
+ }
+ }
+ return VisitCompareZero(this, value, kX64Cmp, &cont);
+ }
+ return VisitWord64Compare(this, value, &cont);
+ }
case IrOpcode::kInt64LessThan:
cont.OverwriteAndNegateIfEqual(kSignedLessThan);
- return VisitWordCompare(this, value, kX64Cmp, &cont);
+ return VisitWord64Compare(this, value, &cont);
case IrOpcode::kInt64LessThanOrEqual:
cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
- return VisitWordCompare(this, value, kX64Cmp, &cont);
+ return VisitWord64Compare(this, value, &cont);
case IrOpcode::kUint64LessThan:
cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
- return VisitWordCompare(this, value, kX64Cmp, &cont);
+ return VisitWord64Compare(this, value, &cont);
+ case IrOpcode::kUint64LessThanOrEqual:
+ cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+ return VisitWord64Compare(this, value, &cont);
+ case IrOpcode::kFloat32Equal:
+ cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
+ return VisitFloat32Compare(this, value, &cont);
+ case IrOpcode::kFloat32LessThan:
+ cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
+ return VisitFloat32Compare(this, value, &cont);
+ case IrOpcode::kFloat32LessThanOrEqual:
+ cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
+ return VisitFloat32Compare(this, value, &cont);
case IrOpcode::kFloat64Equal:
cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kFloat64LessThan:
- cont.OverwriteAndNegateIfEqual(kUnorderedLessThan);
+ cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kFloat64LessThanOrEqual:
- cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+ cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
- if (OpParameter<size_t>(value) == 1u) {
+ if (ProjectionIndexOf(value->op()) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
- // <Operation> is either NULL, which means there's no use of the
+ // <Operation> is either nullptr, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
- Node* node = value->InputAt(0);
- Node* result = node->FindProjection(0);
- if (result == NULL || IsDefined(result)) {
+ Node* const node = value->InputAt(0);
+ Node* const result = NodeProperties::FindProjection(node, 0);
+ if (result == nullptr || IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
cont.OverwriteAndNegateIfEqual(kOverflow);
@@ -1126,6 +1518,12 @@
case IrOpcode::kInt32SubWithOverflow:
cont.OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop(this, node, kX64Sub32, &cont);
+ case IrOpcode::kInt64AddWithOverflow:
+ cont.OverwriteAndNegateIfEqual(kOverflow);
+ return VisitBinop(this, node, kX64Add, &cont);
+ case IrOpcode::kInt64SubWithOverflow:
+ cont.OverwriteAndNegateIfEqual(kOverflow);
+ return VisitBinop(this, node, kX64Sub, &cont);
default:
break;
}
@@ -1135,7 +1533,7 @@
case IrOpcode::kInt32Sub:
return VisitWordCompare(this, value, kX64Cmp32, &cont);
case IrOpcode::kInt64Sub:
- return VisitWordCompare(this, value, kX64Cmp, &cont);
+ return VisitWord64Compare(this, value, &cont);
case IrOpcode::kWord32And:
return VisitWordCompare(this, value, kX64Test32, &cont);
case IrOpcode::kWord64And:
@@ -1150,6 +1548,37 @@
}
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
+ X64OperandGenerator g(this);
+ InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
+
+ // Emit either ArchTableSwitch or ArchLookupSwitch.
+ size_t table_space_cost = 4 + sw.value_range;
+ size_t table_time_cost = 3;
+ size_t lookup_space_cost = 3 + 2 * sw.case_count;
+ size_t lookup_time_cost = sw.case_count;
+ if (sw.case_count > 4 &&
+ table_space_cost + 3 * table_time_cost <=
+ lookup_space_cost + 3 * lookup_time_cost &&
+ sw.min_value > std::numeric_limits<int32_t>::min()) {
+ InstructionOperand index_operand = g.TempRegister();
+ if (sw.min_value) {
+ // The leal automatically zero extends, so result is a valid 64-bit index.
+ Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand,
+ value_operand, g.TempImmediate(-sw.min_value));
+ } else {
+ // Zero extend, because we use it as 64-bit index into the jump table.
+ Emit(kX64Movl, index_operand, value_operand);
+ }
+ // Generate a table lookup.
+ return EmitTableSwitch(sw, index_operand);
+ }
+
+ // Generate a sequence of conditional jumps.
+ return EmitLookupSwitch(sw, value_operand);
+}
+
+
void InstructionSelector::VisitWord32Equal(Node* const node) {
Node* user = node;
FlagsContinuation cont(kEqual, node);
@@ -1211,43 +1640,29 @@
void InstructionSelector::VisitWord64Equal(Node* const node) {
- Node* user = node;
FlagsContinuation cont(kEqual, node);
- Int64BinopMatcher m(user);
+ Int64BinopMatcher m(node);
if (m.right().Is(0)) {
- Node* value = m.left().node();
-
- // Try to combine with comparisons against 0 by simply inverting the branch.
- while (CanCover(user, value) && value->opcode() == IrOpcode::kWord64Equal) {
- Int64BinopMatcher m(value);
- if (m.right().Is(0)) {
- user = value;
- value = m.left().node();
- cont.Negate();
- } else {
- break;
- }
- }
-
- // Try to combine the branch with a comparison.
+ // Try to combine the equality check with a comparison.
+ Node* const user = m.node();
+ Node* const value = m.left().node();
if (CanCover(user, value)) {
switch (value->opcode()) {
case IrOpcode::kInt64Sub:
- return VisitWordCompare(this, value, kX64Cmp, &cont);
+ return VisitWord64Compare(this, value, &cont);
case IrOpcode::kWord64And:
return VisitWordCompare(this, value, kX64Test, &cont);
default:
break;
}
}
- return VisitCompareZero(this, value, kX64Cmp, &cont);
}
- VisitWordCompare(this, node, kX64Cmp, &cont);
+ VisitWord64Compare(this, node, &cont);
}
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
- if (Node* ovf = node->FindProjection(1)) {
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
VisitBinop(this, node, kX64Add32, &cont);
}
@@ -1257,7 +1672,7 @@
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
- if (Node* ovf = node->FindProjection(1)) {
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kX64Sub32, &cont);
}
@@ -1268,19 +1683,43 @@
void InstructionSelector::VisitInt64LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node);
- VisitWordCompare(this, node, kX64Cmp, &cont);
+ VisitWord64Compare(this, node, &cont);
}
void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node);
- VisitWordCompare(this, node, kX64Cmp, &cont);
+ VisitWord64Compare(this, node, &cont);
}
void InstructionSelector::VisitUint64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node);
- VisitWordCompare(this, node, kX64Cmp, &cont);
+ VisitWord64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
+ FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+ VisitWord64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32Equal(Node* node) {
+ FlagsContinuation cont(kUnorderedEqual, node);
+ VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThan(Node* node) {
+ FlagsContinuation cont(kUnsignedGreaterThan, node);
+ VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
+ FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node);
+ VisitFloat32Compare(this, node, &cont);
}
@@ -1291,27 +1730,79 @@
void InstructionSelector::VisitFloat64LessThan(Node* node) {
- FlagsContinuation cont(kUnorderedLessThan, node);
+ FlagsContinuation cont(kUnsignedGreaterThan, node);
VisitFloat64Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
- FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+ FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node);
VisitFloat64Compare(this, node, &cont);
}
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
+ g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+ X64OperandGenerator g(this);
+ Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
+ g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+ X64OperandGenerator g(this);
+ Node* left = node->InputAt(0);
+ Node* right = node->InputAt(1);
+ Float64Matcher mleft(left);
+ if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
+ Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
+ return;
+ }
+ Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
+ g.UseRegister(left), g.Use(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+ X64OperandGenerator g(this);
+ Node* left = node->InputAt(0);
+ Node* right = node->InputAt(1);
+ Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
+ g.UseRegister(left), g.Use(right));
+}
+
+
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
- if (CpuFeatures::IsSupported(SSE4_1)) {
- return MachineOperatorBuilder::kFloat64Floor |
- MachineOperatorBuilder::kFloat64Ceil |
- MachineOperatorBuilder::kFloat64RoundTruncate |
- MachineOperatorBuilder::kWord32ShiftIsSafe;
+ MachineOperatorBuilder::Flags flags =
+ MachineOperatorBuilder::kFloat32Max |
+ MachineOperatorBuilder::kFloat32Min |
+ MachineOperatorBuilder::kFloat64Max |
+ MachineOperatorBuilder::kFloat64Min |
+ MachineOperatorBuilder::kWord32ShiftIsSafe |
+ MachineOperatorBuilder::kWord32Ctz | MachineOperatorBuilder::kWord64Ctz;
+ if (CpuFeatures::IsSupported(POPCNT)) {
+ flags |= MachineOperatorBuilder::kWord32Popcnt |
+ MachineOperatorBuilder::kWord64Popcnt;
}
- return MachineOperatorBuilder::kNoFlags;
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ flags |= MachineOperatorBuilder::kFloat32RoundDown |
+ MachineOperatorBuilder::kFloat64RoundDown |
+ MachineOperatorBuilder::kFloat32RoundUp |
+ MachineOperatorBuilder::kFloat64RoundUp |
+ MachineOperatorBuilder::kFloat32RoundTruncate |
+ MachineOperatorBuilder::kFloat64RoundTruncate |
+ MachineOperatorBuilder::kFloat32RoundTiesEven |
+ MachineOperatorBuilder::kFloat64RoundTiesEven;
+ }
+ return flags;
}
} // namespace compiler