Skip to content

Commit 9634f6b

Browse files
modulovaluedart-scoped@luci-project-accounts.iam.gserviceaccount.com
authored andcommitted
[typed_data] Add Int32x4.notEqual
TEST=lib/typed_data/int32x4_compare_test Bug: #64073 Issue: #64170 Change-Id: I1e97afbeca2e637fc0ccdbb3367986539ec4ce5c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/541221 Reviewed-by: Stephen Adams <sra@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Auto-Submit: Modestas Valauskas <valauskasmodestas@gmail.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Slava Egorov <vegorov@google.com>
1 parent 70a7fd1 commit 9634f6b

7 files changed

Lines changed: 132 additions & 26 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
- Added `Int32x4.equal`, a lane-wise equality comparison that returns `-1` in
2121
each lane where the operands are equal and `0` elsewhere, and the
2222
`Int32x4.anyTrue` getter, which is `true` when any lane is non-zero.
23+
- Added `Int32x4.notEqual`, a lane-wise inequality comparison that returns `-1`
24+
in each lane where the operands differ and `0` elsewhere.
2325

2426
#### `dart:js_interop`
2527

‎sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,15 @@ final class NativeInt32x4 implements Int32x4 {
17381738
);
17391739
}
17401740

1741+
Int32x4 notEqual(Int32x4 other) {
1742+
return NativeInt32x4._truncated(
1743+
x != other.x ? -1 : 0,
1744+
y != other.y ? -1 : 0,
1745+
z != other.z ? -1 : 0,
1746+
w != other.w ? -1 : 0,
1747+
);
1748+
}
1749+
17411750
bool get anyTrue => (x | y | z | w) != 0;
17421751

17431752
/// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.

‎sdk/lib/_internal/js_runtime/lib/native_typed_data.dart‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,6 +2026,15 @@ final class NativeInt32x4 implements Int32x4 {
20262026
);
20272027
}
20282028

2029+
Int32x4 notEqual(Int32x4 other) {
2030+
return NativeInt32x4._truncated(
2031+
x != other.x ? -1 : 0,
2032+
y != other.y ? -1 : 0,
2033+
z != other.z ? -1 : 0,
2034+
w != other.w ? -1 : 0,
2035+
);
2036+
}
2037+
20292038
bool get anyTrue => (x | y | z | w) != 0;
20302039

20312040
/// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.

‎sdk/lib/_internal/vm/lib/typed_data_patch.dart‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4030,6 +4030,13 @@ final class _Int32x4 implements Int32x4 {
40304030
@pragma("vm:external-name", "Int32x4_equal")
40314031
external Int32x4 equal(Int32x4 other);
40324032

4033+
Int32x4 notEqual(Int32x4 other) => Int32x4(
4034+
x != other.x ? -1 : 0,
4035+
y != other.y ? -1 : 0,
4036+
z != other.z ? -1 : 0,
4037+
w != other.w ? -1 : 0,
4038+
);
4039+
40334040
@pragma("vm:recognized", "other")
40344041
@pragma("vm:external-name", "Int32x4_getX")
40354042
external int get x;

‎sdk/lib/_internal/wasm/common/simd.dart‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,15 @@ final class I32x4 extends WasmTypedDataBase implements Int32x4 {
653653
Int32x4 equal(Int32x4 other) =>
654654
I32x4.fromV128(WasmI32x4(_bits).eq(WasmI32x4((other as I32x4)._bits)));
655655

656+
Int32x4 notEqual(Int32x4 other) {
657+
return I32x4._truncated(
658+
x != other.x ? -1 : 0,
659+
y != other.y ? -1 : 0,
660+
z != other.z ? -1 : 0,
661+
w != other.w ? -1 : 0,
662+
);
663+
}
664+
656665
bool get anyTrue => _bits.anyTrue;
657666

658667
Int32x4 shuffle(int mask) {

‎sdk/lib/typed_data/typed_data.dart‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4376,6 +4376,15 @@ abstract final class Int32x4 {
43764376
/// Returns four values that are always either 0 or -1.
43774377
Int32x4 equal(Int32x4 other);
43784378

4379+
/// Lane-wise integer inequality comparison.
4380+
///
4381+
/// The result for a lane is a 32-bit signed integer which is -1
4382+
/// (all bits set) if the value from this object is not equal to
4383+
/// the value from [other], and the result is 0 (all bits cleared) if it is.
4384+
///
4385+
/// Returns four values that are always either 0 or -1.
4386+
Int32x4 notEqual(Int32x4 other);
4387+
43794388
/// Extract 32-bit mask from x lane.
43804389
int get x;
43814390

‎tests/lib/typed_data/int32x4_compare_test.dart‎

Lines changed: 87 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,92 @@ import 'dart:typed_data';
1111

1212
import 'package:expect/expect.dart';
1313

14-
void testEqual() {
15-
final a = Int32x4(1, 2, 3, 4);
14+
// Int32 min and max.
15+
const _min = -2147483648;
16+
const _max = 2147483647;
17+
18+
/// Tests Int32x4 equality comparisons.
19+
///
20+
/// If [testingEqual] is true, tests [Int32x4.equal].
21+
/// If [testingEqual] is false, tests [Int32x4.notEqual].
22+
void testEquality(bool testingEqual) {
23+
Int32x4 compare(Int32x4 a, Int32x4 b) =>
24+
testingEqual ? a.equal(b) : a.notEqual(b);
25+
26+
// Checks that:
27+
// - compare produces the expected mask
28+
// - compare is symmetric
29+
// - each operand is reflexive (equals itself in every lane)
30+
// - equal and notEqual are inverses, i.e. never equal to each other
31+
void check(Int32x4 a, Int32x4 b) {
32+
void expectSameLanes(Int32x4 expected, Int32x4 actual) {
33+
Expect.equals(expected.x, actual.x);
34+
Expect.equals(expected.y, actual.y);
35+
Expect.equals(expected.z, actual.z);
36+
Expect.equals(expected.w, actual.w);
37+
}
38+
39+
// -1 where the operator is true for the lane, else 0.
40+
int compareLane(int a, int b) => (a == b) == testingEqual ? -1 : 0;
41+
final r = compare(a, b);
42+
Expect.equals(compareLane(a.x, b.x), r.x);
43+
Expect.equals(compareLane(a.y, b.y), r.y);
44+
Expect.equals(compareLane(a.z, b.z), r.z);
45+
Expect.equals(compareLane(a.w, b.w), r.w);
46+
var sign = 0;
47+
if (r.x == -1) sign |= 1;
48+
if (r.y == -1) sign |= 2;
49+
if (r.z == -1) sign |= 4;
50+
if (r.w == -1) sign |= 8;
51+
Expect.equals(sign, r.signMask);
52+
53+
// Symmetry: swapping the operands gives the same mask.
54+
expectSameLanes(r, compare(b, a));
55+
56+
// Reflexivity: each operand compares equal to itself in every lane.
57+
void reflexive(Int32x4 v) {
58+
final selfMask = compare(v, v);
59+
final expected = testingEqual ? -1 : 0;
60+
Expect.equals(expected, selfMask.x);
61+
Expect.equals(expected, selfMask.y);
62+
Expect.equals(expected, selfMask.z);
63+
Expect.equals(expected, selfMask.w);
64+
}
65+
66+
reflexive(a);
67+
reflexive(b);
68+
69+
// equal and notEqual are inverses: ~ turns one into the other, and they
70+
// disagree in every lane (eq.notEqual(neq) all true, eq.equal(neq) all
71+
// false).
72+
final eq = a.equal(b);
73+
final neq = a.notEqual(b);
74+
expectSameLanes(neq, ~eq);
75+
expectSameLanes(eq, ~neq);
76+
final eqNeq = eq.notEqual(neq);
77+
Expect.equals(-1, eqNeq.x);
78+
Expect.equals(-1, eqNeq.y);
79+
Expect.equals(-1, eqNeq.z);
80+
Expect.equals(-1, eqNeq.w);
81+
final eqEq = eq.equal(neq);
82+
Expect.equals(0, eqEq.x);
83+
Expect.equals(0, eqEq.y);
84+
Expect.equals(0, eqEq.z);
85+
Expect.equals(0, eqEq.w);
86+
}
1687

17-
// All lanes equal -> every lane is -1.
18-
final all = a.equal(Int32x4(1, 2, 3, 4));
19-
Expect.equals(-1, all.x);
20-
Expect.equals(-1, all.y);
21-
Expect.equals(-1, all.z);
22-
Expect.equals(-1, all.w);
23-
Expect.equals(0xf, all.signMask);
24-
25-
// No lanes equal -> every lane is 0.
26-
final none = a.equal(Int32x4(5, 6, 7, 8));
27-
Expect.equals(0, none.x);
28-
Expect.equals(0, none.y);
29-
Expect.equals(0, none.z);
30-
Expect.equals(0, none.w);
31-
Expect.equals(0x0, none.signMask);
32-
33-
// Per-lane result: only y and w match.
34-
final some = a.equal(Int32x4(0, 2, 0, 4));
35-
Expect.equals(0, some.x);
36-
Expect.equals(-1, some.y);
37-
Expect.equals(0, some.z);
38-
Expect.equals(-1, some.w);
39-
Expect.equals(0xa, some.signMask); // bits 1 and 3.
88+
// All lanes equal.
89+
check(Int32x4(1, 2, 3, 4), Int32x4(1, 2, 3, 4));
90+
check(Int32x4(-3, -2, -1, 0), Int32x4(-3, -2, -1, 0));
91+
check(Int32x4(_min, _max, 0, -1), Int32x4(_min, _max, 0, -1));
92+
// No lanes equal.
93+
check(Int32x4(1, 2, 3, 4), Int32x4(5, 6, 7, 8));
94+
check(Int32x4(-3, -2, -1, 0), Int32x4(-7, -6, -5, -4));
95+
check(Int32x4(_min, _max, 0, -1), Int32x4(_max, _min, -1, 0));
96+
// Only y and w match.
97+
check(Int32x4(1, 2, 3, 4), Int32x4(0, 2, 0, 4));
98+
check(Int32x4(-3, -2, -1, 0), Int32x4(0, -2, 0, 0));
99+
check(Int32x4(_min, 2, _max, 4), Int32x4(0, 2, 0, 4));
40100
}
41101

42102
void testAnyTrue() {
@@ -75,7 +135,8 @@ void testAnyTrue() {
75135

76136
void main() {
77137
for (int i = 0; i < 20; i++) {
78-
testEqual();
138+
testEquality(true); // equal
139+
testEquality(false); // notEqual
79140
testAnyTrue();
80141
}
81142
}

0 commit comments

Comments
 (0)