Index: src/compiler/arm/instruction-selector-arm.cc |
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc |
index 8c7353548a69f709a5a256e4c6afb800254e788b..259c336281b4945cba21ee90e7cf633f28ae3776 100644 |
--- a/src/compiler/arm/instruction-selector-arm.cc |
+++ b/src/compiler/arm/instruction-selector-arm.cc |
@@ -338,6 +338,46 @@ void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode, |
} |
} |
+void EmitLoad(InstructionSelector* selector, InstructionCode opcode, |
+ InstructionOperand* output, Node* base, Node* index) { |
+ ArmOperandGenerator g(selector); |
+ InstructionOperand inputs[3]; |
+ size_t input_count = 2; |
+ |
+ inputs[0] = g.UseRegister(base); |
+ if (g.CanBeImmediate(index, opcode)) { |
+ inputs[1] = g.UseImmediate(index); |
+ opcode |= AddressingModeField::encode(kMode_Offset_RI); |
+ } else if ((opcode == kArmLdr) && |
+ TryMatchLSLImmediate(selector, &opcode, index, &inputs[1], |
+ &inputs[2])) { |
+ input_count = 3; |
+ } else { |
+ inputs[1] = g.UseRegister(index); |
+ opcode |= AddressingModeField::encode(kMode_Offset_RR); |
+ } |
+ selector->Emit(opcode, 1, output, input_count, inputs); |
+} |
+ |
+void EmitStore(InstructionSelector* selector, InstructionCode opcode, |
+ size_t input_count, InstructionOperand* inputs, |
+ Node* index) { |
+ ArmOperandGenerator g(selector); |
+ |
+ if (g.CanBeImmediate(index, opcode)) { |
+ inputs[input_count++] = g.UseImmediate(index); |
+ opcode |= AddressingModeField::encode(kMode_Offset_RI); |
+ } else if ((opcode == kArmStr) && |
+ TryMatchLSLImmediate(selector, &opcode, index, &inputs[2], |
+ &inputs[3])) { |
+ input_count = 4; |
+ } else { |
+ inputs[input_count++] = g.UseRegister(index); |
+ opcode |= AddressingModeField::encode(kMode_Offset_RR); |
+ } |
+ selector->Emit(opcode, 0, nullptr, input_count, inputs); |
+} |
+ |
} // namespace |
@@ -346,9 +386,6 @@ void InstructionSelector::VisitLoad(Node* node) { |
ArmOperandGenerator g(this); |
Node* base = node->InputAt(0); |
Node* index = node->InputAt(1); |
- InstructionOperand inputs[3]; |
- size_t input_count = 0; |
- InstructionOperand outputs[1]; |
InstructionCode opcode = kArchNop; |
switch (load_rep.representation()) { |
@@ -376,24 +413,8 @@ void InstructionSelector::VisitLoad(Node* node) { |
return; |
} |
- outputs[0] = g.DefineAsRegister(node); |
- inputs[0] = g.UseRegister(base); |
- |
- if (g.CanBeImmediate(index, opcode)) { |
- input_count = 2; |
- inputs[1] = g.UseImmediate(index); |
- opcode |= AddressingModeField::encode(kMode_Offset_RI); |
- } else if ((opcode == kArmLdr) && |
- TryMatchLSLImmediate(this, &opcode, index, &inputs[1], |
- &inputs[2])) { |
- input_count = 3; |
- } else { |
- input_count = 2; |
- inputs[1] = g.UseRegister(index); |
- opcode |= AddressingModeField::encode(kMode_Offset_RR); |
- } |
- |
- Emit(opcode, arraysize(outputs), outputs, input_count, inputs); |
+ InstructionOperand output = g.DefineAsRegister(node); |
+ EmitLoad(this, opcode, &output, base, index); |
} |
@@ -445,9 +466,6 @@ void InstructionSelector::VisitStore(Node* node) { |
code |= MiscField::encode(static_cast<int>(record_write_mode)); |
Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); |
} else { |
- InstructionOperand inputs[4]; |
- size_t input_count = 0; |
- |
InstructionCode opcode = kArchNop; |
switch (rep) { |
case MachineRepresentation::kFloat32: |
@@ -474,31 +492,129 @@ void InstructionSelector::VisitStore(Node* node) { |
return; |
} |
- inputs[0] = g.UseRegister(value); |
- inputs[1] = g.UseRegister(base); |
+ InstructionOperand inputs[4]; |
+ size_t input_count = 0; |
+ inputs[input_count++] = g.UseRegister(value); |
+ inputs[input_count++] = g.UseRegister(base); |
+ EmitStore(this, opcode, input_count, inputs, index); |
+ } |
+} |
+ |
+void InstructionSelector::VisitUnalignedLoad(Node* node) { |
+ UnalignedLoadRepresentation load_rep = |
+ UnalignedLoadRepresentationOf(node->op()); |
+ ArmOperandGenerator g(this); |
+ Node* base = node->InputAt(0); |
+ Node* index = node->InputAt(1); |
+ |
+ InstructionCode opcode = kArmLdr; |
+ // Only floating point loads need to be specially handled; integer loads |
+ // support unaligned access. We support unaligned FP loads by loading to |
+ // integer registers first, then moving to the destination FP register. |
+ switch (load_rep.representation()) { |
+ case MachineRepresentation::kFloat32: { |
+ InstructionOperand temp = g.TempRegister(); |
+ EmitLoad(this, opcode, &temp, base, index); |
+ Emit(kArmVmovF32U32, g.DefineAsRegister(node), temp); |
+ return; |
+ } |
+ case MachineRepresentation::kFloat64: { |
+ // TODO(arm): use vld1.8 for this when NEON is available. |
+ // Compute the address of the least-significant half of the FP value. |
+ // We assume that the base node is unlikely to be an encodable immediate |
+ // or the result of a shift operation, so only consider the addressing |
+ // mode that should be used for the index node. |
+ InstructionCode add_opcode = kArmAdd; |
+ InstructionOperand inputs[3]; |
+ inputs[0] = g.UseRegister(base); |
+ |
+ size_t input_count; |
+ if (TryMatchImmediateOrShift(this, &add_opcode, index, &input_count, |
+ &inputs[1])) { |
+ // input_count has been set by TryMatchImmediateOrShift(), so increment |
+ // it to account for the base register in inputs[0]. |
+ input_count++; |
+ } else { |
+ add_opcode |= AddressingModeField::encode(kMode_Operand2_R); |
+ inputs[1] = g.UseRegister(index); |
+ input_count = 2; // Base register and index. |
+ } |
+ |
+ InstructionOperand addr = g.TempRegister(); |
+ Emit(add_opcode, 1, &addr, input_count, inputs); |
- if (g.CanBeImmediate(index, opcode)) { |
- input_count = 3; |
- inputs[2] = g.UseImmediate(index); |
+ // Load both halves and move to an FP register. |
+ InstructionOperand fp_lo = g.TempRegister(); |
+ InstructionOperand fp_hi = g.TempRegister(); |
opcode |= AddressingModeField::encode(kMode_Offset_RI); |
- } else if ((opcode == kArmStr) && |
- TryMatchLSLImmediate(this, &opcode, index, &inputs[2], |
- &inputs[3])) { |
- input_count = 4; |
- } else { |
- input_count = 3; |
- inputs[2] = g.UseRegister(index); |
- opcode |= AddressingModeField::encode(kMode_Offset_RR); |
+ Emit(opcode, fp_lo, addr, g.TempImmediate(0)); |
+ Emit(opcode, fp_hi, addr, g.TempImmediate(4)); |
+ Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), fp_lo, fp_hi); |
+ return; |
} |
- Emit(opcode, 0, nullptr, input_count, inputs); |
+ default: |
+ // All other cases should support unaligned accesses. |
+ UNREACHABLE(); |
+ return; |
} |
} |
-// Architecture supports unaligned access, therefore VisitLoad is used instead |
-void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); } |
+void InstructionSelector::VisitUnalignedStore(Node* node) { |
+ ArmOperandGenerator g(this); |
+ Node* base = node->InputAt(0); |
+ Node* index = node->InputAt(1); |
+ Node* value = node->InputAt(2); |
+ |
+ InstructionOperand inputs[4]; |
+ size_t input_count = 0; |
-// Architecture supports unaligned access, therefore VisitStore is used instead |
-void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); } |
+ UnalignedStoreRepresentation store_rep = |
+ UnalignedStoreRepresentationOf(node->op()); |
+ |
+ // Only floating point stores need to be specially handled; integer stores |
+ // support unaligned access. We support unaligned FP stores by moving the |
+ // value to integer registers first, then storing to the destination address. |
+ switch (store_rep) { |
+ case MachineRepresentation::kFloat32: { |
+ inputs[input_count++] = g.TempRegister(); |
+ Emit(kArmVmovU32F32, inputs[0], g.UseRegister(value)); |
+ inputs[input_count++] = g.UseRegister(base); |
+ EmitStore(this, kArmStr, input_count, inputs, index); |
+ return; |
+ } |
+ case MachineRepresentation::kFloat64: { |
+ // TODO(arm): use vst1.8 for this when NEON is available. |
+ // Store a 64-bit floating point value using two 32-bit integer stores. |
+ // Computing the store address here would require three live temporary |
+ // registers (fp<63:32>, fp<31:0>, address), so compute base + 4 after |
+ // storing the least-significant half of the value. |
+ |
+ // First, move the 64-bit FP value into two temporary integer registers. |
+ InstructionOperand fp[] = {g.TempRegister(), g.TempRegister()}; |
+ inputs[input_count++] = g.UseRegister(value); |
+ Emit(kArmVmovU32U32F64, arraysize(fp), fp, input_count, |
+ inputs); |
+ |
+ // Store the least-significant half. |
+ inputs[0] = fp[0]; // Low 32-bits of FP value. |
+ inputs[input_count++] = g.UseRegister(base); // First store base address. |
+ EmitStore(this, kArmStr, input_count, inputs, index); |
+ |
+ // Store the most-significant half. |
+ InstructionOperand base4 = g.TempRegister(); |
+ Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_I), base4, |
+ g.UseRegister(base), g.TempImmediate(4)); // Compute base + 4. |
+ inputs[0] = fp[1]; // High 32-bits of FP value. |
+ inputs[1] = base4; // Second store base + 4 address. |
+ EmitStore(this, kArmStr, input_count, inputs, index); |
+ return; |
+ } |
+ default: |
+ // All other cases should support unaligned accesses. |
+ UNREACHABLE(); |
+ return; |
+ } |
+} |
void InstructionSelector::VisitCheckedLoad(Node* node) { |
CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); |
@@ -2176,8 +2292,11 @@ InstructionSelector::SupportedMachineOperatorFlags() { |
// static |
MachineOperatorBuilder::AlignmentRequirements |
InstructionSelector::AlignmentRequirements() { |
+ Vector<MachineType> req_aligned = Vector<MachineType>::New(2); |
+ req_aligned[0] = MachineType::Float32(); |
+ req_aligned[1] = MachineType::Float64(); |
return MachineOperatorBuilder::AlignmentRequirements:: |
- FullUnalignedAccessSupport(); |
+ SomeUnalignedAccessUnsupported(req_aligned, req_aligned); |
} |
} // namespace compiler |