Commit dd3234bc authored by Ng Zhi An's avatar Ng Zhi An Committed by V8 LUCI CQ

[wasm-relaxed-simd][ia32] Prototype relaxed min and max

Relaxed f32x4 and f64x2 min and max.

These instructions only guarantee results when the inputs are non nans,
and when the inputs are not 0s of opposite signs.

Drive-by rename of instruction codes to be Minps/Maxps/Minpd/Maxpd
since they map down exactly to a single instruction.

ia32 port of c3f346b7.

Bug: v8:12284
Change-Id: If64da551524ea8c304e1fa8f9cf4acbd54abfe5c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3251708Reviewed-by: 's avatarDeepti Gandluri <gdeepti@chromium.org>
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77780}
parent 614ed93b
......@@ -1823,12 +1823,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputOperand(1));
break;
}
case kIA32F64x2Pmin: {
case kIA32Minpd: {
__ Minpd(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
}
case kIA32F64x2Pmax: {
case kIA32Maxpd: {
__ Maxpd(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
......@@ -2174,12 +2174,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputOperand(1));
break;
}
case kIA32F32x4Pmin: {
case kIA32Minps: {
__ Minps(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
}
case kIA32F32x4Pmax: {
case kIA32Maxps: {
__ Maxps(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
......
......@@ -120,8 +120,8 @@ namespace compiler {
V(IA32F64x2Ne) \
V(IA32F64x2Lt) \
V(IA32F64x2Le) \
V(IA32F64x2Pmin) \
V(IA32F64x2Pmax) \
V(IA32Minpd) \
V(IA32Maxpd) \
V(IA32F64x2Round) \
V(IA32F64x2ConvertLowI32x4S) \
V(IA32F64x2ConvertLowI32x4U) \
......@@ -167,8 +167,8 @@ namespace compiler {
V(IA32F32x4Ne) \
V(IA32F32x4Lt) \
V(IA32F32x4Le) \
V(IA32F32x4Pmin) \
V(IA32F32x4Pmax) \
V(IA32Minps) \
V(IA32Maxps) \
V(IA32F32x4Round) \
V(IA32F32x4DemoteF64x2Zero) \
V(IA32I32x4Splat) \
......
......@@ -104,8 +104,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kIA32F64x2Ne:
case kIA32F64x2Lt:
case kIA32F64x2Le:
case kIA32F64x2Pmin:
case kIA32F64x2Pmax:
case kIA32Minpd:
case kIA32Maxpd:
case kIA32F64x2Round:
case kIA32F64x2ConvertLowI32x4S:
case kIA32F64x2ConvertLowI32x4U:
......@@ -151,8 +151,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kIA32F32x4Ne:
case kIA32F32x4Lt:
case kIA32F32x4Le:
case kIA32F32x4Pmin:
case kIA32F32x4Pmax:
case kIA32Minps:
case kIA32Maxps:
case kIA32F32x4Round:
case kIA32F32x4DemoteF64x2Zero:
case kIA32I32x4Splat:
......
......@@ -3032,33 +3032,56 @@ void InstructionSelector::VisitI8x16Swizzle(Node* node) { UNREACHABLE(); }
#endif // V8_ENABLE_WEBASSEMBLY
namespace {
void VisitPminOrPmax(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
void VisitMinOrMax(InstructionSelector* selector, Node* node, ArchOpcode opcode,
bool flip_inputs) {
// Due to the way minps/minpd work, we want the dst to be same as the second
// input: b = pmin(a, b) directly maps to minps b a.
IA32OperandGenerator g(selector);
InstructionOperand dst = selector->IsSupported(AVX)
? g.DefineAsRegister(node)
: g.DefineSameAsFirst(node);
selector->Emit(opcode, dst, g.UseRegister(node->InputAt(1)),
g.UseRegister(node->InputAt(0)));
if (flip_inputs) {
// Due to the way minps/minpd work, we want the dst to be same as the second
// input: b = pmin(a, b) directly maps to minps b a.
selector->Emit(opcode, dst, g.UseRegister(node->InputAt(1)),
g.UseRegister(node->InputAt(0)));
} else {
selector->Emit(opcode, dst, g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(1)));
}
}
} // namespace
void InstructionSelector::VisitF32x4Pmin(Node* node) {
VisitPminOrPmax(this, node, kIA32F32x4Pmin);
VisitMinOrMax(this, node, kIA32Minps, true);
}
void InstructionSelector::VisitF32x4Pmax(Node* node) {
VisitPminOrPmax(this, node, kIA32F32x4Pmax);
VisitMinOrMax(this, node, kIA32Maxps, true);
}
void InstructionSelector::VisitF64x2Pmin(Node* node) {
VisitPminOrPmax(this, node, kIA32F64x2Pmin);
VisitMinOrMax(this, node, kIA32Minpd, true);
}
void InstructionSelector::VisitF64x2Pmax(Node* node) {
VisitPminOrPmax(this, node, kIA32F64x2Pmax);
VisitMinOrMax(this, node, kIA32Maxpd, true);
}
void InstructionSelector::VisitF32x4RelaxedMin(Node* node) {
VisitMinOrMax(this, node, kIA32Minps, false);
}
void InstructionSelector::VisitF32x4RelaxedMax(Node* node) {
VisitMinOrMax(this, node, kIA32Maxps, false);
}
void InstructionSelector::VisitF64x2RelaxedMin(Node* node) {
VisitMinOrMax(this, node, kIA32Minpd, false);
}
void InstructionSelector::VisitF64x2RelaxedMax(Node* node) {
VisitMinOrMax(this, node, kIA32Maxpd, false);
}
namespace {
......
......@@ -2790,10 +2790,6 @@ void InstructionSelector::VisitF32x4Qfms(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_S390X && !V8_TARGET_ARCH_PPC64
#if !V8_TARGET_ARCH_X64
void InstructionSelector::VisitF32x4RelaxedMin(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF32x4RelaxedMax(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2RelaxedMin(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2RelaxedMax(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI32x4RelaxedTruncF64x2SZero(Node* node) {
UNIMPLEMENTED();
}
......@@ -2821,6 +2817,10 @@ void InstructionSelector::VisitI32x4RelaxedLaneSelect(Node* node) {
void InstructionSelector::VisitI64x2RelaxedLaneSelect(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitF32x4RelaxedMin(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF32x4RelaxedMax(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2RelaxedMin(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2RelaxedMax(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32
void InstructionSelector::VisitFinishRegion(Node* node) { EmitIdentity(node); }
......
......@@ -313,6 +313,22 @@ WASM_RELAXED_SIMD_TEST(I64x2RelaxedLaneSelect) {
RelaxedLaneSelectTest<uint64_t, kElems>(execution_tier, v1, v2, s, expected,
kExprI64x2RelaxedLaneSelect);
}
WASM_RELAXED_SIMD_TEST(F32x4RelaxedMin) {
RunF32x4BinOpTest(execution_tier, kExprF32x4RelaxedMin, Minimum);
}
WASM_RELAXED_SIMD_TEST(F32x4RelaxedMax) {
RunF32x4BinOpTest(execution_tier, kExprF32x4RelaxedMax, Maximum);
}
WASM_RELAXED_SIMD_TEST(F64x2RelaxedMin) {
RunF64x2BinOpTest(execution_tier, kExprF64x2RelaxedMin, Minimum);
}
WASM_RELAXED_SIMD_TEST(F64x2RelaxedMax) {
RunF64x2BinOpTest(execution_tier, kExprF64x2RelaxedMax, Maximum);
}
#endif // V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32
#if V8_TARGET_ARCH_X64
......@@ -338,22 +354,6 @@ WASM_RELAXED_SIMD_TEST(I8x16RelaxedSwizzle) {
}
}
WASM_RELAXED_SIMD_TEST(F32x4RelaxedMin) {
RunF32x4BinOpTest(execution_tier, kExprF32x4RelaxedMin, Minimum);
}
WASM_RELAXED_SIMD_TEST(F32x4RelaxedMax) {
RunF32x4BinOpTest(execution_tier, kExprF32x4RelaxedMax, Maximum);
}
WASM_RELAXED_SIMD_TEST(F64x2RelaxedMin) {
RunF64x2BinOpTest(execution_tier, kExprF64x2RelaxedMin, Minimum);
}
WASM_RELAXED_SIMD_TEST(F64x2RelaxedMax) {
RunF64x2BinOpTest(execution_tier, kExprF64x2RelaxedMax, Maximum);
}
namespace {
// For relaxed trunc instructions, don't test out of range values.
// FloatType comes later so caller can rely on template argument deduction and
......
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