diff --git a/runtime/lib/simd128.cc b/runtime/lib/simd128.cc index 9adf5c390e8..92aee8a0de6 100644 --- a/runtime/lib/simd128.cc +++ b/runtime/lib/simd128.cc @@ -195,7 +195,8 @@ DEFINE_NATIVE_ENTRY(Float32x4_clamp, 0, 3) { float _w; // ARM semantics are different from X86/X64 at an instruction level. Ensure // that we match the semantics of the architecture in the C version. -#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) +#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \ + defined(USING_SIMULATOR) _x = self.x() < hi.x() ? self.x() : hi.x(); _y = self.y() < hi.y() ? self.y() : hi.y(); _z = self.z() < hi.z() ? self.z() : hi.z(); @@ -741,7 +742,8 @@ DEFINE_NATIVE_ENTRY(Float64x2_clamp, 0, 3) { // ARM semantics are different from X86/X64 at an instruction level. Ensure // that we match the semantics of the architecture in the C version. -#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) +#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \ + defined(USING_SIMULATOR) _x = self.x() < hi.x() ? self.x() : hi.x(); _y = self.y() < hi.y() ? self.y() : hi.y(); _x = lo.x() < _x ? _x : lo.x(); diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc index 0010aba83db..9daefc3ec2c 100644 --- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc +++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc @@ -6732,6 +6732,25 @@ ASSEMBLER_TEST_RUN(Vcged, test) { "ret\n"); } +// Verify that vmaxs(-0.0, 0.0) = 0.0 +ASSEMBLER_TEST_GENERATE(Vmaxs_zero, assembler) { + __ veor(V1, V1, V1); + __ vnegd(V2, V1); + __ vmaxs(V0, V2, V1); + __ ret(); +} + +ASSEMBLER_TEST_RUN(Vmaxs_zero, test) { + typedef double (*DoubleReturn)() DART_UNUSED; + double d = EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()); + EXPECT_EQ(true, !signbit(d) && (d == 0.0)); + EXPECT_DISASSEMBLY( + "veor v1, v1, v1\n" + "vnegd v2, v1\n" + "vmaxs v0, v2, v1\n" + "ret\n"); +} + ASSEMBLER_TEST_GENERATE(Vmaxs, assembler) { __ LoadDImmediate(V0, 10.5); __ LoadDImmediate(V1, 10.0); @@ -6791,6 +6810,25 @@ ASSEMBLER_TEST_RUN(Vmaxs, test) { "ret\n"); } +// Verify that vmaxd(-0.0, 0.0) = 0.0 +ASSEMBLER_TEST_GENERATE(Vmaxd_zero, assembler) { + __ veor(V1, V1, V1); + __ vnegd(V2, V1); + __ vmaxd(V0, V2, V1); + __ ret(); +} + +ASSEMBLER_TEST_RUN(Vmaxd_zero, test) { + typedef double (*DoubleReturn)() DART_UNUSED; + double d = EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()); + EXPECT_EQ(true, !signbit(d) && (d == 0.0)); + EXPECT_DISASSEMBLY( + "veor v1, v1, v1\n" + "vnegd v2, v1\n" + "vmaxd v0, v2, v1\n" + "ret\n"); +} + ASSEMBLER_TEST_GENERATE(Vmaxd, assembler) { __ LoadDImmediate(V0, 21.0); __ LoadDImmediate(V1, 20.5); @@ -6826,6 +6864,26 @@ ASSEMBLER_TEST_RUN(Vmaxd, test) { "ret\n"); } +// Verify that vmins(-0.0, 0.0) = -0.0 +ASSEMBLER_TEST_GENERATE(Vmins_zero, assembler) { + __ veor(V1, V1, V1); + __ vnegd(V2, V1); + __ vmins(V0, V1, V2); + __ ret(); +} + +ASSEMBLER_TEST_RUN(Vmins_zero, test) { + typedef double (*DoubleReturn)() DART_UNUSED; + double d = EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()); + fprintf(stderr, "d: %f\n", d); + EXPECT_EQ(true, signbit(d) && (d == 0.0)); + EXPECT_DISASSEMBLY( + "veor v1, v1, v1\n" + "vnegd v2, v1\n" + "vmins v0, v1, v2\n" + "ret\n"); +} + ASSEMBLER_TEST_GENERATE(Vmins, assembler) { __ LoadDImmediate(V0, 10.5); __ LoadDImmediate(V1, 11.0); @@ -6885,6 +6943,26 @@ ASSEMBLER_TEST_RUN(Vmins, test) { "ret\n"); } +// Verify that vmind(-0.0, 0.0) = -0.0 +ASSEMBLER_TEST_GENERATE(Vmind_zero, assembler) { + __ veor(V1, V1, V1); + __ vnegd(V2, V1); + __ vmind(V0, V1, V2); + __ ret(); +} + +ASSEMBLER_TEST_RUN(Vmind_zero, test) { + typedef double (*DoubleReturn)() DART_UNUSED; + double d = EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()); + fprintf(stderr, "d: %f\n", d); + EXPECT_EQ(true, signbit(d) && (d == 0.0)); + EXPECT_DISASSEMBLY( + "veor v1, v1, v1\n" + "vnegd v2, v1\n" + "vmind v0, v1, v2\n" + "ret\n"); +} + ASSEMBLER_TEST_GENERATE(Vmind, assembler) { __ LoadDImmediate(V0, 21.0); __ LoadDImmediate(V1, 21.5); diff --git a/runtime/vm/compiler/assembler/assembler_arm_test.cc b/runtime/vm/compiler/assembler/assembler_arm_test.cc index 11adcf2092f..be8de038437 100644 --- a/runtime/vm/compiler/assembler/assembler_arm_test.cc +++ b/runtime/vm/compiler/assembler/assembler_arm_test.cc @@ -3409,6 +3409,25 @@ ASSEMBLER_TEST_RUN(Vcgtqs, test) { } } +// Verify that vmins(-0.0, 0.0) = -0.0 +ASSEMBLER_TEST_GENERATE(Vminqs_zero, assembler) { + if (TargetCPUFeatures::neon_supported()) { + __ veorq(Q1, Q1, Q1); + __ vnegqs(Q2, Q1); + __ vminqs(Q0, Q1, Q2); + } + __ Ret(); +} + +ASSEMBLER_TEST_RUN(Vminqs_zero, test) { + EXPECT(test != NULL); + if (TargetCPUFeatures::neon_supported()) { + typedef int (*Tst)() DART_UNUSED; + float res = EXECUTE_TEST_CODE_FLOAT(Tst, test->entry()); + EXPECT_EQ(true, signbit(res) && (res == 0.0)); + } +} + ASSEMBLER_TEST_GENERATE(Vminqs, assembler) { if (TargetCPUFeatures::neon_supported()) { __ LoadSImmediate(S0, 1.0); @@ -3441,6 +3460,25 @@ ASSEMBLER_TEST_RUN(Vminqs, test) { } } +ASSEMBLER_TEST_GENERATE(Vmaxqs_zero, assembler) { + if (TargetCPUFeatures::neon_supported()) { + __ veorq(Q1, Q1, Q1); + __ vnegqs(Q2, Q1); + __ vmaxqs(Q0, Q2, Q1); + } + __ Ret(); +} + +// Verify that vmaxqs(-0.0, 0.0) = 0.0 +ASSEMBLER_TEST_RUN(Vmaxqs_zero, test) { + EXPECT(test != NULL); + if (TargetCPUFeatures::neon_supported()) { + typedef int (*Tst)() DART_UNUSED; + float res = EXECUTE_TEST_CODE_FLOAT(Tst, test->entry()); + EXPECT_EQ(true, !signbit(res) && (res == 0.0)); + } +} + ASSEMBLER_TEST_GENERATE(Vmaxqs, assembler) { if (TargetCPUFeatures::neon_supported()) { __ LoadSImmediate(S0, 1.0); diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc index 8dd801345fb..e6381ebad1c 100644 --- a/runtime/vm/simulator_arm.cc +++ b/runtime/vm/simulator_arm.cc @@ -2893,6 +2893,22 @@ static void simd_value_swap(simd_value_t* s1, s2->data_[i2].u = tmp; } +static float vminf(float f1, float f2) { + if (f1 == f2) { + // take care of (-0.0) < 0.0, (they are equal according to minss) + return signbit(f1) ? f1 : f2; + } + return f1 > f2 ? f2 : f1; +} + +static float vmaxf(float f1, float f2) { + if (f1 == f2) { + // take care of (-0.0) < 0.0, (they are equal according to minss) + return signbit(f1) ? f2 : f1; + } + return f1 < f2 ? f2 : f1; +} + void Simulator::DecodeSIMDDataProcessing(Instr* instr) { ASSERT(instr->ConditionField() == kSpecialCondition); @@ -3118,13 +3134,13 @@ void Simulator::DecodeSIMDDataProcessing(Instr* instr) { (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) { // Format(instr, "vminqs 'qd, 'qn, 'qm"); for (int i = 0; i < 4; i++) { - s8d.data_[i].f = fminf(s8n.data_[i].f, s8m.data_[i].f); + s8d.data_[i].f = vminf(s8n.data_[i].f, s8m.data_[i].f); } } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) && (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) { // Format(instr, "vmaxqs 'qd, 'qn, 'qm"); for (int i = 0; i < 4; i++) { - s8d.data_[i].f = fmaxf(s8n.data_[i].f, s8m.data_[i].f); + s8d.data_[i].f = vmaxf(s8n.data_[i].f, s8m.data_[i].f); } } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) && (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc index 4f34a915fed..fbb9df47cde 100644 --- a/runtime/vm/simulator_arm64.cc +++ b/runtime/vm/simulator_arm64.cc @@ -3003,6 +3003,38 @@ void Simulator::DecodeSIMDCopy(Instr* instr) { } } +static float vminf(float f1, float f2) { + if (f1 == f2) { + // take care of (-0.0) < 0.0, (they are equal according to minss) + return signbit(f1) ? f1 : f2; + } + return f1 > f2 ? f2 : f1; +} + +static float vmaxf(float f1, float f2) { + if (f1 == f2) { + // take care of (-0.0) < 0.0, (they are equal according to minss) + return signbit(f1) ? f2 : f1; + } + return f1 < f2 ? f2 : f1; +} + +static double vmind(double f1, double f2) { + if (f1 == f2) { + // take care of (-0.0) < 0.0, (they are equal according to minss) + return signbit(f1) ? f1 : f2; + } + return f1 > f2 ? f2 : f1; +} + +static double vmaxd(double f1, double f2) { + if (f1 == f2) { + // take care of (-0.0) < 0.0, (they are equal according to minss) + return signbit(f1) ? f2 : f1; + } + return f1 < f2 ? f2 : f1; +} + void Simulator::DecodeSIMDThreeSame(Instr* instr) { const int Q = instr->Bit(30); const int U = instr->Bit(29); @@ -3069,11 +3101,11 @@ void Simulator::DecodeSIMDThreeSame(Instr* instr) { } else if ((U == 0) && (opcode == 0x1e)) { if (instr->Bit(23) == 1) { // Format(instr, "vmin'vsz 'vd, 'vn, 'vm"); - const float m = fminf(vn_flt, vm_flt); + const float m = vminf(vn_flt, vm_flt); res = bit_cast(m); } else { // Format(instr, "vmax'vsz 'vd, 'vn, 'vm"); - const float m = fmaxf(vn_flt, vm_flt); + const float m = vmaxf(vn_flt, vm_flt); res = bit_cast(m); } } else if ((U == 0) && (opcode == 0x1f)) { @@ -3143,11 +3175,11 @@ void Simulator::DecodeSIMDThreeSame(Instr* instr) { } else if ((U == 0) && (opcode == 0x1e)) { if (instr->Bit(23) == 1) { // Format(instr, "vmin'vsz 'vd, 'vn, 'vm"); - const double m = fmin(vn_dbl, vm_dbl); + const double m = vmind(vn_dbl, vm_dbl); res = bit_cast(m); } else { // Format(instr, "vmax'vsz 'vd, 'vn, 'vm"); - const double m = fmax(vn_dbl, vm_dbl); + const double m = vmaxd(vn_dbl, vm_dbl); res = bit_cast(m); } } else { diff --git a/tests/lib_2/typed_data/float64x2_clamp_test.dart b/tests/lib_2/typed_data/float64x2_clamp_test.dart index 3bbe32fb698..ea028d07f39 100644 --- a/tests/lib_2/typed_data/float64x2_clamp_test.dart +++ b/tests/lib_2/typed_data/float64x2_clamp_test.dart @@ -1,7 +1,8 @@ // Copyright (c) 2013, 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=--optimization-counter-threshold=10 --no-background-compilation +// VMOptions=--intrinsify --optimization-counter-threshold=10 --no-background-compilation +// VMOptions=--no-intrinsify --optimization-counter-threshold=10 --no-background-compilation // @dart = 2.9