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 3 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
26 changes: 22 additions & 4 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,7 @@ FCIMPL3(void, RhpCopyContextFromExInfo, void * pOSContext, int32_t cbOSContext,
}
FCIMPLEND

#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64)
#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64) || defined(HOST_LOONGARCH64)
sunlijun-610 marked this conversation as resolved.
Show resolved Hide resolved
struct DISPATCHER_CONTEXT
{
uintptr_t ControlPc;
Expand Down Expand Up @@ -266,7 +282,7 @@ EXTERN_C int32_t RhpPInvokeExceptionGuard()
}
#endif

#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64) || defined(HOST_WASM)
#if defined(HOST_AMD64) || defined(HOST_ARM) || defined(HOST_X86) || defined(HOST_ARM64) || defined(HOST_WASM) || defined(HOST_LOONGARCH64)
sunlijun-610 marked this conversation as resolved.
Show resolved Hide resolved
FCDECL2(void, RhpThrowHwEx, int exceptionCode, TADDR faultingIP);
#else
FCIMPL0(void, RhpThrowHwEx)
Expand Down Expand Up @@ -328,7 +344,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 +377,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 +459,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?
// pcalau12i $r21, imm20; jirl $r0, $r21, imm16
else if (unboxingStub &&
(pCode[0] & 0xfe00001f) == 0x1a000015 &&
(pCode[1] & 0xfc0003ff) == 0x4c0002a0)
{
// relative jump - dist is relative to the instruction
// offset = SignExtend(immhi10:immlo16:'00', 64);
int64_t distToTarget = ((((int64_t)pCode[0] & ~0x1f) << 39) >> 32);
distToTarget += ((((int64_t)pCode[1] & ~0x3ff) << 38) >> 46);
return (uint8_t *)(((int64_t)pCode & ~0xfff) + distToTarget);
}
#else
UNREFERENCED_PARAMETER(unboxingStub);
PORTABILITY_ASSERT("RhGetCodeTarget");
Expand Down
99 changes: 99 additions & 0 deletions src/coreclr/nativeaot/Runtime/PalRedhawk.h
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,105 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
}
} CONTEXT, *PCONTEXT;

#elif defined(HOST_LOONGARCH64)

#define CONTEXT_LOONGARCH64 0x00400000L

#define CONTEXT_CONTROL (CONTEXT_LOONGARCH64 | 0x1L)
#define CONTEXT_INTEGER (CONTEXT_LOONGARCH64 | 0x2L)

// Specify the number of breakpoints and watchpoints that the OS
// will track. Architecturally, LOONGARCH64 supports up to 16. In practice,
// however, almost no one implements more than 4 of each.

#define LOONGARCH64_MAX_BREAKPOINTS 8
#define LOONGARCH64_MAX_WATCHPOINTS 2

typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
//
// Control flags.
//
uint32_t ContextFlags;

//
// Integer registers
//
uint32_t Csr; // NZVF + DAIF + CurrentEL + SPSel
union {
struct {
uint64_t R0;
uint64_t R2;
uint64_t R4;
uint64_t R5;
uint64_t R6;
uint64_t R7;
uint64_t R8;
uint64_t R9;
uint64_t R10;
uint64_t R11;
uint64_t R12;
uint64_t R13;
uint64_t R14;
uint64_t R15;
uint64_t R16;
uint64_t R17;
uint64_t R18;
uint64_t R19;
uint64_t R20;
uint64_t R21;
uint64_t R23;
uint64_t R24;
uint64_t R25;
uint64_t R26;
uint64_t R27;
uint64_t R28;
uint64_t R29;
uint64_t R30;
uint64_t R31;
#pragma warning(push)
#pragma warning(disable:4201) // nameless struct
};
uint64_t R[29];
};
#pragma warning(pop)
uint64_t Fp; // R22
uint64_t Ra; // R1
uint64_t Sp; // R3
uint64_t Pc;

//
// Floating Point Registers
//
uint64_t F[32];
sunlijun-610 marked this conversation as resolved.
Show resolved Hide resolved
uint32_t Fpcr;
uint32_t Fpsr;

//
// Debug registers
//
uint32_t Bcr[LOONGARCH64_MAX_BREAKPOINTS];
uint64_t Bvr[LOONGARCH64_MAX_BREAKPOINTS];
uint32_t Wcr[LOONGARCH64_MAX_WATCHPOINTS];
uint64_t Wvr[LOONGARCH64_MAX_WATCHPOINTS];

void SetIp(uintptr_t ip) { Pc = ip; }
void SetArg0Reg(uintptr_t val) { R4 = val; }
void SetArg1Reg(uintptr_t val) { R5 = val; }
uintptr_t GetIp() { return Pc; }
uintptr_t GetRa() { return Ra; }
uintptr_t GetSp() { return Sp; }

template <typename F>
void ForEachPossibleObjectRef(F lambda)
{
for (uint64_t* pReg = &R0; pReg <= &R31; pReg++)
lambda((size_t*)pReg);

// Ra can be used as a scratch register
lambda((size_t*)&Ra);
}
} CONTEXT, *PCONTEXT;

#elif defined(HOST_WASM)

typedef struct DECLSPEC_ALIGN(8) _CONTEXT {
Expand Down
Loading
Loading