[WebAssembly] Explicitly set getCmpLibcallReturnType to i32#192425
[WebAssembly] Explicitly set getCmpLibcallReturnType to i32#192425
getCmpLibcallReturnType to i32#192425Conversation
|
@llvm/pr-subscribers-backend-webassembly Author: Trevor Gross (tgross35) ChangesLLVM's default for The unintentional i32 default is actually a reasonable choice for Wasm because it may be slightly cheaper to operate on when running 64-bit wasm on 32-bit hosts, and there is no advantage to using a larger integer (the result of comparisons need only be able to represent three possible values). Thus, do the following:
GCC does not support wasm64 so there is no compatibility concern at the current time. If added, it would be reasonable for Closes: #75302 Full diff: https://github.com/llvm/llvm-project/pull/192425.diff 3 Files Affected:
diff --git a/compiler-rt/lib/builtins/fp_compare_impl.inc b/compiler-rt/lib/builtins/fp_compare_impl.inc
index f883338c471d3..129d0136a0b98 100644
--- a/compiler-rt/lib/builtins/fp_compare_impl.inc
+++ b/compiler-rt/lib/builtins/fp_compare_impl.inc
@@ -15,6 +15,9 @@
#if defined(__aarch64__) || defined(__arm64ec__)
// AArch64 GCC overrides libgcc_cmp_return to use int instead of long.
typedef int CMP_RESULT;
+#elif defined(__wasm__)
+// Both wasm32 and wasm64 use i32
+typedef int CMP_RESULT;
#elif __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 4
// LLP64 ABIs use long long instead of long.
typedef long long CMP_RESULT;
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 9caeef89d0b1c..14958f5674d46 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -106,7 +106,7 @@ Changes to LLVM infrastructure
([#177046](https://github.com/llvm/llvm-project/pull/125687)). Note that
there are still issues with invalid compiler reasoning about some functions
in bitcode, e.g. `malloc`. Not yet supported on MachO or when using
- distributed ThinLTO.
+ distributed ThinLTO.
Changes to building LLVM
------------------------
@@ -198,6 +198,9 @@ Changes to the RISC-V Backend
Changes to the WebAssembly Backend
----------------------------------
+* The result of runtime library call comparisons is explicitly set to `i32` on
+ both wasm32 and wasm64.
+
Changes to the Windows Target
-----------------------------
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
index 42f047840e504..5de57615dccd4 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
@@ -29,6 +29,10 @@ class WebAssemblyTargetLowering final : public TargetLowering {
MVT getPointerTy(const DataLayout &DL, uint32_t AS = 0) const override;
MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const override;
+ MVT::SimpleValueType getCmpLibcallReturnType() const override {
+ // i32 may be more efficient than the default word size for wasm64 targets
+ return MVT::i32;
+ }
private:
/// Keep a pointer to the WebAssemblySubtarget around so that we can make the
/// right decision when generating code for different targets.
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
64928b1 to
e45bb7d
Compare
|
|
||
| MVT::SimpleValueType getCmpLibcallReturnType() const override { | ||
| // i32 may be more efficient than the default word size for wasm64 targets | ||
| return MVT::i32; |
There was a problem hiding this comment.
But doesn't the base class already default to returning i32? i.e. this override isn't doing anything is it?
See:
llvm-project/llvm/lib/CodeGen/TargetLoweringBase.cpp
Lines 1962 to 1964 in 547197d
There was a problem hiding this comment.
Currently yes but that's something that should change. This is just making the wasm choice explicit before that happens since (afaik) wasm64 is the only one to hit the case where i32 and a word have an incompatible ABI, aside from those with overrides in GCC.
I'm planning to follow up with #192441
There was a problem hiding this comment.
I would rather you include the override when you land #192441.. since that is the point at which it becomes needed.
There was a problem hiding this comment.
Also, I'm not actually sure its worth diverging here for wasm64. We might just want to go with wordsize too for consistency.
There was a problem hiding this comment.
I can drop the override.
Also, I'm not actually sure its worth diverging here for wasm64. We might just want to go with wordsize too for consistency.
On most 64-bit targets there is no extra cost between a word sized comparison and a 32-bit and they share the same ABI, so those targets that happen to be consistent also aren't paying anything extra. IIUC however, wasm64 can still be running on 32-bit targets. On those, using a 64-bit comparison result rather than 32-bit means each libcall cmp costs up to (1) an extra register to be clobbered during return, (2) an extra instruction to put a meaningless value in that register, (3) ~2 extra instructions when checking the compare result.
This probably doesn't show up noticeably, especially considering the libcall is doing a lot more. But it seems like a reasonable enough case to break consistency considering 62 of the bits are wasted anyway.
sbc100
left a comment
There was a problem hiding this comment.
Any idea why this hasn't shown up already, for example, in emscripten?
@Spxg pointed out in rust-lang/compiler-builtins#1199 that emscripten's fork of compiler-rt is patching for this https://github.com/emscripten-core/emscripten/blob/88e0002141254cdb772b558f63d2c1ad9b215eb2/system/lib/compiler-rt/lib/builtins/fp_compare_impl.inc#L15. |
Oh yes that makes sense :) How about just porting emscripten patch here (i.e. just modifying line 15 instead of adding a whole new block?) |
Mostly because "// AArch64 GCC overrides libgcc_cmp_return to use int instead of long." doesn't apply here |
You can add anther line to the existing comment. |
|
/cc @aheejin |
dschuff
left a comment
There was a problem hiding this comment.
I have a mild preference for the separate ifdef for wasm in compiler-rt since we have a separate comment, but I could go either way.
…method. NFC (llvm#192483) This trivial method makes more sense in the header (indeed, both the existing overrides for it are already in headers). I noticed this while hunting for the default value while reviewing llvm#192425
e45bb7d to
ebae57a
Compare
|
Thanks for the reviews. I'll need one of you to merge this, unless anyone feels more strongly about the comment or deferring the override. (I have a mild preference as-is of course, but 🤷♂️ ) |
|
I thought we were doing to avoid adding an override until one is needed? I.e. until #192441 lands? |
| ---------------------------------- | ||
|
|
||
| * The result of runtime library call comparisons is explicitly set to `i32` on | ||
| both wasm32 and wasm64. |
There was a problem hiding this comment.
Since i32 was the default already I don't think we need to changelog entry do we? i.e. nothing actually changed here?
There was a problem hiding this comment.
There is no change, but this was meant as an FYI that forks of compiler-rt or independent implementations may want to update. That affects a very small number of people though, so I'll drop.
| typedef int CMP_RESULT; | ||
| #elif defined(__wasm__) | ||
| // Both wasm32 and wasm64 use i32 | ||
| typedef int CMP_RESULT; |
There was a problem hiding this comment.
This change seems like it can land in isolation, it just reflects the current reality, right?
I still feel like having a target-specific change is nicer in log/blame to make it clear that this was an intentional decision, rather than being wrapped in a more generic "change default, preserve current behavior" diff. I've been bitten by this before, still wondering about some GCC ABI decisions that look like this in git :) Also took the other approvals to think this was fine. But if you still feel strongly, will drop. |
|
I think it's easier to just split off the compiler-rt changes since the context is pretty different. Opened #194093 |
LLVM's default for `getCmpLibcallReturnType` is currently set to `i32`, but this is not exactly accurate: the default in GCC is an integer of word size. This means that on wasm64 targets, runtime libraries that are assuming word size are incorrect and instead need to be using a 32-bit integer. The unintentional i32 default is actually a reasonable choice for Wasm because it may be slightly cheaper to operate on when running 64-bit wasm on 32-bit hosts, and there is no advantage to using a larger integer (the result of comparisons need only be able to represent three possible values). Thus, make the `i32` explicit. GCC does not support wasm64 so there is no compatibility concern at the current time. If added, it would be reasonable for `i32` to be used there as well.
ebae57a to
385a4b1
Compare
…method. NFC (llvm#192483) This trivial method makes more sense in the header (indeed, both the existing overrides for it are already in headers). I noticed this while hunting for the default value while reviewing llvm#192425
LLVM's default for
getCmpLibcallReturnTypeis currently set toi32,but this is not exactly accurate: the default in GCC is an integer of
word size. This means that on wasm64 targets, runtime libraries that are
assuming word size are incorrect and instead need to be using a 32-bit
integer.
The unintentional i32 default is actually a reasonable choice for Wasm
because it may be slightly cheaper to operate on when running 64-bit
wasm on 32-bit hosts, and there is no advantage to using a larger
integer (the result of comparisons need only be able to represent three
possible values). Thus, make the
i32explicit.GCC does not support wasm64 so there is no compatibility concern at the
current time. If added, it would be reasonable for
i32to be usedthere as well.