[flang-commits] [flang] [flang] Inherit target specific code for BIND(C) types on Windows (PR #129579)
via flang-commits
flang-commits at lists.llvm.org
Thu Mar 6 07:30:35 PST 2025
jeanPerier wrote:
> Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed as if they were integers of the same size. Structs or unions of other sizes are passed as a pointer to memory allocated by the caller. For these aggregate types passed as a pointer, including __m128, the caller-allocated temporary memory must be 16-byte aligned.
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:
- why clang does not set the byval attribute when passing the struct in memory (like it is done for linux)?
- should the alignment of struct in memory be 16 like required when passing arguments, or the default alignment for the type?
```
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index e2f8fb9d239a..a22c82316a4d 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -780,6 +780,45 @@ struct TargetX86_64Win : public GenericTarget<TargetX86_64Win> {
}
return marshal;
}
+
+ CodeGenSpecifics::Marshalling
+ structArgumentType(mlir::Location loc, fir::RecordType type,
+ const Marshalling &) const override {
+ std::uint64_t size =
+ fir::getTypeSizeAndAlignmentOrCrash(loc, type, getDataLayout(), kindMap)
+ .first;
+ CodeGenSpecifics::Marshalling marshal;
+ if (size <= 8)
+ marshal.emplace_back(mlir::IntegerType::get(type.getContext(), size * 8),
+ AT{});
+ else
+ // TODO: investigate: clang is not setting the byval attribute, it is not
+ // clear why. Currently, this needs to be set here for flang so that the
+ // target-rewrite pass allocate memory as expected. Is it OK to set byval
+ // when clang does not?
+ marshal.emplace_back(fir::ReferenceType::get(type),
+ AT{16, /*byval=*/true, /*sret=*/false});
+ return marshal;
+ }
+
+ CodeGenSpecifics::Marshalling
+ structReturnType(mlir::Location loc, fir::RecordType type) const override {
+ std::uint64_t size =
+ fir::getTypeSizeAndAlignmentOrCrash(loc, type, getDataLayout(), kindMap)
+ .first;
+ CodeGenSpecifics::Marshalling marshal;
+ if (size <= 8)
+ marshal.emplace_back(mlir::IntegerType::get(type.getContext(), size * 8),
+ AT{});
+ else
+ // TODO: investigate: the ABI is not very clear about the alignment for
+ // the return in memory (while it was explicit about 16 for the argument
+ // passing case). Should it be the default alignment for that type
+ // instead?
+ marshal.emplace_back(fir::ReferenceType::get(type),
+ AT{16, /*byval=*/false, /*sret=*/true});
+ return marshal;
+ }
};
} // namespace
```
I validated on simple example that it does what I would expect reading the ABI:
```
module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"} {
// Cases where the type must be passed/returned in register.
func.func @test_t1(%0 : !t1) -> () {
return
}
func.func @test_call_t1(%0 : !fir.ref<!t1>) {
%1 = fir.load %0 : !fir.ref<!t1>
fir.call @test_t1(%1) : (!t1) -> ()
return
}
func.func @test_return_t1(%0 : !fir.ref<!t1>) -> !t1 {
%1 = fir.load %0 : !fir.ref<!t1>
return %1 : !t1
}
func.func @test_call_return_t1(%0 : !fir.ref<!t1>) -> () {
%1 = fir.call @test_return_t1(%0) : (!fir.ref<!t1>) -> !t1
fir.store %1 to %0 : !fir.ref<!t1>
return
}
// Cases where the type must be passed/returned on the stack.
func.func @test_call_t2(%0 : !fir.ref<!t2>) {
%1 = fir.load %0 : !fir.ref<!t2>
fir.call @test_t2(%1) : (!t2) -> ()
return
}
func.func @test_t2(%0 : !t2) -> () {
return
}
func.func @test_return_t2(%0 : !fir.ref<!t2>) -> !t2 {
%1 = fir.load %0 : !fir.ref<!t2>
return %1 : !t2
}
func.func @test_call_return_t2(%0 : !fir.ref<!t2>) -> () {
%1 = fir.call @test_return_t2(%0) : (!fir.ref<!t2>) -> !t2
fir.store %1 to %0 : !fir.ref<!t2>
return
}
}
```
https://github.com/llvm/llvm-project/pull/129579
More information about the flang-commits
mailing list