[llvm] [WASM] Constant fold SIMD wasm intrinsics: any/alltrue (PR #148074)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 10 18:14:54 PDT 2025
https://github.com/badumbatish updated https://github.com/llvm/llvm-project/pull/148074
>From 637e45c63c2392f250a20e3714b7d6e16b8c6fa6 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Wed, 9 Jul 2025 15:17:39 -0700
Subject: [PATCH 1/3] Precommit test for const fold wasm intrinsics for any/all
true.
---
.../WebAssembly/const_fold_simd_intrinsics.ll | 147 ++++++++++++++++++
1 file changed, 147 insertions(+)
create mode 100644 llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
diff --git a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
new file mode 100644
index 0000000000000..a57b70c905a49
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
@@ -0,0 +1,147 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+; Test that intrinsics wasm call are constant folded
+
+; all_one: a splat that is all one
+; not_all_one: a splat that is all one, except for 0 in the first location
+
+; all_zero: a splat that is all zero
+; not_all_zero: a splat that is all zero, except for 1 in the first location
+
+target triple = "wasm32-unknown-unknown"
+
+define void @all_true_splat_not_all_one(ptr %ptr) {
+; CHECK-LABEL: define void @all_true_splat_not_all_one(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.alltrue.v16i8(<16 x i8> <i8 0, 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, i8 1>)
+; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.alltrue.v8i16(<8 x i16> <i16 0, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>)
+; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i32(<4 x i32> <i32 0, i32 1, i32 1, i32 1>)
+; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.alltrue.v2i64(<2 x i64> <i64 0, i64 1>)
+; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i64(<4 x i64> <i64 0, i64 1, i64 1, i64 1>)
+; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: ret void
+;
+ %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> <i8 0, 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, i8 1>)
+ store volatile i32 %a, ptr %ptr
+
+ %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> <i16 0, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>)
+ store volatile i32 %b, ptr %ptr
+
+ %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> <i32 0, i32 1, i32 1, i32 1>)
+ store volatile i32 %c, ptr %ptr
+
+ %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> <i64 0, i64 1>)
+ store volatile i32 %d, ptr %ptr
+
+ %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> <i64 0, i64 1, i64 1, i64 1>)
+ store volatile i32 %e, ptr %ptr
+
+ ret void
+}
+
+define void @all_true_splat_one(ptr %ptr) {
+; CHECK-LABEL: define void @all_true_splat_one(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.alltrue.v16i8(<16 x i8> splat (i8 1))
+; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.alltrue.v8i16(<8 x i16> splat (i16 1))
+; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i32(<4 x i32> splat (i32 1))
+; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.alltrue.v2i64(<2 x i64> splat (i64 1))
+; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i64(<4 x i64> splat (i64 1))
+; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: ret void
+;
+ %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> <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, i8 1, i8 1>)
+ store volatile i32 %a, ptr %ptr
+
+ %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>)
+ store volatile i32 %b, ptr %ptr
+
+ %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> <i32 1, i32 1, i32 1, i32 1>)
+ store volatile i32 %c, ptr %ptr
+
+ %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> <i64 1, i64 1>)
+ store volatile i32 %d, ptr %ptr
+
+ %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> <i64 1, i64 1, i64 1, i64 1>)
+ store volatile i32 %e, ptr %ptr
+
+ ret void
+}
+
+
+define void @any_true_splat_zero(ptr %ptr) {
+; CHECK-LABEL: define void @any_true_splat_zero(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.anytrue.v16i8(<16 x i8> zeroinitializer)
+; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.anytrue.v8i16(<8 x i16> zeroinitializer)
+; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i32(<4 x i32> zeroinitializer)
+; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.anytrue.v2i64(<2 x i64> zeroinitializer)
+; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i64(<4 x i64> zeroinitializer)
+; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: ret void
+;
+ %a = tail 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>)
+ store volatile i32 %a, ptr %ptr
+
+ %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> <i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
+ store volatile i32 %b, ptr %ptr
+
+ %c = tail call i32 @llvm.wasm.anytrue(<4 x i32> <i32 0, i32 0, i32 0, i32 0>)
+ store volatile i32 %c, ptr %ptr
+
+ %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> <i64 0, i64 0>)
+ store volatile i32 %d, ptr %ptr
+
+ %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> <i64 0, i64 0, i64 0, i64 0>)
+ store volatile i32 %e, ptr %ptr
+
+ ret void
+}
+
+
+define void @any_true_splat_not_all_zero(ptr %ptr) {
+; CHECK-LABEL: define void @any_true_splat_not_all_zero(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.anytrue.v16i8(<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>)
+; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.anytrue.v8i16(<8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
+; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i32(<4 x i32> <i32 1, i32 0, i32 0, i32 0>)
+; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.anytrue.v2i64(<2 x i64> <i64 1, i64 0>)
+; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
+; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i64(<4 x i64> <i64 1, i64 0, i64 0, i64 0>)
+; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: ret void
+;
+ %a = tail 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>)
+ store volatile i32 %a, ptr %ptr
+
+ %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
+ store volatile i32 %b, ptr %ptr
+
+ %c = tail call i32 @llvm.wasm.anytrue(<4 x i32> <i32 1, i32 0, i32 0, i32 0>)
+ store volatile i32 %c, ptr %ptr
+
+ %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> <i64 1, i64 0>)
+ store volatile i32 %d, ptr %ptr
+
+ %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> <i64 1, i64 0, i64 0, i64 0>)
+ store volatile i32 %e, ptr %ptr
+
+ ret void
+}
>From e27f5bc3cff07f242a0e29b4786126efc79897bb Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Wed, 9 Jul 2025 20:32:12 -0700
Subject: [PATCH 2/3] Added support for constant folding of wasm
anytrue/alltrue
---
llvm/lib/Analysis/ConstantFolding.cpp | 13 +++-
.../WebAssembly/const_fold_simd_intrinsics.ll | 60 +++++++------------
2 files changed, 32 insertions(+), 41 deletions(-)
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 6e469c034d9c8..ddd3f137ad84d 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1655,6 +1655,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
case Intrinsic::arm_mve_vctp32:
case Intrinsic::arm_mve_vctp64:
case Intrinsic::aarch64_sve_convert_from_svbool:
+ case Intrinsic::wasm_alltrue:
+ case Intrinsic::wasm_anytrue:
// WebAssembly float semantics are always known
case Intrinsic::wasm_trunc_signed:
case Intrinsic::wasm_trunc_unsigned:
@@ -2832,7 +2834,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// Support ConstantVector in case we have an Undef in the top.
if (isa<ConstantVector>(Operands[0]) ||
- isa<ConstantDataVector>(Operands[0])) {
+ isa<ConstantDataVector>(Operands[0]) ||
+ isa<ConstantAggregateZero>(Operands[0])) {
auto *Op = cast<Constant>(Operands[0]);
switch (IntrinsicID) {
default: break;
@@ -2856,6 +2859,14 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
/*roundTowardZero=*/true, Ty,
/*IsSigned*/true);
break;
+
+ case Intrinsic::wasm_anytrue:
+ return Op->isZeroValue() ? ConstantInt::get(Ty, 1)
+ : ConstantInt::get(Ty, 0);
+
+ case Intrinsic::wasm_alltrue:
+ return Op->isAllOnesValue() ? ConstantInt::get(Ty, 1)
+ : ConstantInt::get(Ty, 0);
}
}
diff --git a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
index a57b70c905a49..4d29b82f64d0d 100644
--- a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
+++ b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
@@ -15,16 +15,11 @@ target triple = "wasm32-unknown-unknown"
define void @all_true_splat_not_all_one(ptr %ptr) {
; CHECK-LABEL: define void @all_true_splat_not_all_one(
; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.alltrue.v16i8(<16 x i8> <i8 0, 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, i8 1>)
-; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.alltrue.v8i16(<8 x i16> <i16 0, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>)
-; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i32(<4 x i32> <i32 0, i32 1, i32 1, i32 1>)
-; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.alltrue.v2i64(<2 x i64> <i64 0, i64 1>)
-; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i64(<4 x i64> <i64 0, i64 1, i64 1, i64 1>)
-; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
%a = tail call i32 @llvm.wasm.alltrue(<16 x i8> <i8 0, 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, i8 1>)
@@ -48,16 +43,11 @@ define void @all_true_splat_not_all_one(ptr %ptr) {
define void @all_true_splat_one(ptr %ptr) {
; CHECK-LABEL: define void @all_true_splat_one(
; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.alltrue.v16i8(<16 x i8> splat (i8 1))
-; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.alltrue.v8i16(<8 x i16> splat (i16 1))
-; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i32(<4 x i32> splat (i32 1))
-; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.alltrue.v2i64(<2 x i64> splat (i64 1))
-; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i64(<4 x i64> splat (i64 1))
-; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
%a = tail call i32 @llvm.wasm.alltrue(<16 x i8> <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, i8 1, i8 1>)
@@ -82,16 +72,11 @@ define void @all_true_splat_one(ptr %ptr) {
define void @any_true_splat_zero(ptr %ptr) {
; CHECK-LABEL: define void @any_true_splat_zero(
; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.anytrue.v16i8(<16 x i8> zeroinitializer)
-; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.anytrue.v8i16(<8 x i16> zeroinitializer)
-; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i32(<4 x i32> zeroinitializer)
-; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.anytrue.v2i64(<2 x i64> zeroinitializer)
-; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i64(<4 x i64> zeroinitializer)
-; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
%a = tail 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>)
@@ -116,16 +101,11 @@ define void @any_true_splat_zero(ptr %ptr) {
define void @any_true_splat_not_all_zero(ptr %ptr) {
; CHECK-LABEL: define void @any_true_splat_not_all_zero(
; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = tail call i32 @llvm.wasm.anytrue.v16i8(<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>)
-; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.anytrue.v8i16(<8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
-; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i32(<4 x i32> <i32 1, i32 0, i32 0, i32 0>)
-; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.anytrue.v2i64(<2 x i64> <i64 1, i64 0>)
-; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4
-; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i64(<4 x i64> <i64 1, i64 0, i64 0, i64 0>)
-; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
%a = tail 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>)
>From e8d1ff2546f1229fc6cfa83d43e1cd1ff3b091ef Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Thu, 10 Jul 2025 18:11:33 -0700
Subject: [PATCH 3/3] Fix logic error in wasm_all_true, update tests
---
llvm/lib/Analysis/ConstantFolding.cpp | 15 +++--
.../WebAssembly/const_fold_simd_intrinsics.ll | 66 +++++++++----------
2 files changed, 44 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index ddd3f137ad84d..f0c3fdaa4e50d 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -2861,12 +2861,19 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
break;
case Intrinsic::wasm_anytrue:
- return Op->isZeroValue() ? ConstantInt::get(Ty, 1)
- : ConstantInt::get(Ty, 0);
+ return Op->isZeroValue() ? ConstantInt::get(Ty, 0)
+ : ConstantInt::get(Ty, 1);
case Intrinsic::wasm_alltrue:
- return Op->isAllOnesValue() ? ConstantInt::get(Ty, 1)
- : ConstantInt::get(Ty, 0);
+ // Check each element individually
+ unsigned E = cast<FixedVectorType>(Op->getType())->getNumElements();
+ for (unsigned I = 0; I != E; ++I)
+ if (Constant *Elt = Op->getAggregateElement(I))
+ if (Elt->isZeroValue())
+ return ConstantInt::get(Ty, 0);
+
+
+ return ConstantInt::get(Ty, 1);
}
}
diff --git a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
index 4d29b82f64d0d..063bb8a810384 100644
--- a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
+++ b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll
@@ -4,16 +4,16 @@
; Test that intrinsics wasm call are constant folded
-; all_one: a splat that is all one
-; not_all_one: a splat that is all one, except for 0 in the first location
+; all_non_zero: a splat that is all non_zero
+; not_all_non_zero: a splat that is all one, except for 0 in the first location
; all_zero: a splat that is all zero
-; not_all_zero: a splat that is all zero, except for 1 in the first location
+; not_all_zero: a splat that is all zero, except for a non-zero in the first location
target triple = "wasm32-unknown-unknown"
-define void @all_true_splat_not_all_one(ptr %ptr) {
-; CHECK-LABEL: define void @all_true_splat_not_all_one(
+define void @all_true_splat_not_all_none_zero(ptr %ptr) {
+; CHECK-LABEL: define void @all_true_splat_not_all_none_zero(
; CHECK-SAME: ptr [[PTR:%.*]]) {
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
@@ -22,16 +22,16 @@ define void @all_true_splat_not_all_one(ptr %ptr) {
; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
- %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> <i8 0, 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, i8 1>)
+ %a = tail 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>)
store volatile i32 %a, ptr %ptr
- %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> <i16 0, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>)
+ %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> <i16 0, i16 1, i16 2, i16 1, i16 1, i16 1, i16 1, i16 1>)
store volatile i32 %b, ptr %ptr
%c = tail call i32 @llvm.wasm.alltrue(<4 x i32> <i32 0, i32 1, i32 1, i32 1>)
store volatile i32 %c, ptr %ptr
- %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> <i64 0, i64 1>)
+ %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> <i64 0, i64 42>)
store volatile i32 %d, ptr %ptr
%e = tail call i32 @llvm.wasm.alltrue(<4 x i64> <i64 0, i64 1, i64 1, i64 1>)
@@ -40,17 +40,17 @@ define void @all_true_splat_not_all_one(ptr %ptr) {
ret void
}
-define void @all_true_splat_one(ptr %ptr) {
-; CHECK-LABEL: define void @all_true_splat_one(
+define void @all_true_splat_all_non_zero(ptr %ptr) {
+; CHECK-LABEL: define void @all_true_splat_all_non_zero(
; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
- %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> <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, i8 1, i8 1>)
+ %a = tail 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>)
store volatile i32 %a, ptr %ptr
%b = tail call i32 @llvm.wasm.alltrue(<8 x i16> <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>)
@@ -59,24 +59,24 @@ define void @all_true_splat_one(ptr %ptr) {
%c = tail call i32 @llvm.wasm.alltrue(<4 x i32> <i32 1, i32 1, i32 1, i32 1>)
store volatile i32 %c, ptr %ptr
- %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> <i64 1, i64 1>)
+ %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> <i64 2, i64 2>)
store volatile i32 %d, ptr %ptr
- %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> <i64 1, i64 1, i64 1, i64 1>)
+ %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> <i64 1, i64 2, i64 1, i64 1>)
store volatile i32 %e, ptr %ptr
ret void
}
-define void @any_true_splat_zero(ptr %ptr) {
-; CHECK-LABEL: define void @any_true_splat_zero(
+define void @any_true_splat_all_zero(ptr %ptr) {
+; CHECK-LABEL: define void @any_true_splat_all_zero(
; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
%a = tail 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>)
@@ -101,26 +101,26 @@ define void @any_true_splat_zero(ptr %ptr) {
define void @any_true_splat_not_all_zero(ptr %ptr) {
; CHECK-LABEL: define void @any_true_splat_not_all_zero(
; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
-; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4
; CHECK-NEXT: ret void
;
%a = tail 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>)
store volatile i32 %a, ptr %ptr
- %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
+ %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> <i16 3, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>)
store volatile i32 %b, ptr %ptr
%c = tail call i32 @llvm.wasm.anytrue(<4 x i32> <i32 1, i32 0, i32 0, i32 0>)
store volatile i32 %c, ptr %ptr
- %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> <i64 1, i64 0>)
+ %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> <i64 -1, i64 0>)
store volatile i32 %d, ptr %ptr
- %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> <i64 1, i64 0, i64 0, i64 0>)
+ %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> <i64 2, i64 0, i64 0, i64 0>)
store volatile i32 %e, ptr %ptr
ret void
More information about the llvm-commits
mailing list