[llvm] [WebAssembly] Fold constant `i8x16.swizzle` and `i8x16.relaxed.swizzle` to `shufflevector` (PR #169110)
Petr Penzin via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 27 22:23:11 PST 2025
================
@@ -0,0 +1,107 @@
+//=== WebAssemblyInstCombineIntrinsic.cpp -
+// WebAssembly specific InstCombine pass ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements a TargetTransformInfo analysis pass specific to
+/// WebAssembly. It uses the target's detailed information to provide more
+/// precise answers to certain TTI queries, while letting the target independent
+/// and default TTI implementations handle the rest.
+///
+//===----------------------------------------------------------------------===//
+
+#include "WebAssemblyTargetTransformInfo.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/IntrinsicsWebAssembly.h"
+#include "llvm/Transforms/InstCombine/InstCombiner.h"
+#include <optional>
+
+using namespace llvm;
+using namespace llvm::PatternMatch;
+
+/// Attempt to convert [relaxed_]swizzle to shufflevector if the mask is
+/// constant.
+static Value *simplifyWasmSwizzle(const IntrinsicInst &II,
+ InstCombiner::BuilderTy &Builder,
+ bool IsRelaxed) {
+ auto *V = dyn_cast<Constant>(II.getArgOperand(1));
+ if (!V)
+ return nullptr;
+
+ auto *VecTy = cast<FixedVectorType>(II.getType());
+ unsigned NumElts = VecTy->getNumElements();
+ assert(NumElts == 16);
+
+ // Construct a shuffle mask from constant integers or UNDEFs.
+ int Indexes[16];
+ bool AnyOutOfBounds = false;
+
+ for (unsigned I = 0; I < NumElts; ++I) {
+ Constant *COp = V->getAggregateElement(I);
+ if (!COp || (!isa<UndefValue>(COp) && !isa<ConstantInt>(COp)))
+ return nullptr;
+
+ if (isa<UndefValue>(COp)) {
+ Indexes[I] = -1;
+ continue;
+ }
+
+ int64_t Index = cast<ConstantInt>(COp)->getSExtValue();
+
+ if (Index >= NumElts && IsRelaxed) {
+ // For lane indices above 15, the relaxed_swizzle operation can choose
+ // between returning 0 or the lane at `Index % 16`. However, the choice
+ // must be made consistently. As the WebAssembly spec states:
+ //
+ // "The result of relaxed operators are implementation-dependent, because
+ // the set of possible results may depend on properties of the host
+ // environment, such as its hardware. Technically, their behaviour is
+ // controlled by a set of global parameters to the semantics that an
+ // implementation can instantiate in different ways. These choices are
+ // fixed, that is, parameters are constant during the execution of any
+ // given program."
+ //
+ // The WebAssembly runtime may choose differently from us, so we can't
+ // optimize a relaxed swizzle with lane indices above 15.
+ return nullptr;
+ }
+
+ if (Index >= NumElts || Index < 0) {
----------------
ppenzin wrote:
Official spec is the way to go. In the original swizzle indices are unsigned, just like all lane indices in the spec, relaxed spec added language to signify the value is treated as signed.
https://github.com/llvm/llvm-project/pull/169110
More information about the llvm-commits
mailing list