[llvm-dev] Correct way to pass int128 from LLVM to C++ function (MSVC)
Stefan de Bruijn via llvm-dev
llvm-dev at lists.llvm.org
Wed Dec 21 23:40:20 PST 2016
Ø 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>
More information about the llvm-dev
mailing list