[vm, compiler] Fix Float32x4.greaterThan[OrEqual] on IA32 and X64 to give the expected result for NaNs.

TEST=lib/typed_data/float32x4_compare_test
Bug: https://github.com/dart-lang/sdk/issues/53662
Change-Id: Ia5e1e5088fde84c60d30e0a1d50d1d2d3b50f2f0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328768
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2023-10-03 15:32:30 +00:00 committed by Commit Queue
parent 2a30837626
commit b370e3f509
4 changed files with 143 additions and 4 deletions

View file

@ -7920,6 +7920,24 @@ SimdOpInstr* SimdOpInstr::CreateFromCall(Zone* zone,
case MethodRecognizer::kFloat64x2Sub:
op = new (zone) SimdOpInstr(KindForOperator(kind), call->deopt_id());
break;
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
case MethodRecognizer::kFloat32x4GreaterThan:
// cmppsgt does not exist, cmppsnlt gives wrong NaN result, need to flip
// at the IL level to get the right SameAsFirstInput.
op = new (zone)
SimdOpInstr(SimdOpInstr::kFloat32x4LessThan, call->deopt_id());
op->SetInputAt(0, call->ArgumentValueAt(1)->CopyWithType(zone));
op->SetInputAt(1, new (zone) Value(receiver));
return op;
case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
// cmppsge does not exist, cmppsnle gives wrong NaN result, need to flip
// at the IL level to get the right SameAsFirstInput.
op = new (zone)
SimdOpInstr(SimdOpInstr::kFloat32x4LessThanOrEqual, call->deopt_id());
op->SetInputAt(0, call->ArgumentValueAt(1)->CopyWithType(zone));
op->SetInputAt(1, new (zone) Value(receiver));
return op;
#endif
default:
op = new (zone) SimdOpInstr(KindForMethod(kind), call->deopt_id());
break;
@ -7935,6 +7953,7 @@ SimdOpInstr* SimdOpInstr::CreateFromCall(Zone* zone,
op->set_mask(mask);
}
ASSERT(call->ArgumentCount() == (op->InputCount() + (op->HasMask() ? 1 : 0)));
return op;
}

View file

@ -4052,8 +4052,6 @@ Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
V(Int32x4BitXor, xorps) \
V(Float32x4Equal, cmppseq) \
V(Float32x4NotEqual, cmppsneq) \
V(Float32x4GreaterThan, cmppsnle) \
V(Float32x4GreaterThanOrEqual, cmppsnlt) \
V(Float32x4LessThan, cmppslt) \
V(Float32x4LessThanOrEqual, cmppsle)
@ -4423,6 +4421,8 @@ LocationSummary* SimdOpInstr::MakeLocationSummary(Zone* zone, bool opt) const {
#undef CASE
#undef EMIT
#undef SIMPLE
case SimdOpInstr::kFloat32x4GreaterThan:
case SimdOpInstr::kFloat32x4GreaterThanOrEqual:
case kIllegalSimdOp:
UNREACHABLE();
break;
@ -4442,6 +4442,8 @@ void SimdOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
#undef CASE
#undef EMIT
#undef SIMPLE
case SimdOpInstr::kFloat32x4GreaterThan:
case SimdOpInstr::kFloat32x4GreaterThanOrEqual:
case kIllegalSimdOp:
UNREACHABLE();
break;

View file

@ -4228,8 +4228,6 @@ Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
V(Int32x4BitXor, xorps) \
V(Float32x4Equal, cmppseq) \
V(Float32x4NotEqual, cmppsneq) \
V(Float32x4GreaterThan, cmppsnle) \
V(Float32x4GreaterThanOrEqual, cmppsnlt) \
V(Float32x4LessThan, cmppslt) \
V(Float32x4LessThanOrEqual, cmppsle)
@ -4600,6 +4598,8 @@ LocationSummary* SimdOpInstr::MakeLocationSummary(Zone* zone, bool opt) const {
#undef CASE
#undef EMIT
#undef SIMPLE
case SimdOpInstr::kFloat32x4GreaterThan:
case SimdOpInstr::kFloat32x4GreaterThanOrEqual:
case kIllegalSimdOp:
break;
}
@ -4618,6 +4618,8 @@ void SimdOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
#undef CASE
#undef EMIT
#undef SIMPLE
case SimdOpInstr::kFloat32x4GreaterThan:
case SimdOpInstr::kFloat32x4GreaterThanOrEqual:
case kIllegalSimdOp:
UNREACHABLE();
break;

View file

@ -0,0 +1,116 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--max_deoptimization_counter_threshold=1000 --optimization-counter-threshold=10 --no-background-compilation
// VMOptions=--no-intrinsify
import "dart:typed_data";
import "package:expect/expect.dart";
testEqual() {
var a = new Float32x4(
double.nan, double.infinity, double.negativeInfinity, double.nan);
var b = new Float32x4(0.0, 0.0, 0.0, double.nan);
var c = a.equal(b);
var d = b.equal(a);
Expect.equals(0, c.x);
Expect.equals(0, c.y);
Expect.equals(0, c.z);
Expect.equals(0, c.w);
Expect.equals(0, d.x);
Expect.equals(0, d.y);
Expect.equals(0, d.z);
Expect.equals(0, d.w);
}
testNotEqual() {
var a = new Float32x4(
double.nan, double.infinity, double.negativeInfinity, double.nan);
var b = new Float32x4(0.0, 0.0, 0.0, double.nan);
var c = a.notEqual(b);
var d = b.notEqual(a);
Expect.equals(-1, c.x);
Expect.equals(-1, c.y);
Expect.equals(-1, c.z);
Expect.equals(-1, c.w);
Expect.equals(-1, d.x);
Expect.equals(-1, d.y);
Expect.equals(-1, d.z);
Expect.equals(-1, d.w);
}
testLessThan() {
var a = new Float32x4(
double.nan, double.infinity, double.negativeInfinity, double.nan);
var b = new Float32x4(0.0, 0.0, 0.0, double.nan);
var c = a.lessThan(b);
var d = b.lessThan(a);
Expect.equals(0, c.x);
Expect.equals(0, c.y);
Expect.equals(-1, c.z);
Expect.equals(0, c.w);
Expect.equals(0, d.x);
Expect.equals(-1, d.y);
Expect.equals(0, d.z);
Expect.equals(0, d.w);
}
testLessThanOrEqual() {
var a = new Float32x4(
double.nan, double.infinity, double.negativeInfinity, double.nan);
var b = new Float32x4(0.0, 0.0, 0.0, double.nan);
var c = a.lessThanOrEqual(b);
var d = b.lessThanOrEqual(a);
Expect.equals(0, c.x);
Expect.equals(0, c.y);
Expect.equals(-1, c.z);
Expect.equals(0, c.w);
Expect.equals(0, d.x);
Expect.equals(-1, d.y);
Expect.equals(0, d.z);
Expect.equals(0, d.w);
}
testGreaterThan() {
var a = new Float32x4(
double.nan, double.infinity, double.negativeInfinity, double.nan);
var b = new Float32x4(0.0, 0.0, 0.0, double.nan);
var c = a.greaterThan(b);
var d = b.greaterThan(a);
Expect.equals(0, c.x);
Expect.equals(-1, c.y);
Expect.equals(0, c.z);
Expect.equals(0, c.w);
Expect.equals(0, d.x);
Expect.equals(0, d.y);
Expect.equals(-1, d.z);
Expect.equals(0, d.w);
}
testGreaterThanOrEqual() {
var a = new Float32x4(
double.nan, double.infinity, double.negativeInfinity, double.nan);
var b = new Float32x4(0.0, 0.0, 0.0, double.nan);
var c = a.greaterThanOrEqual(b);
var d = b.greaterThan(a);
Expect.equals(0, c.x);
Expect.equals(-1, c.y);
Expect.equals(0, c.z);
Expect.equals(0, c.w);
Expect.equals(0, d.x);
Expect.equals(0, d.y);
Expect.equals(-1, d.z);
Expect.equals(0, d.w);
}
main() {
for (int i = 0; i < 20; i++) {
testEqual();
testNotEqual();
testLessThan();
testLessThanOrEqual();
testGreaterThan();
testGreaterThanOrEqual();
}
}