V8_PRESERVE_MOST increases code size on Windows

105 views
Skip to first unread message

seth.b...@microsoft.com

unread,
Nov 20, 2023, 11:33:22 AM11/20/23
to v8-dev
Hi everyone,

I noticed some unfortunate disassembly recently and am curious about whether y'all are aware of this problem or have any ideas about how to fix it.

Problem description:

The Clang preserve_most attribute defines a new calling convention where all floating-point registers are caller-saved. This is a mismatch with the normal Windows calling convention, and causes any caller of a V8_PRESERVE_MOST function to save and restore xmm6 through xmm15, at a cost of 126 bytes of extra instructions per calling function. When there are many callers to a V8_PRESERVE_MOST function, this size cost adds up: for example, there are many hundreds of instantiations of the template AllocationDispatcher::Invoke in Chromium, and each one calls a V8_PRESERVE_MOST function. I tried disabling V8_PRESERVE_MOST and found that it reduced the size of a release build of chrome.dll by a whopping 2 MB.

The preserve_most calling convention is working correctly, as defined at https://clang.llvm.org/docs/AttributeReference.html#preserve-most . However, it's a bad fit for Windows. This problem has been raised in the LLVM discussion forum: https://discourse.llvm.org/t/conv-c-and-conv-preservemost-mix-badly-on-windows-x64/73054 .

The discussion question: what should we do about this? I could imagine a few answers:

1. Do nothing; it's working fine and we're okay with the code-size cost
2. Disable preserve_most for Windows builds, since the cost of saving and restoring all of those floating-point registers outweighs the benefit of avoiding similar stack access for general-purpose registers
3. Redefine preserve_most in a platform-specific way so it treats xmm6 through xmm15 as callee-save on Windows
4. Define a new Clang attribute preserve_most_win which is like preserve_most but with Windows semantics for floating-point registers
5. Use preserve_all instead on Windows, to declare that all floating-point registers are callee-save. This is appealing because it pushes the cost of saving and restoring into the cold function, but when I tried it, I got a bunch of internal compiler errors.

Best,
Seth

Clemens Backes

unread,
Nov 21, 2023, 9:02:54 AM11/21/23
to v8-...@googlegroups.com, biki...@chromium.org
Thanks for raising this issue. Looks like no one checked the assembly that's being generated on Windows.

I agree that we should do something about this. As both the preserve_most and preserve_all calling conventions are still experimental anyway, I think they can still both be changed in LLVM. Note that also the preserve_most attribute had issues originally, which Anton (CCed) fixed in https://reviews.llvm.org/D141020.

My personal preference for a fix would be either (3) or (5), but both would need fixes on the LLVM side. If that doesn't work we can also do (2) in the meantime.



--
--
v8-dev mailing list
v8-...@googlegroups.com
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-dev+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/v8-dev/3e5b967d-553e-40dd-ad7b-4a606d750f85n%40googlegroups.com.


--

Clemens Backes

Software Engineer

clem...@google.com

Google Germany GmbH

Erika-Mann-Straße 33

80636 München


Geschäftsführer: Paul Manicle, Liana Sebastian   

Registergericht und -nummer: Hamburg, HRB 86891

Sitz der Gesellschaft: Hamburg


Diese E-Mail ist vertraulich. Falls sie diese fälschlicherweise erhalten haben sollten, leiten Sie diese bitte nicht an jemand anderes weiter, löschen Sie alle Kopien und Anhänge davon und lassen Sie mich bitte wissen, dass die E-Mail an die falsche Person gesendet wurde.


This e-mail is confidential. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it has gone to the wrong person.


seth.b...@microsoft.com

unread,
Nov 22, 2023, 5:21:11 PM11/22/23
to v8-dev
Thanks, Clemens! I'm pleased to hear that the preserve_most semantics can still be changed, because I think option 3 is the most appealing. I'll look into implementing it in LLVM; if all goes well, we won't need to change anything in V8.

Best,
Seth

Anton Bikineev

unread,
Nov 23, 2023, 9:07:14 AM11/23/23
to v8-...@googlegroups.com
Thanks Seth for raising this. I agree with Clemens that (3) would be the best option. The only issue is that fixing preserve_most in LLVM would break binary compatibility (e.g. the caller code is recompiled whereas the old callee clobbers xmm6-xmm15), so it'll likely have to through some discussion first.

I guess you know it already, but just in case: changing preserve_most for Windows would likely require adding a new windows-specific callee-saved-regs list into X86CallingCond.td (e.g. CSR_Win64_RT_MostRegs) that would contain xmm6-xmm15. Then you'd need to dispatch based on whether IsWin64 in X86RegisterInfo.cpp.

seth.b...@microsoft.com

unread,
Dec 4, 2023, 3:06:55 PM12/4/23
to v8-dev

I guess you know it already, but just in case: changing preserve_most for Windows would likely require adding a new windows-specific callee-saved-regs list into X86CallingCond.td (e.g. CSR_Win64_RT_MostRegs) that would contain xmm6-xmm15. Then you'd need to dispatch based on whether IsWin64 in X86RegisterInfo.cpp.

I didn't know that, so you saved me a lot of time. Thanks! 🙂 The change is now landed in LLVM: Update preserve_most to treat XMM registers like C by sethbrenith · Pull Request #73866 · llvm/llvm-project (github.com).
 

Anton Bikineev

unread,
Dec 4, 2023, 3:40:18 PM12/4/23
to v8-...@googlegroups.com
I didn't know that, so you saved me a lot of time. Thanks! 🙂 The change is now landed in LLVM: Update preserve_most to treat XMM registers like C by sethbrenith · Pull Request #73866 · llvm/llvm-project (github.com).
Amazing, thanks for taking this over! Have you checked if this fixed the binary size regression (and possibly performance)?

пн, 4 дек. 2023 г. в 21:06, 'seth.b...@microsoft.com' via v8-dev <v8-...@googlegroups.com>:

I guess you know it already, but just in case: changing preserve_most for Windows would likely require adding a new windows-specific callee-saved-regs list into X86CallingCond.td (e.g. CSR_Win64_RT_MostRegs) that would contain xmm6-xmm15. Then you'd need to dispatch based on whether IsWin64 in X86RegisterInfo.cpp.

I didn't know that, so you saved me a lot of time. Thanks! 🙂 The change is now landed in LLVM: Update preserve_most to treat XMM registers like C by sethbrenith · Pull Request #73866 · llvm/llvm-project (github.com).
 

--
--
v8-dev mailing list
v8-...@googlegroups.com
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-dev+un...@googlegroups.com.


--
Sincerely,
Anton.

seth.b...@microsoft.com

unread,
Dec 5, 2023, 6:31:51 PM12/5/23
to v8-dev
Hi Anton,

I tried building Chromium with and without this LLVM change and saw a size reduction of 2.4 MB. However, that was a normal x64.release development build, and I'm not sure if official builds with profile-guided optimization will see the same benefit. I suspect that PGO might already have the power to override our recommendation of calling convention if it decides that a function is cold enough, which could avoid the problem in many cases.

I haven't done any speed testing, but I hope that this change will prevent future Windows-only regressions such as  1431430 - [Chromium Perf Sheriff]: 3 regressions in blink_perf.bindings - chromium.

Best,
Seth

Anton Bikineev

unread,
Dec 6, 2023, 8:25:04 AM12/6/23
to v8-...@googlegroups.com
I tried building Chromium with and without this LLVM change and saw a size reduction of 2.4 MB
Nice, thanks for checking, Seth!

Reply all
Reply to author
Forward
0 new messages