Skip to content

Commit

Permalink
[LoongArch64] Add nativeaot support on LoongArch64. (#103889)
Browse files Browse the repository at this point in the history
* [LoongArch64] Add nativeaot support on LoongArch64.

---------

Co-authored-by: Filip Navara <filip.navara@gmail.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
3 people authored Jul 6, 2024
1 parent 67e1983 commit aee78d3
Show file tree
Hide file tree
Showing 26 changed files with 1,359 additions and 76 deletions.
2 changes: 1 addition & 1 deletion eng/Subsets.props
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
<PropertyGroup>
<!-- CLR NativeAot only builds in a subset of the matrix -->
<_NativeAotSupportedOS Condition="'$(TargetOS)' == 'windows' or '$(TargetOS)' == 'linux' or '$(TargetOS)' == 'osx' or '$(TargetOS)' == 'maccatalyst' or '$(TargetOS)' == 'iossimulator' or '$(TargetOS)' == 'ios' or '$(TargetOS)' == 'tvossimulator' or '$(TargetOS)' == 'tvos' or '$(TargetOS)' == 'freebsd'">true</_NativeAotSupportedOS>
<_NativeAotSupportedArch Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64' or '$(TargetArchitecture)' == 'arm' or ('$(TargetOS)' == 'windows' and '$(TargetArchitecture)' == 'x86')">true</_NativeAotSupportedArch>
<_NativeAotSupportedArch Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64' or '$(TargetArchitecture)' == 'arm' or '$(TargetArchitecture)' == 'loongarch64' or ('$(TargetOS)' == 'windows' and '$(TargetArchitecture)' == 'x86')">true</_NativeAotSupportedArch>
<NativeAotSupported Condition="'$(_NativeAotSupportedOS)' == 'true' and '$(_NativeAotSupportedArch)' == 'true'">true</NativeAotSupported>
<UseNativeAotForComponents Condition="'$(NativeAotSupported)' == 'true' and '$(TargetOS)' == '$(HostOS)' and ('$(TargetOS)' != 'windows' or '$(TargetArchitecture)' != 'x86') and '$(TargetsLinuxBionic)' != 'true' and ('$(TargetsLinuxMusl)' != 'true' or '$(TargetArchitecture)' != 'arm')">true</UseNativeAotForComponents>

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ add_subdirectory(tools/aot/jitinterface)

if(NOT CLR_CROSS_COMPONENTS_BUILD)
# NativeAOT only buildable for a subset of CoreCLR-supported configurations
if(CLR_CMAKE_HOST_ARCH_ARM64 OR CLR_CMAKE_HOST_ARCH_AMD64 OR CLR_CMAKE_HOST_ARCH_ARM OR (CLR_CMAKE_HOST_ARCH_I386 AND CLR_CMAKE_HOST_WIN32))
if(CLR_CMAKE_HOST_ARCH_ARM64 OR CLR_CMAKE_HOST_ARCH_AMD64 OR CLR_CMAKE_HOST_ARCH_ARM OR CLR_CMAKE_HOST_ARCH_LOONGARCH64 OR (CLR_CMAKE_HOST_ARCH_I386 AND CLR_CMAKE_HOST_WIN32))
add_subdirectory(nativeaot)
endif()
endif(NOT CLR_CROSS_COMPONENTS_BUILD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
#define ENREGISTERED_PARAMTYPE_MAXSIZE
#elif TARGET_WASM
#elif TARGET_LOONGARCH64
#define CALLDESCR_ARGREGS // CallDescrWorker has ArgumentRegister parameter
#define CALLDESCR_FPARGREGS // CallDescrWorker has FloatArgumentRegisters parameter
#define ENREGISTERED_RETURNTYPE_MAXSIZE
#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
#define ENREGISTERED_PARAMTYPE_MAXSIZE
#else
#error Unknown architecture!
#endif
Expand Down Expand Up @@ -300,6 +306,60 @@ internal struct ArchitectureConstants
public const int STACK_ELEM_SIZE = 4;
public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
}
#elif TARGET_LOONGARCH64
[StructLayout(LayoutKind.Sequential)]
internal struct ReturnBlock
{
private IntPtr returnValue;
private IntPtr returnValue2;
private IntPtr returnValue3;
private IntPtr returnValue4;
}

[StructLayout(LayoutKind.Sequential)]
internal struct ArgumentRegisters
{
private IntPtr r4;
private IntPtr r5;
private IntPtr r6;
private IntPtr r7;
private IntPtr r8;
private IntPtr r9;
private IntPtr r10;
private IntPtr r11;
public static unsafe int GetOffsetOfr11()
{
return sizeof(IntPtr) * 7;
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct FloatArgumentRegisters
{
private double f0;
private double f1;
private double f2;
private double f3;
private double f4;
private double f5;
private double f6;
private double f7;
}

internal struct ArchitectureConstants
{
// To avoid corner case bugs, limit maximum size of the arguments with sufficient margin
public const int MAX_ARG_SIZE = 0xFFFFFF;

public const int NUM_ARGUMENT_REGISTERS = 8;
public const int ARGUMENTREGISTERS_SIZE = NUM_ARGUMENT_REGISTERS * 8;
public const int ENREGISTERED_RETURNTYPE_MAXSIZE = 32; // bytes (four FP registers: d0,d1,d2 and d3)
public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 16; // bytes (two int registers: x0 and x1)
public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE_PRIMITIVE = 8;
public const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16; // bytes (max value type size that can be passed by value)
public const int STACK_ELEM_SIZE = 8;
public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
}
#endif

//
Expand Down Expand Up @@ -392,6 +452,20 @@ public static unsafe int GetOffsetOfArgumentRegisters()
{
return sizeof(ReturnBlock);
}
#elif TARGET_LOONGARCH64
public ReturnBlock m_returnBlock;
public static unsafe int GetOffsetOfReturnValuesBlock()
{
return 0;
}

public ArgumentRegisters m_argumentRegisters;
public static unsafe int GetOffsetOfArgumentRegisters()
{
return sizeof(ReturnBlock);
}

public IntPtr m_alignmentPad;
#else
#error Portability problem
#endif
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/nativeaot/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@
<PropertyGroup Condition="'$(Platform)' == 'arm64'">
<DefineConstants>TARGET_64BIT;TARGET_ARM64;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' == 'loongarch64'">
<DefineConstants>TARGET_64BIT;TARGET_LOONGARCH64;$(DefineConstants)</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<DefineConstants Condition="'$(TargetsWindows)'=='true'">TARGET_WINDOWS;$(DefineConstants)</DefineConstants>
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/nativeaot/Runtime/CommonMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ inline bool IS_ALIGNED(T* val, uintptr_t alignment);
#define LOG2_PTRSIZE 2
#define POINTER_SIZE 4

#elif defined(HOST_LOONGARCH64)

#define LOG2_PTRSIZE 3
#define POINTER_SIZE 8

#else
#error Unsupported target architecture
#endif
Expand Down
71 changes: 20 additions & 51 deletions src/coreclr/nativeaot/Runtime/EHHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,22 @@ FCIMPL3(void, RhpCopyContextFromExInfo, void * pOSContext, int32_t cbOSContext,
pContext->Sp = pPalContext->SP;
pContext->Lr = pPalContext->LR;
pContext->Pc = pPalContext->IP;
#elif defined(HOST_LOONGARCH64)
pContext->R4 = pPalContext->R4;
pContext->R5 = pPalContext->R5;
pContext->R23 = pPalContext->R23;
pContext->R24 = pPalContext->R24;
pContext->R25 = pPalContext->R25;
pContext->R26 = pPalContext->R26;
pContext->R27 = pPalContext->R27;
pContext->R28 = pPalContext->R28;
pContext->R29 = pPalContext->R29;
pContext->R30 = pPalContext->R30;
pContext->R31 = pPalContext->R31;
pContext->Fp = pPalContext->FP;
pContext->Sp = pPalContext->SP;
pContext->Ra = pPalContext->RA;
pContext->Pc = pPalContext->IP;
#elif defined(HOST_WASM)
// No registers, no work to do yet
#else
Expand All @@ -195,7 +211,6 @@ FCIMPL3(void, RhpCopyContextFromExInfo, void * pOSContext, int32_t cbOSContext,
}
FCIMPLEND

#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64)
struct DISPATCHER_CONTEXT
{
uintptr_t ControlPc;
Expand Down Expand Up @@ -257,56 +272,8 @@ EXTERN_C int32_t __stdcall RhpPInvokeExceptionGuard(PEXCEPTION_RECORD pExc

return 0;
}
#else
EXTERN_C int32_t RhpPInvokeExceptionGuard()
{
ASSERT_UNCONDITIONALLY("RhpPInvokeExceptionGuard NYI for this architecture!");
RhFailFast();
return 0;
}
#endif

#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64) || defined(HOST_WASM)
FCDECL2(void, RhpThrowHwEx, int exceptionCode, TADDR faultingIP);
#else
FCIMPL0(void, RhpThrowHwEx)
{
ASSERT_UNCONDITIONALLY("RhpThrowHwEx NYI for this architecture!");
}
FCIMPLEND
FCIMPL0(void, RhpThrowEx)
{
ASSERT_UNCONDITIONALLY("RhpThrowEx NYI for this architecture!");
}
FCIMPLEND
FCIMPL0(void, RhpCallCatchFunclet)
{
ASSERT_UNCONDITIONALLY("RhpCallCatchFunclet NYI for this architecture!");
}
FCIMPLEND
FCIMPL0(void, RhpCallFinallyFunclet)
{
ASSERT_UNCONDITIONALLY("RhpCallFinallyFunclet NYI for this architecture!");
}
FCIMPLEND
FCIMPL0(void, RhpCallFilterFunclet)
{
ASSERT_UNCONDITIONALLY("RhpCallFilterFunclet NYI for this architecture!");
}
FCIMPLEND
FCIMPL0(void, RhpRethrow)
{
ASSERT_UNCONDITIONALLY("RhpRethrow NYI for this architecture!");
}
FCIMPLEND

EXTERN_C void* RhpCallCatchFunclet2 = NULL;
EXTERN_C void* RhpCallFinallyFunclet2 = NULL;
EXTERN_C void* RhpCallFilterFunclet2 = NULL;
EXTERN_C void* RhpThrowEx2 = NULL;
EXTERN_C void* RhpThrowHwEx2 = NULL;
EXTERN_C void* RhpRethrow2 = NULL;
#endif

EXTERN_C CODE_LOCATION RhpAssignRefAVLocation;
#if defined(HOST_X86)
Expand All @@ -328,7 +295,7 @@ EXTERN_C CODE_LOCATION RhpCheckedAssignRefEBPAVLocation;
#endif
EXTERN_C CODE_LOCATION RhpByRefAssignRefAVLocation1;

#if !defined(HOST_ARM64)
#if !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64)
EXTERN_C CODE_LOCATION RhpByRefAssignRefAVLocation2;
#endif

Expand Down Expand Up @@ -361,7 +328,7 @@ static bool InWriteBarrierHelper(uintptr_t faultingIP)
(uintptr_t)&RhpCheckedAssignRefEBPAVLocation,
#endif
(uintptr_t)&RhpByRefAssignRefAVLocation1,
#if !defined(HOST_ARM64)
#if !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64)
(uintptr_t)&RhpByRefAssignRefAVLocation2,
#endif
};
Expand Down Expand Up @@ -443,6 +410,8 @@ static uintptr_t UnwindSimpleHelperToCaller(
pContext->SetSp(sp+sizeof(uintptr_t)); // pop the stack
#elif defined(HOST_ARM) || defined(HOST_ARM64)
uintptr_t adjustedFaultingIP = pContext->GetLr();
#elif defined(HOST_LOONGARCH64)
uintptr_t adjustedFaultingIP = pContext->GetRa();
#else
uintptr_t adjustedFaultingIP = 0; // initializing to make the compiler happy
PORTABILITY_ASSERT("UnwindSimpleHelperToCaller");
Expand Down
21 changes: 21 additions & 0 deletions src/coreclr/nativeaot/Runtime/ICodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,27 @@ inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
return returnKind;
}

#elif defined(TARGET_LOONGARCH64)
// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
C_ASSERT(PTFF_R4_IS_GCREF == ((uint64_t)GCRK_Object << 32));
C_ASSERT(PTFF_R4_IS_BYREF == ((uint64_t)GCRK_Byref << 32));
C_ASSERT(PTFF_R5_IS_GCREF == ((uint64_t)GCRK_Scalar_Obj << 32));
C_ASSERT(PTFF_R5_IS_BYREF == ((uint64_t)GCRK_Scalar_Byref << 32));

inline uint64_t ReturnKindToTransitionFrameFlags(GCRefKind returnKind)
{
// just need to report gc ref bits here.
// appropriate PTFF_SAVE_ bits will be added by the frame building routine.
return ((uint64_t)returnKind << 32);
}

inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
{
GCRefKind returnKind = (GCRefKind)((transFrameFlags & (PTFF_R4_IS_GCREF | PTFF_R4_IS_BYREF | PTFF_R5_IS_GCREF | PTFF_R5_IS_BYREF)) >> 32);
ASSERT((returnKind == GCRK_Scalar) || ((transFrameFlags & PTFF_SAVE_R4) && (transFrameFlags & PTFF_SAVE_R5)));
return returnKind;
}

#elif defined(TARGET_AMD64)

// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
Expand Down
35 changes: 35 additions & 0 deletions src/coreclr/nativeaot/Runtime/MiscHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,41 @@ FCIMPL1(uint8_t *, RhGetCodeTarget, uint8_t * pCodeOrg)
int64_t distToTarget = ((int64_t)pCode[0] << 38) >> 36;
return (uint8_t *)pCode + distToTarget;
}
#elif TARGET_LOONGARCH64
uint32_t * pCode = (uint32_t *)pCodeOrg;
// is this "addi.d $a0, $a0, 8"?
if (pCode[0] == 0x02c02084)
{
// unboxing sequence
unboxingStub = true;
pCode++;
}
// is this an indirect jump?
// pcalau12i $t7, imm20; ld.d $t7, $t7, imm12; jirl $r0, $t7, 0
if ((pCode[0] & 0xfe000000) == 0x1a000000 &&
(pCode[1] & 0xffc00000) == 0x28c00000 &&
(pCode[2] & 0xfc000000) == 0x4c000000)
{
// normal import stub - dist to IAT cell is relative to (PC & ~0xfff)
// pcalau12i: imm = SignExtend(imm20:Zeros(12), 64);
int64_t distToIatCell = ((((int64_t)pCode[0] & ~0x1f) << 39) >> 32);
// ld.d: offset = SignExtend(imm12, 64);
distToIatCell += (((int64_t)pCode[1] << 42) >> 52);
uint8_t ** pIatCell = (uint8_t **)(((int64_t)pCode & ~0xfff) + distToIatCell);
return *pIatCell;
}
// is this an unboxing stub followed by a relative jump?
// pcaddu18i $r21, imm20; jirl $r0, $r21, imm16
else if (unboxingStub &&
(pCode[0] & 0xfe00001f) == 0x1e000015 &&
(pCode[1] & 0xfc0003ff) == 0x4c0002a0)
{
// relative jump - dist is relative to the instruction
// offset = SignExtend(immhi20:immlo16:'00', 64);
int64_t distToTarget = ((((int64_t)pCode[0] & ~0x1f) << 39) >> 26);
distToTarget += ((((int64_t)pCode[1] & ~0x3ff) << 38) >> 46);
return (uint8_t *)((int64_t)pCode + distToTarget);
}
#else
UNREFERENCED_PARAMETER(unboxingStub);
PORTABILITY_ASSERT("RhGetCodeTarget");
Expand Down
Loading

0 comments on commit aee78d3

Please sign in to comment.