-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[flang] Inherit target specific code for BIND(C) types on Windows #129579
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-flang-fir-hlfir @llvm/pr-subscribers-flang-codegen Author: Markus Mützel (mmuetzel) ChangesInherit target specific code for Windows i386 and x86_64 from the classes that define that code for the respective processors on non-Windows operating systems. That allows re-using the existing implementation for BIND(C) types on non-Windows x86_64 also for Windows x86_64 targets. Full diff: https://github.com/llvm/llvm-project/pull/129579.diff 1 Files Affected:
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 2a1eb0bc33f5c..b03c1dd492ab0 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -199,10 +199,8 @@ struct TargetI386 : public GenericTarget<TargetI386> {
//===----------------------------------------------------------------------===//
namespace {
-struct TargetI386Win : public GenericTarget<TargetI386Win> {
- using GenericTarget::GenericTarget;
-
- static constexpr int defaultWidth = 32;
+struct TargetI386Win : public TargetI386 {
+ using TargetI386::TargetI386;
CodeGenSpecifics::Marshalling
complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
@@ -718,10 +716,8 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
//===----------------------------------------------------------------------===//
namespace {
-struct TargetX86_64Win : public GenericTarget<TargetX86_64Win> {
- using GenericTarget::GenericTarget;
-
- static constexpr int defaultWidth = 64;
+struct TargetX86_64Win : public TargetX86_64 {
+ using TargetX86_64::TargetX86_64;
CodeGenSpecifics::Marshalling
complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
|
If there is no functional change, can you add NFC to the patch title? Should we have an AArch64Win as well? |
As far as I am aware, the BIND(C) ABI for AArch64 is the same on Windows and Linux (at least as far as Fortran is concerned; it is subtly different in C++ but in ways that don't affect Fortran) so I don't believe there's any reason to have an AArch64Win here. |
Thank you for checking this PR.
While there is no functional change by this change for most targets, there is one for Windows x86_64 targets.
With this change, the existing implementation for x86_64 is also used when targeting Windows x86_64. This is essentially a follow up on 774703e. Back when I originally proposed those changes, the Since then, a few more member functions have been added to Instead of essentially copying most of the source code that already exists in the This change doesn't add any new implementation though. It just re-uses the existing implementation. Does that mean that NFC should still be added to the patch title? In any case, this is the first time I'm trying to contribute to LLVM since it moved to PRs on GitHub. Please, let me know if I'm doing something wrong. |
If there is a functional change please add a test. Thanks for contributing. Always welcome. The convention is to add a test if there is a functional change otherwise if there is no functional change then add NFC to the title. |
Are there tests for BIND(C) on non-Windows that I could use as an "inspiration"? |
Inherit target specific code for Windows i386 and x86_64 from the classes that define that code for the respective processors on non-Windows operating systems. Only overload parts that differ. That allows re-using the existing implementation for BIND(C) types on non-Windows x86_64 also for Windows x86_64 targets. Fixes llvm#114035.
It looks like the pre-commit CI is still passing with those tests running for a Windows x86_64 target. Is that good enough? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at godbolt with C examples, it seems Windows 64 does not have the same ABI when it comes to passing structs by value, it seems they must be passed in memory in more cases on windows: https://godbolt.org/z/sYMP7T3rr
Can you point to the ABI specification document link (I am not familiar with windows ABI to double check from the documentation)?
Oof. I didn't think about that. Windows x64 ABI conventions are documented here (I guess): https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170 |
Maybe, a relevant part:
I don't think I'll be able to implement that (unless with a lot of hand-holding). I'd very much appreciate if someone else could take that on. In which case, feel free to close this. |
It actually looks like a pretty straightforward ABI. I am reluctant to implement it myself because I cannot test end-to-end and I am not familiar with windows environment, but here is what the implementation could be below. Two things need to be clarified by someone familiar with the windows 64 ABI and clang:
I validated on simple example that it does what I would expect reading the ABI:
|
Thank you very much. Would it be ok to include the diff (with the TODO comments) in this PR? Maybe listing you as the author? I hope it is ok if I ping @mstorsjo because I think he might be able to answer your questions regarding argument passing. |
Sure, no problem with that. |
Thank you. I haven't updated the tests yet. (So, they'll probably fail now that the implementation is "more correct".) I figured that it could still be helpful to have these changes in the PR to make it easier to discuss them. |
Sorry, I don't really know much about this level of how these aspects are modelled in the LLVM IR. I think @rnk or maybe @efriedma-quic may know better (answers to the questions above in #129579 (comment)). |
"byval" is weird: it actually allocates memory on the stack, as part of the argument list, then copies the argument into that memory. Old targets sometimes pass memory like this. The designers for more modern ABIs have recognized that passing around large values like that isn't a good idea, so they don't do that; they pass a pointer to a temporary allocated on the stack. Try looking at the assembly on x86_64-linux-gnu vs. x86_64-windows-msvc for
The "caller-allocated temporary memory must be 16-byte aligned" specifically only applies to calls; in other contexts, normal alignment rules apply. |
Thanks @efriedma-quic, that clarified the difference for me! Looking at the callee side, I actually see now that for x86_64-linux-gnu, the callee is looking for the argument in memory at specific
My question was more specific to returned struct (sret). Looking at the ABI spec, I do not see a specific requirement for the alignment of the return value https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values, does that mean normal alignment rules apply for the hidden argument for the result, while it is always 16 for struct value argument passed in memory? Also, looking at LLVM IR emitted by clang for x86_64-windows-msvc, I see that memory allocated for struct value argument is not always 16 byte aligned (see the |
The spec also sometimes has holes, so probably we'd want to investigate MSVC code generation a bit. But that's my reading.
That's probably a bug? At least, that's my reading of the spec; not sure what happens in practice. |
Any progress? |
Inherit target specific code for Windows i386 and x86_64 from the classes that define that code for the respective processors on non-Windows operating systems.
Only overload parts that differ.
That allows re-using the existing implementation for BIND(C) types on non-Windows x86_64 also for Windows x86_64 targets.
Fixes #114035.