Skip to content

Commit aee78d3

Browse files
sunlijun-610filipnavarajkotas
authored
[LoongArch64] Add nativeaot support on LoongArch64. (#103889)
* [LoongArch64] Add nativeaot support on LoongArch64. --------- Co-authored-by: Filip Navara <[email protected]> Co-authored-by: Jan Kotas <[email protected]>
1 parent 67e1983 commit aee78d3

26 files changed

+1359
-76
lines changed

eng/Subsets.props

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120
<PropertyGroup>
121121
<!-- CLR NativeAot only builds in a subset of the matrix -->
122122
<_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>
123-
<_NativeAotSupportedArch Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64' or '$(TargetArchitecture)' == 'arm' or ('$(TargetOS)' == 'windows' and '$(TargetArchitecture)' == 'x86')">true</_NativeAotSupportedArch>
123+
<_NativeAotSupportedArch Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64' or '$(TargetArchitecture)' == 'arm' or '$(TargetArchitecture)' == 'loongarch64' or ('$(TargetOS)' == 'windows' and '$(TargetArchitecture)' == 'x86')">true</_NativeAotSupportedArch>
124124
<NativeAotSupported Condition="'$(_NativeAotSupportedOS)' == 'true' and '$(_NativeAotSupportedArch)' == 'true'">true</NativeAotSupported>
125125
<UseNativeAotForComponents Condition="'$(NativeAotSupported)' == 'true' and '$(TargetOS)' == '$(HostOS)' and ('$(TargetOS)' != 'windows' or '$(TargetArchitecture)' != 'x86') and '$(TargetsLinuxBionic)' != 'true' and ('$(TargetsLinuxMusl)' != 'true' or '$(TargetArchitecture)' != 'arm')">true</UseNativeAotForComponents>
126126

src/coreclr/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ add_subdirectory(tools/aot/jitinterface)
150150

151151
if(NOT CLR_CROSS_COMPONENTS_BUILD)
152152
# NativeAOT only buildable for a subset of CoreCLR-supported configurations
153-
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))
153+
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))
154154
add_subdirectory(nativeaot)
155155
endif()
156156
endif(NOT CLR_CROSS_COMPONENTS_BUILD)

src/coreclr/nativeaot/Common/src/Internal/Runtime/TransitionBlock.cs

+74
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@
3535
#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
3636
#define ENREGISTERED_PARAMTYPE_MAXSIZE
3737
#elif TARGET_WASM
38+
#elif TARGET_LOONGARCH64
39+
#define CALLDESCR_ARGREGS // CallDescrWorker has ArgumentRegister parameter
40+
#define CALLDESCR_FPARGREGS // CallDescrWorker has FloatArgumentRegisters parameter
41+
#define ENREGISTERED_RETURNTYPE_MAXSIZE
42+
#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
43+
#define ENREGISTERED_PARAMTYPE_MAXSIZE
3844
#else
3945
#error Unknown architecture!
4046
#endif
@@ -300,6 +306,60 @@ internal struct ArchitectureConstants
300306
public const int STACK_ELEM_SIZE = 4;
301307
public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
302308
}
309+
#elif TARGET_LOONGARCH64
310+
[StructLayout(LayoutKind.Sequential)]
311+
internal struct ReturnBlock
312+
{
313+
private IntPtr returnValue;
314+
private IntPtr returnValue2;
315+
private IntPtr returnValue3;
316+
private IntPtr returnValue4;
317+
}
318+
319+
[StructLayout(LayoutKind.Sequential)]
320+
internal struct ArgumentRegisters
321+
{
322+
private IntPtr r4;
323+
private IntPtr r5;
324+
private IntPtr r6;
325+
private IntPtr r7;
326+
private IntPtr r8;
327+
private IntPtr r9;
328+
private IntPtr r10;
329+
private IntPtr r11;
330+
public static unsafe int GetOffsetOfr11()
331+
{
332+
return sizeof(IntPtr) * 7;
333+
}
334+
}
335+
336+
[StructLayout(LayoutKind.Sequential)]
337+
internal struct FloatArgumentRegisters
338+
{
339+
private double f0;
340+
private double f1;
341+
private double f2;
342+
private double f3;
343+
private double f4;
344+
private double f5;
345+
private double f6;
346+
private double f7;
347+
}
348+
349+
internal struct ArchitectureConstants
350+
{
351+
// To avoid corner case bugs, limit maximum size of the arguments with sufficient margin
352+
public const int MAX_ARG_SIZE = 0xFFFFFF;
353+
354+
public const int NUM_ARGUMENT_REGISTERS = 8;
355+
public const int ARGUMENTREGISTERS_SIZE = NUM_ARGUMENT_REGISTERS * 8;
356+
public const int ENREGISTERED_RETURNTYPE_MAXSIZE = 32; // bytes (four FP registers: d0,d1,d2 and d3)
357+
public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 16; // bytes (two int registers: x0 and x1)
358+
public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE_PRIMITIVE = 8;
359+
public const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16; // bytes (max value type size that can be passed by value)
360+
public const int STACK_ELEM_SIZE = 8;
361+
public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
362+
}
303363
#endif
304364

305365
//
@@ -392,6 +452,20 @@ public static unsafe int GetOffsetOfArgumentRegisters()
392452
{
393453
return sizeof(ReturnBlock);
394454
}
455+
#elif TARGET_LOONGARCH64
456+
public ReturnBlock m_returnBlock;
457+
public static unsafe int GetOffsetOfReturnValuesBlock()
458+
{
459+
return 0;
460+
}
461+
462+
public ArgumentRegisters m_argumentRegisters;
463+
public static unsafe int GetOffsetOfArgumentRegisters()
464+
{
465+
return sizeof(ReturnBlock);
466+
}
467+
468+
public IntPtr m_alignmentPad;
395469
#else
396470
#error Portability problem
397471
#endif

src/coreclr/nativeaot/Directory.Build.props

+3
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@
8989
<PropertyGroup Condition="'$(Platform)' == 'arm64'">
9090
<DefineConstants>TARGET_64BIT;TARGET_ARM64;$(DefineConstants)</DefineConstants>
9191
</PropertyGroup>
92+
<PropertyGroup Condition="'$(Platform)' == 'loongarch64'">
93+
<DefineConstants>TARGET_64BIT;TARGET_LOONGARCH64;$(DefineConstants)</DefineConstants>
94+
</PropertyGroup>
9295

9396
<PropertyGroup>
9497
<DefineConstants Condition="'$(TargetsWindows)'=='true'">TARGET_WINDOWS;$(DefineConstants)</DefineConstants>

src/coreclr/nativeaot/Runtime/CommonMacros.h

+5
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ inline bool IS_ALIGNED(T* val, uintptr_t alignment);
119119
#define LOG2_PTRSIZE 2
120120
#define POINTER_SIZE 4
121121

122+
#elif defined(HOST_LOONGARCH64)
123+
124+
#define LOG2_PTRSIZE 3
125+
#define POINTER_SIZE 8
126+
122127
#else
123128
#error Unsupported target architecture
124129
#endif

src/coreclr/nativeaot/Runtime/EHHelpers.cpp

+20-51
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,22 @@ FCIMPL3(void, RhpCopyContextFromExInfo, void * pOSContext, int32_t cbOSContext,
187187
pContext->Sp = pPalContext->SP;
188188
pContext->Lr = pPalContext->LR;
189189
pContext->Pc = pPalContext->IP;
190+
#elif defined(HOST_LOONGARCH64)
191+
pContext->R4 = pPalContext->R4;
192+
pContext->R5 = pPalContext->R5;
193+
pContext->R23 = pPalContext->R23;
194+
pContext->R24 = pPalContext->R24;
195+
pContext->R25 = pPalContext->R25;
196+
pContext->R26 = pPalContext->R26;
197+
pContext->R27 = pPalContext->R27;
198+
pContext->R28 = pPalContext->R28;
199+
pContext->R29 = pPalContext->R29;
200+
pContext->R30 = pPalContext->R30;
201+
pContext->R31 = pPalContext->R31;
202+
pContext->Fp = pPalContext->FP;
203+
pContext->Sp = pPalContext->SP;
204+
pContext->Ra = pPalContext->RA;
205+
pContext->Pc = pPalContext->IP;
190206
#elif defined(HOST_WASM)
191207
// No registers, no work to do yet
192208
#else
@@ -195,7 +211,6 @@ FCIMPL3(void, RhpCopyContextFromExInfo, void * pOSContext, int32_t cbOSContext,
195211
}
196212
FCIMPLEND
197213

198-
#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64)
199214
struct DISPATCHER_CONTEXT
200215
{
201216
uintptr_t ControlPc;
@@ -257,56 +272,8 @@ EXTERN_C int32_t __stdcall RhpPInvokeExceptionGuard(PEXCEPTION_RECORD pExc
257272

258273
return 0;
259274
}
260-
#else
261-
EXTERN_C int32_t RhpPInvokeExceptionGuard()
262-
{
263-
ASSERT_UNCONDITIONALLY("RhpPInvokeExceptionGuard NYI for this architecture!");
264-
RhFailFast();
265-
return 0;
266-
}
267-
#endif
268275

269-
#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64) || defined(HOST_WASM)
270276
FCDECL2(void, RhpThrowHwEx, int exceptionCode, TADDR faultingIP);
271-
#else
272-
FCIMPL0(void, RhpThrowHwEx)
273-
{
274-
ASSERT_UNCONDITIONALLY("RhpThrowHwEx NYI for this architecture!");
275-
}
276-
FCIMPLEND
277-
FCIMPL0(void, RhpThrowEx)
278-
{
279-
ASSERT_UNCONDITIONALLY("RhpThrowEx NYI for this architecture!");
280-
}
281-
FCIMPLEND
282-
FCIMPL0(void, RhpCallCatchFunclet)
283-
{
284-
ASSERT_UNCONDITIONALLY("RhpCallCatchFunclet NYI for this architecture!");
285-
}
286-
FCIMPLEND
287-
FCIMPL0(void, RhpCallFinallyFunclet)
288-
{
289-
ASSERT_UNCONDITIONALLY("RhpCallFinallyFunclet NYI for this architecture!");
290-
}
291-
FCIMPLEND
292-
FCIMPL0(void, RhpCallFilterFunclet)
293-
{
294-
ASSERT_UNCONDITIONALLY("RhpCallFilterFunclet NYI for this architecture!");
295-
}
296-
FCIMPLEND
297-
FCIMPL0(void, RhpRethrow)
298-
{
299-
ASSERT_UNCONDITIONALLY("RhpRethrow NYI for this architecture!");
300-
}
301-
FCIMPLEND
302-
303-
EXTERN_C void* RhpCallCatchFunclet2 = NULL;
304-
EXTERN_C void* RhpCallFinallyFunclet2 = NULL;
305-
EXTERN_C void* RhpCallFilterFunclet2 = NULL;
306-
EXTERN_C void* RhpThrowEx2 = NULL;
307-
EXTERN_C void* RhpThrowHwEx2 = NULL;
308-
EXTERN_C void* RhpRethrow2 = NULL;
309-
#endif
310277

311278
EXTERN_C CODE_LOCATION RhpAssignRefAVLocation;
312279
#if defined(HOST_X86)
@@ -328,7 +295,7 @@ EXTERN_C CODE_LOCATION RhpCheckedAssignRefEBPAVLocation;
328295
#endif
329296
EXTERN_C CODE_LOCATION RhpByRefAssignRefAVLocation1;
330297

331-
#if !defined(HOST_ARM64)
298+
#if !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64)
332299
EXTERN_C CODE_LOCATION RhpByRefAssignRefAVLocation2;
333300
#endif
334301

@@ -361,7 +328,7 @@ static bool InWriteBarrierHelper(uintptr_t faultingIP)
361328
(uintptr_t)&RhpCheckedAssignRefEBPAVLocation,
362329
#endif
363330
(uintptr_t)&RhpByRefAssignRefAVLocation1,
364-
#if !defined(HOST_ARM64)
331+
#if !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64)
365332
(uintptr_t)&RhpByRefAssignRefAVLocation2,
366333
#endif
367334
};
@@ -443,6 +410,8 @@ static uintptr_t UnwindSimpleHelperToCaller(
443410
pContext->SetSp(sp+sizeof(uintptr_t)); // pop the stack
444411
#elif defined(HOST_ARM) || defined(HOST_ARM64)
445412
uintptr_t adjustedFaultingIP = pContext->GetLr();
413+
#elif defined(HOST_LOONGARCH64)
414+
uintptr_t adjustedFaultingIP = pContext->GetRa();
446415
#else
447416
uintptr_t adjustedFaultingIP = 0; // initializing to make the compiler happy
448417
PORTABILITY_ASSERT("UnwindSimpleHelperToCaller");

src/coreclr/nativeaot/Runtime/ICodeManager.h

+21
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
6565
return returnKind;
6666
}
6767

68+
#elif defined(TARGET_LOONGARCH64)
69+
// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
70+
C_ASSERT(PTFF_R4_IS_GCREF == ((uint64_t)GCRK_Object << 32));
71+
C_ASSERT(PTFF_R4_IS_BYREF == ((uint64_t)GCRK_Byref << 32));
72+
C_ASSERT(PTFF_R5_IS_GCREF == ((uint64_t)GCRK_Scalar_Obj << 32));
73+
C_ASSERT(PTFF_R5_IS_BYREF == ((uint64_t)GCRK_Scalar_Byref << 32));
74+
75+
inline uint64_t ReturnKindToTransitionFrameFlags(GCRefKind returnKind)
76+
{
77+
// just need to report gc ref bits here.
78+
// appropriate PTFF_SAVE_ bits will be added by the frame building routine.
79+
return ((uint64_t)returnKind << 32);
80+
}
81+
82+
inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
83+
{
84+
GCRefKind returnKind = (GCRefKind)((transFrameFlags & (PTFF_R4_IS_GCREF | PTFF_R4_IS_BYREF | PTFF_R5_IS_GCREF | PTFF_R5_IS_BYREF)) >> 32);
85+
ASSERT((returnKind == GCRK_Scalar) || ((transFrameFlags & PTFF_SAVE_R4) && (transFrameFlags & PTFF_SAVE_R5)));
86+
return returnKind;
87+
}
88+
6889
#elif defined(TARGET_AMD64)
6990

7091
// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back

src/coreclr/nativeaot/Runtime/MiscHelpers.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,41 @@ FCIMPL1(uint8_t *, RhGetCodeTarget, uint8_t * pCodeOrg)
334334
int64_t distToTarget = ((int64_t)pCode[0] << 38) >> 36;
335335
return (uint8_t *)pCode + distToTarget;
336336
}
337+
#elif TARGET_LOONGARCH64
338+
uint32_t * pCode = (uint32_t *)pCodeOrg;
339+
// is this "addi.d $a0, $a0, 8"?
340+
if (pCode[0] == 0x02c02084)
341+
{
342+
// unboxing sequence
343+
unboxingStub = true;
344+
pCode++;
345+
}
346+
// is this an indirect jump?
347+
// pcalau12i $t7, imm20; ld.d $t7, $t7, imm12; jirl $r0, $t7, 0
348+
if ((pCode[0] & 0xfe000000) == 0x1a000000 &&
349+
(pCode[1] & 0xffc00000) == 0x28c00000 &&
350+
(pCode[2] & 0xfc000000) == 0x4c000000)
351+
{
352+
// normal import stub - dist to IAT cell is relative to (PC & ~0xfff)
353+
// pcalau12i: imm = SignExtend(imm20:Zeros(12), 64);
354+
int64_t distToIatCell = ((((int64_t)pCode[0] & ~0x1f) << 39) >> 32);
355+
// ld.d: offset = SignExtend(imm12, 64);
356+
distToIatCell += (((int64_t)pCode[1] << 42) >> 52);
357+
uint8_t ** pIatCell = (uint8_t **)(((int64_t)pCode & ~0xfff) + distToIatCell);
358+
return *pIatCell;
359+
}
360+
// is this an unboxing stub followed by a relative jump?
361+
// pcaddu18i $r21, imm20; jirl $r0, $r21, imm16
362+
else if (unboxingStub &&
363+
(pCode[0] & 0xfe00001f) == 0x1e000015 &&
364+
(pCode[1] & 0xfc0003ff) == 0x4c0002a0)
365+
{
366+
// relative jump - dist is relative to the instruction
367+
// offset = SignExtend(immhi20:immlo16:'00', 64);
368+
int64_t distToTarget = ((((int64_t)pCode[0] & ~0x1f) << 39) >> 26);
369+
distToTarget += ((((int64_t)pCode[1] & ~0x3ff) << 38) >> 46);
370+
return (uint8_t *)((int64_t)pCode + distToTarget);
371+
}
337372
#else
338373
UNREFERENCED_PARAMETER(unboxingStub);
339374
PORTABILITY_ASSERT("RhGetCodeTarget");

0 commit comments

Comments
 (0)