Skip to content

[WebAssembly] Fix inline assembly with vector types #146574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 2, 2025

Conversation

alexcrichton
Copy link
Contributor

This commit fixes using inline assembly with v128 results. Previously this failed with an internal assertion about a failure to legalize a CopyFromReg where the source register was typed v8f16. It looks like the type used for the destination register was whatever was listed first in the def V128 : WebAssemblyRegClass listing, so the types were shuffled around to have a default-supported type.

A small test was added as well which failed to generate previously and should now pass in generation. This test passed on LLVM 18 additionally and regressed by accident in #93228 which was first included in LLVM 19.

This commit fixes using inline assembly with v128 results. Previously
this failed with an internal assertion about a failure to legalize a
`CopyFromReg` where the source register was typed `v8f16`. It looks like
the type used for the destination register was whatever was listed first
in the `def V128 : WebAssemblyRegClass` listing, so the types were
shuffled around to have a default-supported type.

A small test was added as well which failed to generate previously and
should now pass in generation. This test passed on LLVM 18 additionally
and regressed by accident in llvm#93228 which was first included in LLVM 19.
@llvmbot
Copy link
Member

llvmbot commented Jul 1, 2025

@llvm/pr-subscribers-backend-webassembly

Author: Alex Crichton (alexcrichton)

Changes

This commit fixes using inline assembly with v128 results. Previously this failed with an internal assertion about a failure to legalize a CopyFromReg where the source register was typed v8f16. It looks like the type used for the destination register was whatever was listed first in the def V128 : WebAssemblyRegClass listing, so the types were shuffled around to have a default-supported type.

A small test was added as well which failed to generate previously and should now pass in generation. This test passed on LLVM 18 additionally and regressed by accident in #93228 which was first included in LLVM 19.


Full diff: https://github.com/llvm/llvm-project/pull/146574.diff

2 Files Affected:

  • (modified) llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td (+2-2)
  • (modified) llvm/test/CodeGen/WebAssembly/inline-asm.ll (+11)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
index 17889dacc868c..31a33c1e7365b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
@@ -64,8 +64,8 @@ def I32 : WebAssemblyRegClass<[i32], 32, (add FP32, SP32, I32_0)>;
 def I64 : WebAssemblyRegClass<[i64], 64, (add FP64, SP64, I64_0)>;
 def F32 : WebAssemblyRegClass<[f32], 32, (add F32_0)>;
 def F64 : WebAssemblyRegClass<[f64], 64, (add F64_0)>;
-def V128 : WebAssemblyRegClass<[v8f16, v4f32, v2f64, v2i64, v4i32, v16i8,
-                                v8i16],
+def V128 : WebAssemblyRegClass<[v2i64, v4i32, v16i8, v8i16,
+                                v8f16, v4f32, v2f64],
                                128, (add V128_0)>;
 def FUNCREF : WebAssemblyRegClass<[funcref], 0, (add FUNCREF_0)>;
 def EXTERNREF : WebAssemblyRegClass<[externref], 0, (add EXTERNREF_0)>;
diff --git a/llvm/test/CodeGen/WebAssembly/inline-asm.ll b/llvm/test/CodeGen/WebAssembly/inline-asm.ll
index 4462cfb7aa0c4..c378fd953a555 100644
--- a/llvm/test/CodeGen/WebAssembly/inline-asm.ll
+++ b/llvm/test/CodeGen/WebAssembly/inline-asm.ll
@@ -129,7 +129,18 @@ entry:
   ret i32 %ret
 }
 
+; CHECK-LABEL: v128_load
+; CHECK: local.get 0
+; CHECK-NEXT: v128.load 0
+; CHECK-NEXT: local.set 1
+define <4 x i32> @v128_load(ptr %v) #1 {
+entry:
+  %0 = tail call <4 x i32> asm "local.get $1\0Av128.load 0\0Alocal.set $0", "=r,r"(ptr %v)
+  ret <4 x i32> %0
+}
+
 attributes #0 = { nounwind }
+attributes #1 = { "target-features"="+simd128" }
 
 !0 = !{i32 47}
 !1 = !{i32 145}

Copy link
Member

@sunfishcode sunfishcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@alexcrichton
Copy link
Contributor Author

@sunfishcode would you be ok merging for me? I'm unable to do so myself.

@sunfishcode sunfishcode merged commit a8a9a7f into llvm:main Jul 2, 2025
9 checks passed
alexcrichton added a commit to alexcrichton/wasi-libc that referenced this pull request Jul 2, 2025
This commit is a refinement of WebAssembly#586 to use inline assembly to perform
vector loads instead of using a C-defined load. This is done to avoid UB
in LLVM where C cannot read either before or after an allocation. When
`strlen` is not inlined, as it currently isn't, then there's not really
any reasonable path that a compiler could prove that a load was
out-of-bounds so this is issue is unlikely in practice, but it
nevertheless is still UB. In the future the eventual goal is to move
these SIMD routines into header files to avoid needing multiple builds
of libc itself, and in such a situation inlining is indeed possible and
a compiler would be capable of much more easily seeing the UB which
could cause problems.

Inline assembly unfortunately doesn't work with vector output parameters
on Clang 19 and Clang 20 due to an ICE. This was fixed in
llvm/llvm-project#146574 for Clang 21, but it
means that the SIMD routines are now excluded with Clang 19 and Clang 20
to avoid compilation errors there.
sunfishcode pushed a commit to WebAssembly/wasi-libc that referenced this pull request Jul 3, 2025
This commit is a refinement of #586 to use inline assembly to perform
vector loads instead of using a C-defined load. This is done to avoid UB
in LLVM where C cannot read either before or after an allocation. When
`strlen` is not inlined, as it currently isn't, then there's not really
any reasonable path that a compiler could prove that a load was
out-of-bounds so this is issue is unlikely in practice, but it
nevertheless is still UB. In the future the eventual goal is to move
these SIMD routines into header files to avoid needing multiple builds
of libc itself, and in such a situation inlining is indeed possible and
a compiler would be capable of much more easily seeing the UB which
could cause problems.

Inline assembly unfortunately doesn't work with vector output parameters
on Clang 19 and Clang 20 due to an ICE. This was fixed in
llvm/llvm-project#146574 for Clang 21, but it
means that the SIMD routines are now excluded with Clang 19 and Clang 20
to avoid compilation errors there.
@stefson
Copy link

stefson commented Jul 7, 2025

@sunfishcode this is very shortterm, but there is a llvm-20.1.8 release planed for Tuesday - maybe you're able to cherry pick this fix into the llvm-20.x branch on such a short notice?

upstream announcement: https://discourse.llvm.org/t/llvm-20-1-8-plans/87207

@sunfishcode
Copy link
Member

/cherry-pick a8a9a7f

@llvmbot
Copy link
Member

llvmbot commented Jul 7, 2025

/pull-request #147409

@llvmbot llvmbot moved this from Needs Triage to Done in LLVM Release Status Jul 7, 2025
swift-ci pushed a commit to swiftlang/llvm-project that referenced this pull request Jul 7, 2025
This commit fixes using inline assembly with v128 results. Previously
this failed with an internal assertion about a failure to legalize a
`CopyFromReg` where the source register was typed `v8f16`. It looks like
the type used for the destination register was whatever was listed first
in the `def V128 : WebAssemblyRegClass` listing, so the types were
shuffled around to have a default-supported type.

A small test was added as well which failed to generate previously and
should now pass in generation. This test passed on LLVM 18 additionally
and regressed by accident in llvm#93228 which was first included in LLVM 19.

(cherry picked from commit a8a9a7f)
@alexcrichton alexcrichton deleted the wasm-fix-inline-assembly-simd branch July 8, 2025 15:04
sunfishcode added a commit to WebAssembly/wasi-sdk that referenced this pull request Jul 11, 2025
Update from LLVM 20.1.1  to 20.1.8. This release contains various bug
fixes and notably for wasi-sdk includes llvm/llvm-project#146574, which
fixes inline asm vector operands.
sunfishcode added a commit to WebAssembly/wasi-sdk that referenced this pull request Jul 12, 2025
Update from LLVM 20.1.1 to 20.1.8. This release contains various bug
fixes and notably for wasi-sdk includes llvm/llvm-project#146574, which
fixes inline asm vector operands.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

4 participants