Fix x86 linux tests build and run (#57244)
authort-mustafin <66252296+t-mustafin@users.noreply.github.com>
Sat, 18 Sep 2021 00:21:31 +0000 (03:21 +0300)
committerGitHub <noreply@github.com>
Sat, 18 Sep 2021 00:21:31 +0000 (17:21 -0700)
[unix x86] Fix tests build
[unix x86] Add register map for crossgen2
            Fixes readytorun/coreroot_determinism/coreroot_determinism/coreroot_determinism.sh on x86 linux
[unix x86] Fix tail calls tests
[unix x86] Fix unmanaged callconv
[unix x86] Fix passing implicit args via stack
[unix x86] Pop hidden retbuff arg on cdecl callconv
[unix x86] Fix WriteBarrier call

[x86] Add calling convention name print to dump
[x86] Use ebx to pass VASigCookie to GenericPInvokeCalliHelper
            It fixes stack alignment in GenericPInvokeCalliHelper on unix x86

Fix storageType overflow assertion in TinyArray

12 files changed:
src/coreclr/jit/codegencommon.cpp
src/coreclr/jit/gentree.cpp
src/coreclr/jit/importer.cpp
src/coreclr/jit/morph.cpp
src/coreclr/jit/reglist.h
src/coreclr/jit/targetx86.h
src/coreclr/jit/tinyarray.h
src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs
src/coreclr/vm/i386/asmhelpers.S
src/coreclr/vm/i386/asmhelpers.asm
src/coreclr/vm/i386/jithelp.S
src/tests/baseservices/callconvs/NativeFunctions.cpp

index f0b2475..e80754f 100644 (file)
@@ -8523,6 +8523,14 @@ void CodeGen::genFnEpilog(BasicBlock* block)
 
             noway_assert(compiler->compArgSize < 0x10000); // "ret" only has 2 byte operand
         }
+
+#ifdef UNIX_X86_ABI
+        // The called function must remove hidden address argument from the stack before returning
+        // in case of struct returning according to cdecl calling convention on linux.
+        // Details: http://www.sco.com/developers/devspecs/abi386-4.pdf pages 40-43
+        if (compiler->info.compCallConv == CorInfoCallConvExtension::C && compiler->info.compRetBuffArg != BAD_VAR_NUM)
+            stkArgSize += TARGET_POINTER_SIZE;
+#endif // UNIX_X86_ABI
 #endif // TARGET_X86
 
         /* Return, popping our arguments (if any) */
index 491c7b3..e7cb693 100644 (file)
@@ -6426,7 +6426,8 @@ GenTreeCall* Compiler::gtNewCallNode(
 
     node->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
 #ifdef UNIX_X86_ABI
-    node->gtFlags |= GTF_CALL_POP_ARGS;
+    if (callType == CT_INDIRECT || callType == CT_HELPER)
+        node->gtFlags |= GTF_CALL_POP_ARGS;
 #endif // UNIX_X86_ABI
     for (GenTreeCall::Use& use : GenTreeCall::UseList(args))
     {
@@ -10013,6 +10014,33 @@ void GenTree::SetIndirExceptionFlags(Compiler* comp)
     return charsDisplayed;
 }
 
+#ifdef TARGET_X86
+inline const char* GetCallConvName(CorInfoCallConvExtension callConv)
+{
+    switch (callConv)
+    {
+        case CorInfoCallConvExtension::Managed:
+            return "Managed";
+        case CorInfoCallConvExtension::C:
+            return "C";
+        case CorInfoCallConvExtension::Stdcall:
+            return "Stdcall";
+        case CorInfoCallConvExtension::Thiscall:
+            return "Thiscall";
+        case CorInfoCallConvExtension::Fastcall:
+            return "Fastcall";
+        case CorInfoCallConvExtension::CMemberFunction:
+            return "CMemberFunction";
+        case CorInfoCallConvExtension::StdcallMemberFunction:
+            return "StdcallMemberFunction";
+        case CorInfoCallConvExtension::FastcallMemberFunction:
+            return "FastcallMemberFunction";
+        default:
+            return "UnknownCallConv";
+    }
+}
+#endif // TARGET_X86
+
 /*****************************************************************************/
 
 void Compiler::gtDispNodeName(GenTree* tree)
@@ -10098,6 +10126,10 @@ void Compiler::gtDispNodeName(GenTree* tree)
             {
                 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " thiscall");
             }
+#ifdef TARGET_X86
+            gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " %s",
+                                              GetCallConvName(tree->AsCall()->GetUnmanagedCallConv()));
+#endif // TARGET_X86
             gtfType = gtfTypeBuf;
         }
 
index 2fe7d20..8fcd39d 100644 (file)
@@ -1300,7 +1300,7 @@ GenTree* Compiler::impAssignStructPtr(GenTree*             destAddr,
             // Case of call returning a struct via hidden retbuf arg
             CLANG_FORMAT_COMMENT_ANCHOR;
 
-#if defined(TARGET_WINDOWS) && !defined(TARGET_ARM)
+#if (defined(TARGET_WINDOWS) && !defined(TARGET_ARM)) || defined(UNIX_X86_ABI)
             // Unmanaged instance methods on Windows need the retbuf arg after the first (this) parameter
             if (srcCall->IsUnmanaged())
             {
@@ -1366,7 +1366,7 @@ GenTree* Compiler::impAssignStructPtr(GenTree*             destAddr,
                 }
             }
             else
-#endif
+#endif // (defined(TARGET_WINDOWS) && !defined(TARGET_ARM)) || defined(UNIX_X86_ABI)
             {
                 // insert the return value buffer into the argument list as first byref parameter
                 srcCall->gtCallArgs = gtPrependNewCallArg(destAddr, srcCall->gtCallArgs);
@@ -7488,6 +7488,9 @@ GenTreeCall* Compiler::impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX i
     GenTreeCall* call = gtNewIndCallNode(fptr, callRetTyp, nullptr, ilOffset);
 
     call->gtFlags |= GTF_EXCEPT | (fptr->gtFlags & GTF_GLOB_EFFECT);
+#ifdef UNIX_X86_ABI
+    call->gtFlags &= ~GTF_CALL_POP_ARGS;
+#endif
 
     return call;
 }
index 59d088f..02b6653 100644 (file)
@@ -2833,17 +2833,8 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
         noway_assert(arg != nullptr);
         call->gtCallCookie = nullptr;
 
-#if defined(TARGET_X86)
-        // x86 passes the cookie on the stack as the final argument to the call.
-        GenTreeCall::Use** insertionPoint = &call->gtCallArgs;
-        for (; *insertionPoint != nullptr; insertionPoint = &((*insertionPoint)->NextRef()))
-        {
-        }
-        *insertionPoint = gtNewCallArgs(arg);
-#else  // !defined(TARGET_X86)
-        // All other architectures pass the cookie in a register.
+        // All architectures pass the cookie in a register.
         call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs);
-#endif // defined(TARGET_X86)
 
         nonStandardArgs.Add(arg, REG_PINVOKE_COOKIE_PARAM, NonStandardArgKind::PInvokeCookie);
         numArgs++;
@@ -2960,7 +2951,9 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
         }
 #ifdef UNIX_X86_ABI
         // Add in the ret buff arg
-        if (callHasRetBuffArg)
+        if (callHasRetBuffArg &&
+            call->unmgdCallConv != CorInfoCallConvExtension::C &&     // C and Stdcall calling conventions do not
+            call->unmgdCallConv != CorInfoCallConvExtension::Stdcall) // use registers to pass arguments.
             maxRegArgs++;
 #endif
     }
@@ -18201,8 +18194,8 @@ bool Compiler::fgCheckStmtAfterTailCall()
 //
 bool Compiler::fgCanTailCallViaJitHelper()
 {
-#ifndef TARGET_X86
-    // On anything except X86 we have no faster mechanism available.
+#if !defined(TARGET_X86) || defined(UNIX_X86_ABI)
+    // On anything except windows X86 we have no faster mechanism available.
     return false;
 #else
     // The JIT helper does not properly handle the case where localloc was used.
index 794f291..c8948b8 100644 (file)
@@ -9,7 +9,7 @@
 
 // The "regList" type is a small set of registerse
 #ifdef TARGET_X86
-typedef TinyArray<unsigned short, regNumber, REGNUM_BITS> regList;
+typedef TinyArray<unsigned int, regNumber, REGNUM_BITS> regList;
 #else
 // The regList is unused for all other targets.
 #endif // TARGET*
index 9f7d0fa..63c7f69 100644 (file)
   #define RBM_PINVOKE_TARGET_PARAM RBM_EAX
 
   // GenericPInvokeCalliHelper cookie parameter
-  #define REG_PINVOKE_COOKIE_PARAM REG_STK
+  #define REG_PINVOKE_COOKIE_PARAM REG_EBX
 
   // IL stub's secret parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
   #define REG_SECRET_STUB_PARAM    REG_EAX
index ef3a127..36cd462 100644 (file)
@@ -64,7 +64,7 @@ public:
 
     TinyArrayRef operator[](unsigned int n)
     {
-        assert((n + 1) * bits_per_element <= sizeof(itemType) * 8);
+        assert((n + 1) * bits_per_element <= sizeof(storageType) * 8);
         return TinyArrayRef(&data, n);
     }
     // only use this for clearing it
index 405bc57..70ca0da 100644 (file)
@@ -21,6 +21,7 @@ namespace ILCompiler.DependencyAnalysis.X86
             switch (os)
             {
                 case TargetOS.Windows:
+                case TargetOS.Linux:
                     Arg0 = Register.ECX;
                     Arg1 = Register.EDX;
                     Result = Register.EAX;
index 76b91c9..20d179f 100644 (file)
@@ -620,69 +620,20 @@ NESTED_END VarargPInvokeStub, _TEXT
 // Invoked for marshaling-required unmanaged CALLI calls as a stub.
 // EAX       - the unmanaged target
 // ECX, EDX  - arguments
-// [ESP + 4] - the VASigCookie
+// EBX       - the VASigCookie
 //
 LEAF_ENTRY GenericPInvokeCalliHelper, _TEXT
-    // save the target
-    push    eax
-
-    // EAX <- VASigCookie
-    mov     eax, [esp + 8]           // skip target and retaddr
-
-    mov     eax, [eax + VASigCookie__StubOffset]
-    test    eax, eax
 
+    cmp     dword ptr [ebx + VASigCookie__StubOffset], 0
     jz      LOCAL_LABEL(GoCallCalliWorker)
-    // ---------------------------------------
 
-    push    eax
-
-    // stack layout at this point:
-    //
-    // |         ...          |
-    // |   stack arguments    | ESP + 16
-    // +----------------------+
-    // |     VASigCookie*     | ESP + 12
-    // +----------------------+
-    // |    return address    | ESP + 8
-    // +----------------------+
-    // | CALLI target address | ESP + 4
-    // +----------------------+
-    // |   stub entry point   | ESP + 0
-    // ------------------------
-
-    // remove VASigCookie from the stack
-    mov     eax, [esp + 8]
-    mov     [esp + 12], eax
-
-    // move stub entry point below the RA
-    mov     eax, [esp]
-    mov     [esp + 8], eax
-
-    // load EAX with the target address
-    pop     eax
-    pop     eax
-
-    // stack layout at this point:
-    //
-    // |         ...          |
-    // |   stack arguments    | ESP + 8
-    // +----------------------+
-    // |    return address    | ESP + 4
-    // +----------------------+
-    // |   stub entry point   | ESP + 0
-    // ------------------------
-
-    // CALLI target address is in EAX
-    ret
+    // Stub is already prepared, just jump to it
+    jmp     dword ptr [ebx + VASigCookie__StubOffset]
 
 LOCAL_LABEL(GoCallCalliWorker):
-    // the target is on the stack and will become m_Datum of PInvokeCalliFrame
-    // call the stub generating worker
-    pop     eax
-
     //
-    // target ptr in EAX, VASigCookie ptr in EDX
+    // call the stub generating worker
+    // target ptr in EAX, VASigCookie ptr in EBX
     //
 
     STUB_PROLOG
@@ -692,11 +643,16 @@ LOCAL_LABEL(GoCallCalliWorker):
     // save target
     push        eax
 
+    #define STACK_ALIGN_PADDING 4
+    sub         esp, STACK_ALIGN_PADDING    // pass stack aligned to 0x10
     push        eax                         // unmanaged target
-    push        dword ptr [esi + 4*7]       // pVaSigCookie (first stack argument)
+    push        ebx                         // pVaSigCookie (first stack argument)
     push        esi                         // pTransitionBlock
 
+    CHECK_STACK_ALIGNMENT
     call        C_FUNC(GenericPInvokeCalliStubWorker)
+    add         esp, STACK_ALIGN_PADDING    // restore alignment, callee pop args
+    #undef STACK_ALIGN_PADDING
 
     // restore target
     pop     eax
index 2eb6620..d3eb78d 100644 (file)
@@ -1142,69 +1142,20 @@ _VarargPInvokeStub@0 endp
 ; Invoked for marshaling-required unmanaged CALLI calls as a stub.
 ; EAX       - the unmanaged target
 ; ECX, EDX  - arguments
-; [ESP + 4] - the VASigCookie
+; EBX       - the VASigCookie
 ;
 _GenericPInvokeCalliHelper@0 proc public
-    ; save the target
-    push    eax
-
-    ; EAX <- VASigCookie
-    mov     eax, [esp + 8]           ; skip target and retaddr
-
-    mov     eax, [eax + VASigCookie__StubOffset]
-    test    eax, eax
 
+    cmp     dword ptr [ebx + VASigCookie__StubOffset], 0
     jz      GoCallCalliWorker
-    ; ---------------------------------------
-
-    push    eax
-
-    ; stack layout at this point:
-    ;
-    ; |         ...          |
-    ; |   stack arguments    | ESP + 16
-    ; +----------------------+
-    ; |     VASigCookie*     | ESP + 12
-    ; +----------------------+
-    ; |    return address    | ESP + 8
-    ; +----------------------+
-    ; | CALLI target address | ESP + 4
-    ; +----------------------+
-    ; |   stub entry point   | ESP + 0
-    ; ------------------------
-
-    ; remove VASigCookie from the stack
-    mov     eax, [esp + 8]
-    mov     [esp + 12], eax
-
-    ; move stub entry point below the RA
-    mov     eax, [esp]
-    mov     [esp + 8], eax
 
-    ; load EAX with the target address
-    pop     eax
-    pop     eax
-
-    ; stack layout at this point:
-    ;
-    ; |         ...          |
-    ; |   stack arguments    | ESP + 8
-    ; +----------------------+
-    ; |    return address    | ESP + 4
-    ; +----------------------+
-    ; |   stub entry point   | ESP + 0
-    ; ------------------------
-
-    ; CALLI target address is in EAX
-    ret
+    ; Stub is already prepared, just jump to it
+    jmp     dword ptr [ebx + VASigCookie__StubOffset]
 
 GoCallCalliWorker:
-    ; the target is on the stack and will become m_Datum of PInvokeCalliFrame
-    ; call the stub generating worker
-    pop     eax
-
     ;
-    ; target ptr in EAX, VASigCookie ptr in EDX
+    ; call the stub generating worker
+    ; target ptr in EAX, VASigCookie ptr in EBX
     ;
 
     STUB_PROLOG
@@ -1215,7 +1166,7 @@ GoCallCalliWorker:
     push        eax
 
     push        eax                         ; unmanaged target
-    push        dword ptr [esi + 4*7]       ; pVaSigCookie (first stack argument)
+    push        ebx                         ; pVaSigCookie (first stack argument)
     push        esi                         ; pTransitionBlock
 
     call        _GenericPInvokeCalliStubWorker@12
index 4f227c9..e173381 100644 (file)
@@ -377,6 +377,7 @@ LEAF_ENTRY JIT_WriteBarrierGroup, _TEXT
     ret
 LEAF_END JIT_WriteBarrierGroup, _TEXT
 
+// Pointer to JIT_WriteBarrierEAX
     .data
     .align 4
     .global C_FUNC(JIT_WriteBarrierEAX_Loc)
@@ -396,6 +397,7 @@ LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT
     addl     $_GLOBAL_OFFSET_TABLE_+(2b-1b), %eax
 .intel_syntax noprefix
     mov     eax, dword ptr [eax + C_FUNC(JIT_WriteBarrierEAX_Loc)@GOT]
+    mov     eax, [eax]
     xchg    eax, dword ptr [esp]
     ret
 LEAF_END JIT_WriteBarrier_Callable, _TEXT
index 3f05e0a..4f12103 100644 (file)
@@ -11,7 +11,7 @@ namespace
     }
 }
 
-#if defined HOST_X86
+#if defined HOST_X86 && !defined TARGET_UNIX
 #pragma comment(linker, "/export:DoubleInt=_DoubleInt@4")
 #endif
 extern "C" DLL_EXPORT int DoubleInt(int a)
@@ -24,7 +24,7 @@ extern "C" DLL_EXPORT int __cdecl DoubleIntCdecl(int a)
     return DoubleIntImpl(a);
 }
 
-#if defined HOST_X86
+#if defined HOST_X86 && !defined TARGET_UNIX
 #pragma comment(linker, "/export:DoubleIntStdcall=_DoubleIntStdcall@4")
 #endif
 extern "C" DLL_EXPORT int __stdcall DoubleIntStdcall(int a)
@@ -42,7 +42,7 @@ namespace
     }
 }
 
-#if defined HOST_X86
+#if defined HOST_X86 && !defined TARGET_UNIX
 #pragma comment(linker, "/export:ToUpper=_ToUpper@4")
 #endif
 extern "C" DLL_EXPORT WCHAR ToUpper(WCHAR a)
@@ -55,7 +55,7 @@ extern "C" DLL_EXPORT WCHAR __cdecl ToUpperCdecl(WCHAR a)
     return ToUpperImpl(a);
 }
 
-#if defined HOST_X86
+#if defined HOST_X86 && !defined TARGET_UNIX
 #pragma comment(linker, "/export:ToUpperStdcall=_ToUpperStdcall@4")
 #endif
 extern "C" DLL_EXPORT WCHAR __stdcall ToUpperStdcall(WCHAR a)