[wasm-simd][liftoff][arm] Prototype load lane

Prototype load lane instructions on ARM Liftoff.

We had a helper function for load lane that was living in
instruction-selector. Move it out to assembler-arm so we can reuse that
in Liftoff.

Bug: v8:10975
Change-Id: Ic6e15c23eb778fb94a882609be622d2ca1f61ddb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2614225
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Reviewed-by: Bill Budge <bbudge@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72106}
This commit is contained in:
Zhi An Ng 2021-01-14 07:01:33 +00:00 committed by Commit Bot
parent ee3f5ba10b
commit 9db3cb75ba
4 changed files with 50 additions and 36 deletions

View File

@ -43,6 +43,7 @@
#include "src/base/overflowing-math.h"
#include "src/codegen/arm/assembler-arm-inl.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/string-constants.h"
#include "src/deoptimizer/deoptimizer.h"
@ -5397,6 +5398,21 @@ Register UseScratchRegisterScope::Acquire() {
return reg;
}
LoadStoreLaneParams::LoadStoreLaneParams(MachineRepresentation rep,
uint8_t laneidx) {
if (rep == MachineRepresentation::kWord8) {
*this = LoadStoreLaneParams(laneidx, Neon8, 8);
} else if (rep == MachineRepresentation::kWord16) {
*this = LoadStoreLaneParams(laneidx, Neon16, 4);
} else if (rep == MachineRepresentation::kWord32) {
*this = LoadStoreLaneParams(laneidx, Neon32, 2);
} else if (rep == MachineRepresentation::kWord64) {
*this = LoadStoreLaneParams(laneidx, Neon64, 1);
} else {
UNREACHABLE();
}
}
} // namespace internal
} // namespace v8

View File

@ -41,6 +41,7 @@
#define V8_CODEGEN_ARM_ASSEMBLER_ARM_H_
#include <stdio.h>
#include <memory>
#include <vector>
@ -48,6 +49,7 @@
#include "src/codegen/arm/register-arm.h"
#include "src/codegen/assembler.h"
#include "src/codegen/constant-pool.h"
#include "src/codegen/machine-type.h"
#include "src/numbers/double.h"
#include "src/utils/boxed-float.h"
@ -1394,6 +1396,25 @@ class V8_EXPORT_PRIVATE V8_NODISCARD UseScratchRegisterScope {
VfpRegList old_available_vfp_;
};
// Helper struct for load lane and store lane to indicate which opcode to use
// and what memory size to be encoded in the opcode, and the new lane index.
class LoadStoreLaneParams {
public:
bool low_op;
NeonSize sz;
uint8_t laneidx;
// The register mapping on ARM (1 Q to 2 D), means that loading/storing high
// lanes of a Q register is equivalent to loading/storing the high D reg,
// modulo number of lanes in a D reg. This constructor decides, based on the
// laneidx and load/store size, whether the low or high D reg is accessed, and
// what the new lane index is.
LoadStoreLaneParams(MachineRepresentation rep, uint8_t laneidx);
private:
LoadStoreLaneParams(uint8_t laneidx, NeonSize sz, int lanes)
: low_op(laneidx < lanes), sz(sz), laneidx(laneidx % lanes) {}
};
} // namespace internal
} // namespace v8

View File

@ -511,41 +511,9 @@ void InstructionSelector::VisitAbortCSAAssert(Node* node) {
Emit(kArchAbortCSAAssert, g.NoOutput(), g.UseFixed(node->InputAt(0), r1));
}
namespace {
// Helper struct for load lane and store lane to indicate which opcode to use
// and what memory size to be encoded in the opcode, and the new lane index.
struct LoadStoreLaneParams {
bool low_op;
NeonSize sz;
uint8_t laneidx;
LoadStoreLaneParams(uint8_t laneidx, NeonSize sz, int lanes)
: low_op(laneidx < lanes), sz(sz), laneidx(laneidx % lanes) {}
};
// The register mapping on ARM (1 Q to 2 D), means that loading/storing high
// lanes of a Q register is equivalent to loading/storing the high D reg, modulo
// number of lanes in a D reg. This function decides, based on the laneidx and
// load/store size, whether the low or high D reg is accessed, and what the new
// lane index is.
LoadStoreLaneParams GetLoadStoreLaneParams(MachineRepresentation rep,
uint8_t laneidx) {
if (rep == MachineRepresentation::kWord8) {
return LoadStoreLaneParams(laneidx, Neon8, 8);
} else if (rep == MachineRepresentation::kWord16) {
return LoadStoreLaneParams(laneidx, Neon16, 4);
} else if (rep == MachineRepresentation::kWord32) {
return LoadStoreLaneParams(laneidx, Neon32, 2);
} else if (rep == MachineRepresentation::kWord64) {
return LoadStoreLaneParams(laneidx, Neon64, 1);
} else {
UNREACHABLE();
}
}
} // namespace
void InstructionSelector::VisitStoreLane(Node* node) {
StoreLaneParameters params = StoreLaneParametersOf(node->op());
LoadStoreLaneParams f = GetLoadStoreLaneParams(params.rep, params.laneidx);
LoadStoreLaneParams f(params.rep, params.laneidx);
InstructionCode opcode =
f.low_op ? kArmS128StoreLaneLow : kArmS128StoreLaneHigh;
opcode |= MiscField::encode(f.sz);
@ -563,8 +531,7 @@ void InstructionSelector::VisitStoreLane(Node* node) {
void InstructionSelector::VisitLoadLane(Node* node) {
LoadLaneParameters params = LoadLaneParametersOf(node->op());
LoadStoreLaneParams f =
GetLoadStoreLaneParams(params.rep.representation(), params.laneidx);
LoadStoreLaneParams f(params.rep.representation(), params.laneidx);
InstructionCode opcode =
f.low_op ? kArmS128LoadLaneLow : kArmS128LoadLaneHigh;
opcode |= MiscField::encode(f.sz);

View File

@ -2362,7 +2362,17 @@ void LiftoffAssembler::LoadLane(LiftoffRegister dst, LiftoffRegister src,
Register addr, Register offset_reg,
uintptr_t offset_imm, LoadType type,
uint8_t laneidx, uint32_t* protected_load_pc) {
bailout(kSimd, "loadlane");
UseScratchRegisterScope temps(this);
Register actual_src_addr = liftoff::CalculateActualAddress(
this, &temps, addr, offset_reg, offset_imm);
TurboAssembler::Move(liftoff::GetSimd128Register(dst),
liftoff::GetSimd128Register(src));
*protected_load_pc = pc_offset();
LoadStoreLaneParams load_params(type.mem_type().representation(), laneidx);
NeonListOperand dst_op =
NeonListOperand(load_params.low_op ? dst.low_fp() : dst.high_fp());
TurboAssembler::LoadLane(load_params.sz, dst_op, load_params.laneidx,
NeonMemOperand(actual_src_addr));
}
void LiftoffAssembler::emit_i8x16_swizzle(LiftoffRegister dst,