Commit 9db3cb75 authored by Zhi An Ng's avatar Zhi An Ng Committed by Commit Bot

[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: 's avatarBill Budge <bbudge@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72106}
parent ee3f5ba1
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "src/base/overflowing-math.h" #include "src/base/overflowing-math.h"
#include "src/codegen/arm/assembler-arm-inl.h" #include "src/codegen/arm/assembler-arm-inl.h"
#include "src/codegen/assembler-inl.h" #include "src/codegen/assembler-inl.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/macro-assembler.h" #include "src/codegen/macro-assembler.h"
#include "src/codegen/string-constants.h" #include "src/codegen/string-constants.h"
#include "src/deoptimizer/deoptimizer.h" #include "src/deoptimizer/deoptimizer.h"
...@@ -5397,6 +5398,21 @@ Register UseScratchRegisterScope::Acquire() { ...@@ -5397,6 +5398,21 @@ Register UseScratchRegisterScope::Acquire() {
return reg; 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 internal
} // namespace v8 } // namespace v8
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#define V8_CODEGEN_ARM_ASSEMBLER_ARM_H_ #define V8_CODEGEN_ARM_ASSEMBLER_ARM_H_
#include <stdio.h> #include <stdio.h>
#include <memory> #include <memory>
#include <vector> #include <vector>
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
#include "src/codegen/arm/register-arm.h" #include "src/codegen/arm/register-arm.h"
#include "src/codegen/assembler.h" #include "src/codegen/assembler.h"
#include "src/codegen/constant-pool.h" #include "src/codegen/constant-pool.h"
#include "src/codegen/machine-type.h"
#include "src/numbers/double.h" #include "src/numbers/double.h"
#include "src/utils/boxed-float.h" #include "src/utils/boxed-float.h"
...@@ -1394,6 +1396,25 @@ class V8_EXPORT_PRIVATE V8_NODISCARD UseScratchRegisterScope { ...@@ -1394,6 +1396,25 @@ class V8_EXPORT_PRIVATE V8_NODISCARD UseScratchRegisterScope {
VfpRegList old_available_vfp_; 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 internal
} // namespace v8 } // namespace v8
......
...@@ -511,41 +511,9 @@ void InstructionSelector::VisitAbortCSAAssert(Node* node) { ...@@ -511,41 +511,9 @@ void InstructionSelector::VisitAbortCSAAssert(Node* node) {
Emit(kArchAbortCSAAssert, g.NoOutput(), g.UseFixed(node->InputAt(0), r1)); 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) { void InstructionSelector::VisitStoreLane(Node* node) {
StoreLaneParameters params = StoreLaneParametersOf(node->op()); StoreLaneParameters params = StoreLaneParametersOf(node->op());
LoadStoreLaneParams f = GetLoadStoreLaneParams(params.rep, params.laneidx); LoadStoreLaneParams f(params.rep, params.laneidx);
InstructionCode opcode = InstructionCode opcode =
f.low_op ? kArmS128StoreLaneLow : kArmS128StoreLaneHigh; f.low_op ? kArmS128StoreLaneLow : kArmS128StoreLaneHigh;
opcode |= MiscField::encode(f.sz); opcode |= MiscField::encode(f.sz);
...@@ -563,8 +531,7 @@ void InstructionSelector::VisitStoreLane(Node* node) { ...@@ -563,8 +531,7 @@ void InstructionSelector::VisitStoreLane(Node* node) {
void InstructionSelector::VisitLoadLane(Node* node) { void InstructionSelector::VisitLoadLane(Node* node) {
LoadLaneParameters params = LoadLaneParametersOf(node->op()); LoadLaneParameters params = LoadLaneParametersOf(node->op());
LoadStoreLaneParams f = LoadStoreLaneParams f(params.rep.representation(), params.laneidx);
GetLoadStoreLaneParams(params.rep.representation(), params.laneidx);
InstructionCode opcode = InstructionCode opcode =
f.low_op ? kArmS128LoadLaneLow : kArmS128LoadLaneHigh; f.low_op ? kArmS128LoadLaneLow : kArmS128LoadLaneHigh;
opcode |= MiscField::encode(f.sz); opcode |= MiscField::encode(f.sz);
......
...@@ -2362,7 +2362,17 @@ void LiftoffAssembler::LoadLane(LiftoffRegister dst, LiftoffRegister src, ...@@ -2362,7 +2362,17 @@ void LiftoffAssembler::LoadLane(LiftoffRegister dst, LiftoffRegister src,
Register addr, Register offset_reg, Register addr, Register offset_reg,
uintptr_t offset_imm, LoadType type, uintptr_t offset_imm, LoadType type,
uint8_t laneidx, uint32_t* protected_load_pc) { 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, void LiftoffAssembler::emit_i8x16_swizzle(LiftoffRegister dst,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment