Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc
index d90deae..240a4f2 100644
--- a/src/compiler/arm64/instruction-selector-arm64.cc
+++ b/src/compiler/arm64/instruction-selector-arm64.cc
@@ -40,7 +40,9 @@
// Use the zero register if the node has the immediate value zero, otherwise
// assign a register.
InstructionOperand UseRegisterOrImmediateZero(Node* node) {
- if (IsIntegerConstant(node) && (GetIntegerConstantValue(node) == 0)) {
+ if ((IsIntegerConstant(node) && (GetIntegerConstantValue(node) == 0)) ||
+ (IsFloatConstant(node) &&
+ (bit_cast<int64_t>(GetFloatConstantValue(node)) == V8_INT64_C(0)))) {
return UseImmediate(node);
}
return UseRegister(node);
@@ -68,6 +70,19 @@
return OpParameter<int64_t>(node);
}
+ bool IsFloatConstant(Node* node) {
+ return (node->opcode() == IrOpcode::kFloat32Constant) ||
+ (node->opcode() == IrOpcode::kFloat64Constant);
+ }
+
+ double GetFloatConstantValue(Node* node) {
+ if (node->opcode() == IrOpcode::kFloat32Constant) {
+ return OpParameter<float>(node);
+ }
+ DCHECK_EQ(IrOpcode::kFloat64Constant, node->opcode());
+ return OpParameter<double>(node);
+ }
+
bool CanBeImmediate(Node* node, ImmediateMode mode) {
return IsIntegerConstant(node) &&
CanBeImmediate(GetIntegerConstantValue(node), mode);
@@ -106,6 +121,13 @@
return false;
}
+ bool CanBeLoadStoreShiftImmediate(Node* node, MachineRepresentation rep) {
+ // TODO(arm64): Load and Store on 128 bit Q registers is not supported yet.
+ DCHECK_NE(MachineRepresentation::kSimd128, rep);
+ return IsIntegerConstant(node) &&
+ (GetIntegerConstantValue(node) == ElementSizeLog2Of(rep));
+ }
+
private:
bool IsLoadStoreImmediate(int64_t value, LSDataSize size) {
return Assembler::IsImmLSScaled(value, size) ||
@@ -211,6 +233,28 @@
return false;
}
+bool TryMatchLoadStoreShift(Arm64OperandGenerator* g,
+ InstructionSelector* selector,
+ MachineRepresentation rep, Node* node, Node* index,
+ InstructionOperand* index_op,
+ InstructionOperand* shift_immediate_op) {
+ if (!selector->CanCover(node, index)) return false;
+ if (index->InputCount() != 2) return false;
+ Node* left = index->InputAt(0);
+ Node* right = index->InputAt(1);
+ switch (index->opcode()) {
+ case IrOpcode::kWord32Shl:
+ case IrOpcode::kWord64Shl:
+ if (!g->CanBeLoadStoreShiftImmediate(right, rep)) {
+ return false;
+ }
+ *index_op = g->UseRegister(left);
+ *shift_immediate_op = g->UseImmediate(right);
+ return true;
+ default:
+ return false;
+ }
+}
// Shared routine for multiple binary operations.
template <typename Matcher>
@@ -344,12 +388,16 @@
void InstructionSelector::VisitLoad(Node* node) {
LoadRepresentation load_rep = LoadRepresentationOf(node->op());
+ MachineRepresentation rep = load_rep.representation();
Arm64OperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
- ArchOpcode opcode = kArchNop;
+ InstructionCode opcode = kArchNop;
ImmediateMode immediate_mode = kNoImmediate;
- switch (load_rep.representation()) {
+ InstructionOperand inputs[3];
+ size_t input_count = 0;
+ InstructionOperand outputs[1];
+ switch (rep) {
case MachineRepresentation::kFloat32:
opcode = kArm64LdrS;
immediate_mode = kLoadStoreImm32;
@@ -381,13 +429,25 @@
UNREACHABLE();
return;
}
+
+ outputs[0] = g.DefineAsRegister(node);
+ inputs[0] = g.UseRegister(base);
+
if (g.CanBeImmediate(index, immediate_mode)) {
- Emit(opcode | AddressingModeField::encode(kMode_MRI),
- g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
+ input_count = 2;
+ inputs[1] = g.UseImmediate(index);
+ opcode |= AddressingModeField::encode(kMode_MRI);
+ } else if (TryMatchLoadStoreShift(&g, this, rep, node, index, &inputs[1],
+ &inputs[2])) {
+ input_count = 3;
+ opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
} else {
- Emit(opcode | AddressingModeField::encode(kMode_MRR),
- g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
+ input_count = 2;
+ inputs[1] = g.UseRegister(index);
+ opcode |= AddressingModeField::encode(kMode_MRR);
}
+
+ Emit(opcode, arraysize(outputs), outputs, input_count, inputs);
}
@@ -441,7 +501,9 @@
code |= MiscField::encode(static_cast<int>(record_write_mode));
Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
} else {
- ArchOpcode opcode = kArchNop;
+ InstructionOperand inputs[4];
+ size_t input_count = 0;
+ InstructionCode opcode = kArchNop;
ImmediateMode immediate_mode = kNoImmediate;
switch (rep) {
case MachineRepresentation::kFloat32:
@@ -475,13 +537,25 @@
UNREACHABLE();
return;
}
+
+ inputs[0] = g.UseRegisterOrImmediateZero(value);
+ inputs[1] = g.UseRegister(base);
+
if (g.CanBeImmediate(index, immediate_mode)) {
- Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
- g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
+ input_count = 3;
+ inputs[2] = g.UseImmediate(index);
+ opcode |= AddressingModeField::encode(kMode_MRI);
+ } else if (TryMatchLoadStoreShift(&g, this, rep, node, index, &inputs[2],
+ &inputs[3])) {
+ input_count = 4;
+ opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
} else {
- Emit(opcode | AddressingModeField::encode(kMode_MRR), g.NoOutput(),
- g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
+ input_count = 3;
+ inputs[2] = g.UseRegister(index);
+ opcode |= AddressingModeField::encode(kMode_MRR);
}
+
+ Emit(opcode, 0, nullptr, input_count, inputs);
}
}
@@ -559,7 +633,8 @@
return;
}
Emit(opcode, g.NoOutput(), g.UseRegister(buffer), g.UseRegister(offset),
- g.UseOperand(length, kArithmeticImm), g.UseRegister(value));
+ g.UseOperand(length, kArithmeticImm),
+ g.UseRegisterOrImmediateZero(value));
}
@@ -1396,6 +1471,20 @@
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
return;
}
+ case IrOpcode::kLoad: {
+ // As for the operations above, a 32-bit load will implicitly clear the
+ // top 32 bits of the destination register.
+ LoadRepresentation load_rep = LoadRepresentationOf(value->op());
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kWord8:
+ case MachineRepresentation::kWord16:
+ case MachineRepresentation::kWord32:
+ Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
+ return;
+ default:
+ break;
+ }
+ }
default:
break;
}
@@ -1407,15 +1496,12 @@
VisitRR(this, kArm64Float64ToFloat32, node);
}
+void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) {
+ VisitRR(this, kArchTruncateDoubleToI, node);
+}
-void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
- switch (TruncationModeOf(node->op())) {
- case TruncationMode::kJavaScript:
- return VisitRR(this, kArchTruncateDoubleToI, node);
- case TruncationMode::kRoundToZero:
- return VisitRR(this, kArm64Float64ToInt32, node);
- }
- UNREACHABLE();
+void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
+ VisitRR(this, kArm64Float64ToInt32, node);
}
@@ -1491,6 +1577,9 @@
VisitRRR(this, kArm64Float32Sub, node);
}
+void InstructionSelector::VisitFloat32SubPreserveNan(Node* node) {
+ VisitRRR(this, kArm64Float32Sub, node);
+}
void InstructionSelector::VisitFloat64Sub(Node* node) {
Arm64OperandGenerator g(this);
@@ -1515,6 +1604,9 @@
VisitRRR(this, kArm64Float64Sub, node);
}
+void InstructionSelector::VisitFloat64SubPreserveNan(Node* node) {
+ VisitRRR(this, kArm64Float64Sub, node);
+}
void InstructionSelector::VisitFloat32Mul(Node* node) {
VisitRRR(this, kArm64Float32Mul, node);
@@ -2246,6 +2338,61 @@
g.UseRegister(left), g.UseRegister(right));
}
+void InstructionSelector::VisitAtomicLoad(Node* node) {
+ LoadRepresentation load_rep = LoadRepresentationOf(node->op());
+ Arm64OperandGenerator g(this);
+ Node* base = node->InputAt(0);
+ Node* index = node->InputAt(1);
+ ArchOpcode opcode = kArchNop;
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kWord8:
+ opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8;
+ break;
+ case MachineRepresentation::kWord16:
+ opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16;
+ break;
+ case MachineRepresentation::kWord32:
+ opcode = kAtomicLoadWord32;
+ break;
+ default:
+ UNREACHABLE();
+ return;
+ }
+ Emit(opcode | AddressingModeField::encode(kMode_MRR),
+ g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
+}
+
+void InstructionSelector::VisitAtomicStore(Node* node) {
+ MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
+ Arm64OperandGenerator g(this);
+ Node* base = node->InputAt(0);
+ Node* index = node->InputAt(1);
+ Node* value = node->InputAt(2);
+ ArchOpcode opcode = kArchNop;
+ switch (rep) {
+ case MachineRepresentation::kWord8:
+ opcode = kAtomicStoreWord8;
+ break;
+ case MachineRepresentation::kWord16:
+ opcode = kAtomicStoreWord16;
+ break;
+ case MachineRepresentation::kWord32:
+ opcode = kAtomicStoreWord32;
+ break;
+ default:
+ UNREACHABLE();
+ return;
+ }
+
+ AddressingMode addressing_mode = kMode_MRR;
+ InstructionOperand inputs[3];
+ size_t input_count = 0;
+ inputs[input_count++] = g.UseUniqueRegister(base);
+ inputs[input_count++] = g.UseUniqueRegister(index);
+ inputs[input_count++] = g.UseUniqueRegister(value);
+ InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
+ Emit(code, 0, nullptr, input_count, inputs);
+}
// static
MachineOperatorBuilder::Flags