Skip to content

Commit 18286e0

Browse files
authored
[WebAssembly] Constant fold SIMD intrinsics: any/alltrue (#148074)
Constant fold SIMD wasm intrinsics: any/alltrue Added test in `llvm/test/Transforms/InstSimplify`
1 parent 69f3844 commit 18286e0

File tree

2 files changed

+145
-1
lines changed

2 files changed

+145
-1
lines changed

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
16551655
case Intrinsic::arm_mve_vctp32:
16561656
case Intrinsic::arm_mve_vctp64:
16571657
case Intrinsic::aarch64_sve_convert_from_svbool:
1658+
case Intrinsic::wasm_alltrue:
1659+
case Intrinsic::wasm_anytrue:
16581660
// WebAssembly float semantics are always known
16591661
case Intrinsic::wasm_trunc_signed:
16601662
case Intrinsic::wasm_trunc_unsigned:
@@ -2832,7 +2834,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
28322834

28332835
// Support ConstantVector in case we have an Undef in the top.
28342836
if (isa<ConstantVector>(Operands[0]) ||
2835-
isa<ConstantDataVector>(Operands[0])) {
2837+
isa<ConstantDataVector>(Operands[0]) ||
2838+
isa<ConstantAggregateZero>(Operands[0])) {
28362839
auto *Op = cast<Constant>(Operands[0]);
28372840
switch (IntrinsicID) {
28382841
default: break;
@@ -2856,6 +2859,20 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
28562859
/*roundTowardZero=*/true, Ty,
28572860
/*IsSigned*/true);
28582861
break;
2862+
2863+
case Intrinsic::wasm_anytrue:
2864+
return Op->isZeroValue() ? ConstantInt::get(Ty, 0)
2865+
: ConstantInt::get(Ty, 1);
2866+
2867+
case Intrinsic::wasm_alltrue:
2868+
// Check each element individually
2869+
unsigned E = cast<FixedVectorType>(Op->getType())->getNumElements();
2870+
for (unsigned I = 0; I != E; ++I)
2871+
if (Constant *Elt = Op->getAggregateElement(I))
2872+
if (Elt->isZeroValue())
2873+
return ConstantInt::get(Ty, 0);
2874+
2875+
return ConstantInt::get(Ty, 1);
28592876
}
28602877
}
28612878

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
3+
; RUN: opt -passes=instsimplify -S < %s | FileCheck %s
4+
5+
; Test that intrinsics wasm call are constant folded
6+
7+
; all_non_zero: a splat that is all non_zero
8+
; not_all_non_zero: a splat that is all one, except for 0 in the first location
9+
10+
; all_zero: a splat that is all zero
11+
; not_all_zero: a splat that is all zero, except for a non-zero in the first location
12+
13+
target triple = "wasm32-unknown-unknown"
14+
15+
define void @all_true_splat_not_all_non_zero(ptr %ptr) {
16+
; CHECK-LABEL: define void @all_true_splat_not_all_non_zero(
17+
; CHECK-SAME: ptr [[PTR:%.*]]) {
18+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
19+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
20+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
21+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
22+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
23+
; CHECK-NEXT: ret void
24+
;
25+
%a = call i32 @llvm.wasm.alltrue(<16 x i8> <i8 0, i8 1, i8 2, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>)
26+
store volatile i32 %a, ptr %ptr
27+
28+
%b = call i32 @llvm.wasm.alltrue(<8 x i16> <i16 0, i16 1, i16 2, i16 1, i16 1, i16 1, i16 1, i16 1>)
29+
store volatile i32 %b, ptr %ptr
30+
31+
%c = call i32 @llvm.wasm.alltrue(<4 x i32> <i32 0, i32 1, i32 1, i32 1>)
32+
store volatile i32 %c, ptr %ptr
33+
34+
%d = call i32 @llvm.wasm.alltrue(<2 x i64> <i64 0, i64 42>)
35+
store volatile i32 %d, ptr %ptr
36+
37+
%e = call i32 @llvm.wasm.alltrue(<4 x i64> <i64 0, i64 1, i64 1, i64 1>)
38+
store volatile i32 %e, ptr %ptr
39+
40+
ret void
41+
}
42+
43+
define void @all_true_splat_all_non_zero(ptr %ptr) {
44+
; CHECK-LABEL: define void @all_true_splat_all_non_zero(
45+
; CHECK-SAME: ptr [[PTR:%.*]]) {
46+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
47+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
48+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
49+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
50+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
51+
; CHECK-NEXT: ret void
52+
;
53+
%a = call i32 @llvm.wasm.alltrue(<16 x i8> <i8 1, i8 3, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>)
54+
store volatile i32 %a, ptr %ptr
55+
56+
%b = call i32 @llvm.wasm.alltrue(<8 x i16> <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>)
57+
store volatile i32 %b, ptr %ptr
58+
59+
%c = call i32 @llvm.wasm.alltrue(<4 x i32> <i32 1, i32 1, i32 1, i32 1>)
60+
store volatile i32 %c, ptr %ptr
61+
62+
%d = call i32 @llvm.wasm.alltrue(<2 x i64> <i64 2, i64 2>)
63+
store volatile i32 %d, ptr %ptr
64+
65+
%e = call i32 @llvm.wasm.alltrue(<4 x i64> <i64 1, i64 2, i64 1, i64 1>)
66+
store volatile i32 %e, ptr %ptr
67+
68+
ret void
69+
}
70+
71+
72+
define void @any_true_splat_all_zero(ptr %ptr) {
73+
; CHECK-LABEL: define void @any_true_splat_all_zero(
74+
; CHECK-SAME: ptr [[PTR:%.*]]) {
75+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
76+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
77+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
78+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
79+
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
80+
; CHECK-NEXT: ret void
81+
;
82+
%a = call i32 @llvm.wasm.anytrue(<16 x i8> <i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0>)
83+
store volatile i32 %a, ptr %ptr
84+
85+
%b = call i32 @llvm.wasm.anytrue(<8 x i16> <i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
86+
store volatile i32 %b, ptr %ptr
87+
88+
%c = call i32 @llvm.wasm.anytrue(<4 x i32> <i32 0, i32 0, i32 0, i32 0>)
89+
store volatile i32 %c, ptr %ptr
90+
91+
%d = call i32 @llvm.wasm.anytrue(<2 x i64> <i64 0, i64 0>)
92+
store volatile i32 %d, ptr %ptr
93+
94+
%e = call i32 @llvm.wasm.anytrue(<4 x i64> <i64 0, i64 0, i64 0, i64 0>)
95+
store volatile i32 %e, ptr %ptr
96+
97+
ret void
98+
}
99+
100+
101+
define void @any_true_splat_not_all_zero(ptr %ptr) {
102+
; CHECK-LABEL: define void @any_true_splat_not_all_zero(
103+
; CHECK-SAME: ptr [[PTR:%.*]]) {
104+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
105+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
106+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
107+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
108+
; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
109+
; CHECK-NEXT: ret void
110+
;
111+
%a = call i32 @llvm.wasm.anytrue(<16 x i8> <i8 1, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0>)
112+
store volatile i32 %a, ptr %ptr
113+
114+
%b = call i32 @llvm.wasm.anytrue(<8 x i16> <i16 3, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
115+
store volatile i32 %b, ptr %ptr
116+
117+
%c = call i32 @llvm.wasm.anytrue(<4 x i32> <i32 1, i32 0, i32 0, i32 0>)
118+
store volatile i32 %c, ptr %ptr
119+
120+
%d = call i32 @llvm.wasm.anytrue(<2 x i64> <i64 -1, i64 0>)
121+
store volatile i32 %d, ptr %ptr
122+
123+
%e = call i32 @llvm.wasm.anytrue(<4 x i64> <i64 2, i64 0, i64 0, i64 0>)
124+
store volatile i32 %e, ptr %ptr
125+
126+
ret void
127+
}

0 commit comments

Comments
 (0)