Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LoongArch64] Add nativeaot support on LoongArch64. #103889

Merged
merged 11 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading