From 637e45c63c2392f250a20e3714b7d6e16b8c6fa6 Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Wed, 9 Jul 2025 15:17:39 -0700 Subject: [PATCH 1/6] 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> ) +; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.alltrue.v8i16(<8 x i16> ) +; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i32(<4 x i32> ) +; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.alltrue.v2i64(<2 x i64> ) +; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i64(<4 x i64> ) +; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4 +; CHECK-NEXT: ret void +; + %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> ) + store volatile i32 %a, ptr %ptr + + %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> ) + store volatile i32 %b, ptr %ptr + + %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> ) + store volatile i32 %c, ptr %ptr + + %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) + store volatile i32 %d, ptr %ptr + + %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> ) + 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> ) + store volatile i32 %a, ptr %ptr + + %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> ) + store volatile i32 %b, ptr %ptr + + %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> ) + store volatile i32 %c, ptr %ptr + + %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) + store volatile i32 %d, ptr %ptr + + %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> ) + 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> ) + store volatile i32 %a, ptr %ptr + + %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> ) + store volatile i32 %b, ptr %ptr + + %c = tail call i32 @llvm.wasm.anytrue(<4 x i32> ) + store volatile i32 %c, ptr %ptr + + %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> ) + store volatile i32 %d, ptr %ptr + + %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> ) + 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> ) +; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.anytrue.v8i16(<8 x i16> ) +; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i32(<4 x i32> ) +; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.anytrue.v2i64(<2 x i64> ) +; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4 +; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i64(<4 x i64> ) +; CHECK-NEXT: store volatile i32 [[E]], ptr [[PTR]], align 4 +; CHECK-NEXT: ret void +; + %a = tail call i32 @llvm.wasm.anytrue(<16 x i8> ) + store volatile i32 %a, ptr %ptr + + %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> ) + store volatile i32 %b, ptr %ptr + + %c = tail call i32 @llvm.wasm.anytrue(<4 x i32> ) + store volatile i32 %c, ptr %ptr + + %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> ) + store volatile i32 %d, ptr %ptr + + %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> ) + store volatile i32 %e, ptr %ptr + + ret void +} From e27f5bc3cff07f242a0e29b4786126efc79897bb Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Wed, 9 Jul 2025 20:32:12 -0700 Subject: [PATCH 2/6] 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(Operands[0]) || - isa(Operands[0])) { + isa(Operands[0]) || + isa(Operands[0])) { auto *Op = cast(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> ) -; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.alltrue.v8i16(<8 x i16> ) -; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i32(<4 x i32> ) -; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.alltrue.v2i64(<2 x i64> ) -; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.alltrue.v4i64(<4 x i64> ) -; 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> ) @@ -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> ) @@ -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> ) @@ -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> ) -; CHECK-NEXT: store volatile i32 [[A]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.wasm.anytrue.v8i16(<8 x i16> ) -; CHECK-NEXT: store volatile i32 [[B]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[C:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i32(<4 x i32> ) -; CHECK-NEXT: store volatile i32 [[C]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[D:%.*]] = tail call i32 @llvm.wasm.anytrue.v2i64(<2 x i64> ) -; CHECK-NEXT: store volatile i32 [[D]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[E:%.*]] = tail call i32 @llvm.wasm.anytrue.v4i64(<4 x i64> ) -; 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> ) From e8d1ff2546f1229fc6cfa83d43e1cd1ff3b091ef Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Thu, 10 Jul 2025 18:11:33 -0700 Subject: [PATCH 3/6] 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(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> ) + %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> ) store volatile i32 %a, ptr %ptr - %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> ) + %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> ) store volatile i32 %b, ptr %ptr %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> ) store volatile i32 %c, ptr %ptr - %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) + %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) store volatile i32 %d, ptr %ptr %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> ) @@ -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> ) + %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> ) store volatile i32 %a, ptr %ptr %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> ) @@ -59,24 +59,24 @@ define void @all_true_splat_one(ptr %ptr) { %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> ) store volatile i32 %c, ptr %ptr - %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) + %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) store volatile i32 %d, ptr %ptr - %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> ) + %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> ) 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> ) @@ -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> ) store volatile i32 %a, ptr %ptr - %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> ) + %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> ) store volatile i32 %b, ptr %ptr %c = tail call i32 @llvm.wasm.anytrue(<4 x i32> ) store volatile i32 %c, ptr %ptr - %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> ) + %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> ) store volatile i32 %d, ptr %ptr - %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> ) + %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> ) store volatile i32 %e, ptr %ptr ret void From 06b2e1101b6ae7becbe78714da83503f256cf26f Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Thu, 10 Jul 2025 18:43:29 -0700 Subject: [PATCH 4/6] Fix code formatting error --- llvm/lib/Analysis/ConstantFolding.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index f0c3fdaa4e50d..9c1c2c6e60f02 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -2867,12 +2867,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, case Intrinsic::wasm_alltrue: // Check each element individually unsigned E = cast(Op->getType())->getNumElements(); - for (unsigned I = 0; I != E; ++I) - if (Constant *Elt = Op->getAggregateElement(I)) + 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); } } From 2a3f33a0d28e95d5a126306a20addea09cf76573 Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Fri, 11 Jul 2025 14:43:15 -0700 Subject: [PATCH 5/6] Remove tail from tail call --- .../WebAssembly/const_fold_simd_intrinsics.ll | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll index 063bb8a810384..9dc11204a671b 100644 --- a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll +++ b/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll @@ -12,8 +12,8 @@ target triple = "wasm32-unknown-unknown" -define void @all_true_splat_not_all_none_zero(ptr %ptr) { -; CHECK-LABEL: define void @all_true_splat_not_all_none_zero( +define void @all_true_splat_not_all_non_zero(ptr %ptr) { +; CHECK-LABEL: define void @all_true_splat_not_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 @@ -22,19 +22,19 @@ define void @all_true_splat_not_all_none_zero(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> ) + %a = call i32 @llvm.wasm.alltrue(<16 x i8> ) store volatile i32 %a, ptr %ptr - %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> ) + %b = call i32 @llvm.wasm.alltrue(<8 x i16> ) store volatile i32 %b, ptr %ptr - %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> ) + %c = call i32 @llvm.wasm.alltrue(<4 x i32> ) store volatile i32 %c, ptr %ptr - %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) + %d = call i32 @llvm.wasm.alltrue(<2 x i64> ) store volatile i32 %d, ptr %ptr - %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> ) + %e = call i32 @llvm.wasm.alltrue(<4 x i64> ) store volatile i32 %e, ptr %ptr ret void @@ -50,19 +50,19 @@ define void @all_true_splat_all_non_zero(ptr %ptr) { ; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4 ; CHECK-NEXT: ret void ; - %a = tail call i32 @llvm.wasm.alltrue(<16 x i8> ) + %a = call i32 @llvm.wasm.alltrue(<16 x i8> ) store volatile i32 %a, ptr %ptr - %b = tail call i32 @llvm.wasm.alltrue(<8 x i16> ) + %b = call i32 @llvm.wasm.alltrue(<8 x i16> ) store volatile i32 %b, ptr %ptr - %c = tail call i32 @llvm.wasm.alltrue(<4 x i32> ) + %c = call i32 @llvm.wasm.alltrue(<4 x i32> ) store volatile i32 %c, ptr %ptr - %d = tail call i32 @llvm.wasm.alltrue(<2 x i64> ) + %d = call i32 @llvm.wasm.alltrue(<2 x i64> ) store volatile i32 %d, ptr %ptr - %e = tail call i32 @llvm.wasm.alltrue(<4 x i64> ) + %e = call i32 @llvm.wasm.alltrue(<4 x i64> ) store volatile i32 %e, ptr %ptr ret void @@ -79,19 +79,19 @@ define void @any_true_splat_all_zero(ptr %ptr) { ; CHECK-NEXT: store volatile i32 0, ptr [[PTR]], align 4 ; CHECK-NEXT: ret void ; - %a = tail call i32 @llvm.wasm.anytrue(<16 x i8> ) + %a = call i32 @llvm.wasm.anytrue(<16 x i8> ) store volatile i32 %a, ptr %ptr - %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> ) + %b = call i32 @llvm.wasm.anytrue(<8 x i16> ) store volatile i32 %b, ptr %ptr - %c = tail call i32 @llvm.wasm.anytrue(<4 x i32> ) + %c = call i32 @llvm.wasm.anytrue(<4 x i32> ) store volatile i32 %c, ptr %ptr - %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> ) + %d = call i32 @llvm.wasm.anytrue(<2 x i64> ) store volatile i32 %d, ptr %ptr - %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> ) + %e = call i32 @llvm.wasm.anytrue(<4 x i64> ) store volatile i32 %e, ptr %ptr ret void @@ -108,19 +108,19 @@ define void @any_true_splat_not_all_zero(ptr %ptr) { ; CHECK-NEXT: store volatile i32 1, ptr [[PTR]], align 4 ; CHECK-NEXT: ret void ; - %a = tail call i32 @llvm.wasm.anytrue(<16 x i8> ) + %a = call i32 @llvm.wasm.anytrue(<16 x i8> ) store volatile i32 %a, ptr %ptr - %b = tail call i32 @llvm.wasm.anytrue(<8 x i16> ) + %b = call i32 @llvm.wasm.anytrue(<8 x i16> ) store volatile i32 %b, ptr %ptr - %c = tail call i32 @llvm.wasm.anytrue(<4 x i32> ) + %c = call i32 @llvm.wasm.anytrue(<4 x i32> ) store volatile i32 %c, ptr %ptr - %d = tail call i32 @llvm.wasm.anytrue(<2 x i64> ) + %d = call i32 @llvm.wasm.anytrue(<2 x i64> ) store volatile i32 %d, ptr %ptr - %e = tail call i32 @llvm.wasm.anytrue(<4 x i64> ) + %e = call i32 @llvm.wasm.anytrue(<4 x i64> ) store volatile i32 %e, ptr %ptr ret void From e8c031c06cd45567e0318be0d3c4c3b24e62592f Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Sun, 13 Jul 2025 07:17:29 -0700 Subject: [PATCH 6/6] Move test from codegen to transform/, use instsimplify --- .../InstSimplify/const-fold-wasm-simd-intrinsics.ll} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename llvm/test/{CodeGen/WebAssembly/const_fold_simd_intrinsics.ll => Transforms/InstSimplify/const-fold-wasm-simd-intrinsics.ll} (98%) diff --git a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll b/llvm/test/Transforms/InstSimplify/const-fold-wasm-simd-intrinsics.ll similarity index 98% rename from llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll rename to llvm/test/Transforms/InstSimplify/const-fold-wasm-simd-intrinsics.ll index 9dc11204a671b..7b30edbf7792b 100644 --- a/llvm/test/CodeGen/WebAssembly/const_fold_simd_intrinsics.ll +++ b/llvm/test/Transforms/InstSimplify/const-fold-wasm-simd-intrinsics.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -; RUN: opt -passes=instcombine -S < %s | FileCheck %s +; RUN: opt -passes=instsimplify -S < %s | FileCheck %s ; Test that intrinsics wasm call are constant folded