Stefan de Bruijn via llvm-dev
2016-Dec-21 19:18 UTC
[llvm-dev] Correct way to pass int128 from LLVM to C++ function (MSVC)
Thanks for the quick reply. Yes, passing it as int128* is a workaround that obviously works. Still, that leaves me with the return values. Or are you suggesting that I rewrite int128 Modify(int128& tmp) { … } to void Modify(int128& result, int128& tmp) { … } Obviously that will work, it just feels… dirty and wrong… :-) I’ve also attempted to bit-cast i128’s to <2 x i64> in LLVM. The ABI problems are pretty much the same. At a first glance, it seems to me like this problem is more general, namely: for all structures larger than 8 bytes. Kind regards, Stefan. From: Reid Kleckner [mailto:rnk at google.com] Sent: Wednesday, December 21, 2016 6:12 PM To: Stefan de Bruijn <stefan at nubilosoft.com> Cc: llvm-dev at lists.llvm.org Subject: Re: [llvm-dev] Correct way to pass int128 from LLVM to C++ function (MSVC) The Windows x64 ABI rules say that anything larger than 8 bytes is passed by reference.[1] Because MSVC doesn't support the __int128 type on x64, nobody has made sure that the LLVM i128 type is passed in a way that follows the local ABI rules. I think LLVM should probably pass i128 the same way it passes <2 x i64> on Win64, which is indirectly in memory. Until LLVM is fixed, you can work around the problem by passing i128 by pointer, which you're probably already doing. Given that we will ultimately pass it by pointer in order to obey the ABI, it's a pretty reasonable workaround. [1] https://msdn.microsoft.com/en-us/library/ms235286.aspx On Wed, Dec 21, 2016 at 4:35 AM, Stefan de Bruijn via llvm-dev <llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org>> wrote: Hi, I’ve been attempting to call a C++ function from LLVM code. The LLVM code is JIT’ted and executed from C++. Basically my idea was as follows: -- LLVM IR code – ; ModuleID = 'native' define i32 @main(i32, i8**) { code: call void @"Helper::Test"(i128 128932) ret i32 0 -- C++ code – struct int128 { uint64_t v1; uint64_t v2; // … code omitted… *1 }; struct Helper { static void Test(int128 value) { } }; If I try to execute the code, I notice that MSVC++ seems to expect a pointer. Most notably, if you implement the copy constructor: int128(const int128& o) { … } , the address of o will be 128932 . As for assembler output, I noticed that %ecx is set to the value, %edx is zero’d and then the method is called. As evidenced by the resulting crash, this is apparently not the right way to do something like this… Obviously, I can also try to pass the value by pointer - but will then get issues with return values. Alternatively, I can introduce a 2x64-bit structure, fill that with the int128 and pass that. My question is: what’s the correct way to do something like this? Kind regards, Stefan. _______________________________________________ LLVM Developers mailing list llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161221/4974e4ab/attachment.html>
Reid Kleckner via llvm-dev
2016-Dec-21 21:13 UTC
[llvm-dev] Correct way to pass int128 from LLVM to C++ function (MSVC)
On Wed, Dec 21, 2016 at 11:18 AM, Stefan de Bruijn <stefan at nubilosoft.com> wrote:> Thanks for the quick reply. Yes, passing it as int128* is a workaround > that obviously works. Still, that leaves me with the return values. Or are > you suggesting that I rewrite > > > > int128 Modify(int128& tmp) { … } > > > > to > > > > void Modify(int128& result, int128& tmp) { … } > > > > Obviously that will work, it just feels… dirty and wrong… :-) >Eh, you're just doing what LLVM would do on your behalf. It will open some optimizations but block others. =/> I’ve also attempted to bit-cast i128’s to <2 x i64> in LLVM. The ABI > problems are pretty much the same. At a first glance, it seems to me like > this problem is more general, namely: for all structures larger than 8 > bytes. >My tests show that we translate __m128i to <2 x i64>, and that we are ABI compatible with MSVC when passing __m128i values, so this should actually work. Behind the scenes LLVM will pass these values indirectly by pointer. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161221/7121ab07/attachment.html>
Stefan de Bruijn via llvm-dev
2016-Dec-22 07:40 UTC
[llvm-dev] Correct way to pass int128 from LLVM to C++ function (MSVC)
Ø Eh, you're just doing what LLVM would do on your behalf. It will open some optimizations but block others. =/ Well, if that’s the case, I obviously rather have LLVM do it. Unfortunately, I can’t seem to get that working. The “workaround” (passing a pointer instead of a struct) that I also tested, works just fine. Needless to say that I’ll probably end up doing that. Ø My tests show that we translate __m128i to <2 x i64>, and that we are ABI compatible with MSVC when passing __m128i values, so this should actually work. Behind the scenes LLVM will pass these values indirectly by pointer. Let me put the test case in code. As a reference point, I tried the following C++ code. #include <cstdint> struct myInt128 { uint64_t v1; uint64_t v2; }; myInt128 Test(myInt128 lhs) { return lhs; } int main() { __int128 lhs = 1; Test(*reinterpret_cast<myInt128*>(&lhs)); return 0; } Compiling it with Clang --emit-llvm will give me the following: %struct.myInt128 = type { i64, i64 } define void @"\01?Test@@YA?AUmyInt128@@U1@@Z"(%struct.myInt128* noalias nocapture sret %agg.result, %struct.myInt128* nocapture readonly %lhs) #0 { In other words, Clang seems to convert the ‘void’ to an int128 pointer which basically handles the ABI compatibility. I was actually surprised by this, because I expected LLVM to do the ABI conversions. Next, I attempted to produce have LLVM handle the ABI conversions by emitting the following LLVM in my JIT (irrelevant code omitted): %Int128Wrapper = type { i64, i64 } declare void @"Helper::Test"(%Int128Wrapper) define i32 @main(i32, i8**) { code: %passTemp = alloca i128 store i128 128932, i128* %passTemp %6 = bitcast i128* %passTemp to %Int128Wrapper* %7 = load %Int128Wrapper, %Int128Wrapper* %6 call void @"Helper::Test"(%Int128Wrapper %7) ret i32 0 When executing this program, the it crashes and on closer inspection, the parameter (%7) that’s passed from LLVM has an address of 128932 in Test. So, from these tests I concluded that LLVM doesn’t handle the ABI conversions (but Clang usually does). Kind regards, Stefan. From: Reid Kleckner [mailto:rnk at google.com] Sent: Wednesday, December 21, 2016 10:14 PM To: Stefan de Bruijn <stefan at nubilosoft.com> Cc: llvm-dev at lists.llvm.org Subject: Re: [llvm-dev] Correct way to pass int128 from LLVM to C++ function (MSVC) On Wed, Dec 21, 2016 at 11:18 AM, Stefan de Bruijn <stefan at nubilosoft.com<mailto:stefan at nubilosoft.com>> wrote: Thanks for the quick reply. Yes, passing it as int128* is a workaround that obviously works. Still, that leaves me with the return values. Or are you suggesting that I rewrite int128 Modify(int128& tmp) { … } to void Modify(int128& result, int128& tmp) { … } Obviously that will work, it just feels… dirty and wrong… :-) Eh, you're just doing what LLVM would do on your behalf. It will open some optimizations but block others. =/ I’ve also attempted to bit-cast i128’s to <2 x i64> in LLVM. The ABI problems are pretty much the same. At a first glance, it seems to me like this problem is more general, namely: for all structures larger than 8 bytes. My tests show that we translate __m128i to <2 x i64>, and that we are ABI compatible with MSVC when passing __m128i values, so this should actually work. Behind the scenes LLVM will pass these values indirectly by pointer. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161222/406716b6/attachment-0001.html>
Seemingly Similar Threads
- Correct way to pass int128 from LLVM to C++ function (MSVC)
- Correct way to pass int128 from LLVM to C++ function (MSVC)
- Correct way to pass int128 from LLVM to C++ function (MSVC)
- Portable multiplication 64 x 64 -> 128 for int128 reimplementation
- [cfe-dev] Portable multiplication 64 x 64 -> 128 for int128 reimplementation