| 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
|
|
|