[llvm] [WebAssembly][FastISel] Make use of `sign-ext` proposals instructions when available (PR #179855)

Demetrius Kanios via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 4 21:11:38 PST 2026


https://github.com/QuantumSegfault updated https://github.com/llvm/llvm-project/pull/179855

>From 48afd3b814577781d1f6be7473e3564ffefd3d22 Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Wed, 4 Feb 2026 19:53:42 -0800
Subject: [PATCH] Make use of sign-ext proposal instructions in FastISel

---
 .../WebAssembly/WebAssemblyFastISel.cpp       | 78 +++++++++++++++----
 .../CodeGen/WebAssembly/offset-fastisel.ll    |  7 +-
 llvm/test/CodeGen/WebAssembly/signext-arg.ll  |  7 +-
 .../test/CodeGen/WebAssembly/signext-inreg.ll |  7 +-
 4 files changed, 69 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
index f4860e21e310e..c869164d96945 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
@@ -478,8 +478,8 @@ unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
       .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
 
   Register Result = createResultReg(&WebAssembly::I32RegClass);
-  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
-          TII.get(WebAssembly::AND_I32), Result)
+  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::AND_I32),
+          Result)
       .addReg(Reg)
       .addReg(Imm);
 
@@ -502,14 +502,26 @@ unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
     return 0;
   }
 
+  if (Subtarget->hasSignExt()) {
+    if (From == MVT::i8 || From == MVT::i16) {
+      Register Result = createResultReg(&WebAssembly::I32RegClass);
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
+              TII.get(From == MVT::i16 ? WebAssembly::I32_EXTEND16_S_I32
+                                       : WebAssembly::I32_EXTEND8_S_I32),
+              Result)
+          .addReg(Reg);
+      return Result;
+    }
+  }
+
   Register Imm = createResultReg(&WebAssembly::I32RegClass);
   BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
           TII.get(WebAssembly::CONST_I32), Imm)
       .addImm(32 - MVT(From).getSizeInBits());
 
   Register Left = createResultReg(&WebAssembly::I32RegClass);
-  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
-          TII.get(WebAssembly::SHL_I32), Left)
+  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::SHL_I32),
+          Left)
       .addReg(Reg)
       .addReg(Imm);
 
@@ -551,12 +563,45 @@ unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
     if (From == MVT::i64)
       return copyValue(Reg);
 
-    Reg = signExtendToI32(Reg, V, From);
-
     Register Result = createResultReg(&WebAssembly::I64RegClass);
-    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
-            TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
-        .addReg(Reg);
+
+    if (Subtarget->hasSignExt()) {
+      if (From != MVT::i32) {
+        BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
+                TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
+            .addReg(Reg);
+
+        Reg = Result;
+        Result = createResultReg(&WebAssembly::I64RegClass);
+      }
+
+      switch (From) {
+      case MVT::i8:
+        BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
+                TII.get(WebAssembly::I64_EXTEND8_S_I64), Result)
+            .addReg(Reg);
+        return Result;
+      case MVT::i16:
+        BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
+                TII.get(WebAssembly::I64_EXTEND16_S_I64), Result)
+            .addReg(Reg);
+        return Result;
+      case MVT::i32:
+        BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
+                TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
+            .addReg(Reg);
+        return Result;
+      default:
+        break;
+      }
+    } else {
+      Reg = signExtendToI32(Reg, V, From);
+
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
+              TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
+          .addReg(Reg);
+    }
+
     return Result;
   }
 
@@ -597,8 +642,8 @@ unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
   assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
 
   Register NotReg = createResultReg(&WebAssembly::I32RegClass);
-  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
-          TII.get(WebAssembly::EQZ_I32), NotReg)
+  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::EQZ_I32),
+          NotReg)
       .addReg(Reg);
   return NotReg;
 }
@@ -1210,8 +1255,8 @@ bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
     return true;
   }
 
-  Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
-                                        In);
+  Register Reg =
+      fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), In);
   if (!Reg)
     return false;
   MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
@@ -1273,8 +1318,8 @@ bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
   materializeLoadStoreOperands(Addr);
 
   Register ResultReg = createResultReg(RC);
-  auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc),
-                     ResultReg);
+  auto MIB =
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg);
 
   addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
 
@@ -1422,8 +1467,7 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) {
   if (Reg == 0)
     return false;
 
-  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
-          TII.get(WebAssembly::RETURN))
+  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::RETURN))
       .addReg(Reg);
   return true;
 }
diff --git a/llvm/test/CodeGen/WebAssembly/offset-fastisel.ll b/llvm/test/CodeGen/WebAssembly/offset-fastisel.ll
index b896f8fde247e..5d82bb9a0a771 100644
--- a/llvm/test/CodeGen/WebAssembly/offset-fastisel.ll
+++ b/llvm/test/CodeGen/WebAssembly/offset-fastisel.ll
@@ -120,11 +120,8 @@ define i32 @load_i8_s_with_folded_offset(ptr %p) {
 ; CHECK-LABEL: load_i8_s_with_folded_offset:
 ; CHECK:         .functype load_i8_s_with_folded_offset (i32) -> (i32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    i32.load8_u $push3=, 24($0)
-; CHECK-NEXT:    i32.const $push0=, 24
-; CHECK-NEXT:    i32.shl $push1=, $pop3, $pop0
-; CHECK-NEXT:    i32.const $push4=, 24
-; CHECK-NEXT:    i32.shr_s $push2=, $pop1, $pop4
+; CHECK-NEXT:    i32.load8_u $push1=, 24($0)
+; CHECK-NEXT:    i32.extend8_s $push0=, $pop1
 ; CHECK-NEXT:    # fallthrough-return
   %q = ptrtoint ptr %p to i32
   %r = add nuw i32 %q, 24
diff --git a/llvm/test/CodeGen/WebAssembly/signext-arg.ll b/llvm/test/CodeGen/WebAssembly/signext-arg.ll
index fa595056c840c..d9f3a8a95b3b7 100644
--- a/llvm/test/CodeGen/WebAssembly/signext-arg.ll
+++ b/llvm/test/CodeGen/WebAssembly/signext-arg.ll
@@ -7,11 +7,8 @@ declare i32 @get_int(i16 %arg)
 
 define i32 @func_1(i16 %arg1 , i32 %arg2) #0 {
 ; CHECK-LABEL: func_1:
-; CHECK:         i32.const $push1=, 16
-; CHECK-NEXT:    i32.shl $push2=, $0, $pop1
-; CHECK-NEXT:    i32.const $push4=, 16
-; CHECK-NEXT:    i32.shr_s $push3=, $pop2, $pop4
-; CHECK-NEXT:    call $push0=, get_int, $pop3
+; CHECK:         i32.extend16_s $push1=, $0
+; CHECK-NEXT:    call $push0=, get_int, $pop1
 ; CHECK-NEXT:    end_function
 entry:
   %retval = call i32 @get_int(i16 signext %arg1)
diff --git a/llvm/test/CodeGen/WebAssembly/signext-inreg.ll b/llvm/test/CodeGen/WebAssembly/signext-inreg.ll
index 5778a9418a3d4..2a98b14226ab4 100644
--- a/llvm/test/CodeGen/WebAssembly/signext-inreg.ll
+++ b/llvm/test/CodeGen/WebAssembly/signext-inreg.ll
@@ -1,6 +1,7 @@
-; RUN: llc < %s -mattr=+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s --check-prefix=NOSIGNEXT
-
+; RUN: llc < %s -mattr=+sign-ext -fast-isel=0 -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -fast-isel=0 -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s --check-prefix=NOSIGNEXT
+; RUN: llc < %s -mattr=+sign-ext -fast-isel=1 -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -fast-isel=1 -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s --check-prefix=NOSIGNEXT
 target triple = "wasm32-unknown-unknown"
 
 ; CHECK-LABEL: i32_extend8_s:



More information about the llvm-commits mailing list