[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