[LLVMdev] About JIT by LLVM 2.9 or later
Eli Friedman
eli.friedman at gmail.com
Tue Nov 1 18:48:25 PDT 2011
2011/11/1 空明流转 <wuye9036 at gmail.com>:
> Hello guys,
>
> Thanks for your help when you are busing.
> I am working on an open source project. It supports shader language and
> I want JIT feature, so LLVM is used.
> But now I find the ABI & Calling Convention did not co-work with MSVC.
> For example, following code I have:
>
> struct float4 { float x, y, z, w; };
> struct float4x4 { float4 x, y, z, w; };
>
> float4 fetch_vs( float4x4* mat ){ return mat->y; }
>
> Caller:
>
> // ...
> float4x4 mat; // Initialized
> float4 ret = fetch(mat); // fetch is JITed by LLVM
> float4 ret_vs = fetch_vs(mat)
> // ...
>
> Callee(LLVM):
>
> %vec4 = type { float, float, float, float }
> %mat44 = type { %vec4, %vec4, %vec4, %vec4 }
> define %vec4 @fetch( %mat44* %m ) {
> %matval = load %mat44* %m
> %v2 = extractvalue %mat44 %matval, 2
> ret %vec4 %v2
> }
>
> But if it is implemented by LLVM and called the JIT-ed function in
> MSVC, the program will be crashed.
> I traced into the implementations, ASMs are:
>
> Caller:
>
> float4x4 f;
> float4 b = fetch(&f);
> // Calling function. first address is a temporary result generated by
> caller. And secondary is the &f.
> 013C1428 lea eax,[ebp-48h]
> 013C142B push eax
> 013C142C lea ecx,[ebp-138h]
> 013C1432 push ecx
> 013C1433 call fetch (13C11D6h)
> 013C1438 add esp,8
>
> // Copy result to another temporary vairable.
> 013C143B mov edx,dword ptr [eax]
> 013C143D mov dword ptr [ebp-150h],edx
> 013C1443 mov ecx,dword ptr [eax+4]
> 013C1446 mov dword ptr [ebp-14Ch],ecx
> 013C144C mov edx,dword ptr [eax+8]
> 013C144F mov dword ptr [ebp-148h],edx
> 013C1455 mov eax,dword ptr [eax+0Ch]
> 013C1458 mov dword ptr [ebp-144h],eax
> 013C145E mov ecx,dword ptr [ebp-150h]
>
> // Copy secondary temporary to variable 'b'
> 013C1464 mov dword ptr [ebp-60h],ecx
> 013C1467 mov edx,dword ptr [ebp-14Ch]
> 013C146D mov dword ptr [ebp-5Ch],edx
> 013C1470 mov eax,dword ptr [ebp-148h]
> 013C1476 mov dword ptr [ebp-58h],eax
> 013C1479 mov ecx,dword ptr [ebp-144h]
> 013C147F mov dword ptr [ebp-54h],ecx
>
> Callee( 'fetch_vs' MSVC ):
>
> float4 __cdecl fetch( float4x4* mat ){
>
> // Stack protection
> 002C13B0 push ebp
> 002C13B1 mov ebp,esp
> 002C13B3 sub esp,0C0h
> 002C13B9 push ebx
> 002C13BA push esi
> 002C13BB push edi
> 002C13BC lea edi,[ebp-0C0h]
> 002C13C2 mov ecx,30h
> 002C13C7 mov eax,0CCCCCCCCh
> 002C13CC rep stos dword ptr es:[edi]
> return mat->y;
>
> // Copy to address of first temporary variable.
> 002C13CE mov eax,dword ptr [mat]
> 002C13D1 add eax,10h
> 002C13D4 mov ecx,dword ptr [ebp+8]
> 002C13D7 mov edx,dword ptr [eax]
> 002C13D9 mov dword ptr [ecx],edx
> 002C13DB mov edx,dword ptr [eax+4]
> 002C13DE mov dword ptr [ecx+4],edx
> 002C13E1 mov edx,dword ptr [eax+8]
> 002C13E4 mov dword ptr [ecx+8],edx
> 002C13E7 mov eax,dword ptr [eax+0Ch]
> 002C13EA mov dword ptr [ecx+0Ch],eax
> 002C13ED mov eax,dword ptr [ebp+8]
> }
> 002C13F0 pop edi
> 002C13F1 pop esi
> 002C13F2 pop ebx
> 002C13F3 mov esp,ebp
> 002C13F5 pop ebp
> 002C13F6 ret
>
> Callee( 'fetch' LLVM ):
>
> 010B0010 mov eax,dword ptr [esp+4]
> 010B0014 mov ecx,dword ptr [esp+8]
> 010B0018 movss xmm0,dword ptr [ecx+1Ch]
> 010B001D movss dword ptr [eax+0Ch],xmm0
> 010B0022 movss xmm0,dword ptr [ecx+18h]
> 010B0027 movss dword ptr [eax+8],xmm0
> 010B002C movss xmm0,dword ptr [ecx+10h]
> 010B0031 movss xmm1,dword ptr [ecx+14h]
> 010B0036 movss dword ptr [eax+4],xmm1
> 010B003B movss dword ptr [eax],xmm0
> 010B003F ret 4 // There
> are nothing push/pop in function and stack space is managed by caller, so
> why ret 4 is generated?
>
> It will cause the stack unbalance before and after function call. the other
> code look like well.
>
> Following is my questions:
>
> 1. Why it generates "ret 4" but not "ret" without modify esp?
>From what I can find, that follows the Mingw calling convention (which
is generally the same as cdecl, but not quite the same when returning
a struct). Looks like it's an oversight; I'd suggest filing a bug.
> 2. Does it doesn't support Microsoft Visual C++ compiler directly ?
>
> 3. I want to integrate LLVM JIT in MSVC, is it possible? what I will do,
> such as generate a adapter function ? Any porting document for it?
> 4. Does Clang support MS's call convention? If it does, how it work? I
> traced into it, but code is too large.
People have used LLVM with MSVC; making your calls across compilers
simpler generally helps.
> 5. Does it support Mingw directly ?
LLVM support for mingw is generally more mature than the MSVC support.
> 6. Does x64 work if your solution is applied ?
The Windows 64-bit calling convention should work... it hasn't gotten
much testing as far as I know, though.
-Eli
More information about the llvm-dev
mailing list