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

Add linux-riscv64 nativeaot runtime build #110688

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 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 src/coreclr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,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_LOONGARCH64 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_RISCV64 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,7 +35,7 @@
#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
#define ENREGISTERED_PARAMTYPE_MAXSIZE
#elif TARGET_WASM
#elif TARGET_LOONGARCH64
#elif TARGET_LOONGARCH64 || TARGET_RISCV64
#define CALLDESCR_ARGREGS // CallDescrWorker has ArgumentRegister parameter
#define CALLDESCR_FPARGREGS // CallDescrWorker has FloatArgumentRegisters parameter
#define ENREGISTERED_RETURNTYPE_MAXSIZE
Expand Down Expand Up @@ -360,6 +360,60 @@ internal struct ArchitectureConstants
public const int STACK_ELEM_SIZE = 8;
public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
}
#elif TARGET_RISCV64
[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 a0;
private IntPtr a1;
private IntPtr a2;
private IntPtr a3;
private IntPtr a4;
private IntPtr a5;
private IntPtr a6;
private IntPtr a7;
public static unsafe int GetOffsetOfa7()
{
return sizeof(IntPtr) * 7;
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct FloatArgumentRegisters
{
private double fa0;
private double fa1;
private double fa2;
private double fa3;
private double fa4;
private double fa5;
private double fa6;
private double fa7;
}

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: fa0, fa1, fa2, and fa3)
public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 16; // bytes (two int registers: a0 and a1)
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 @@ -465,6 +519,20 @@ public static unsafe int GetOffsetOfArgumentRegisters()
return sizeof(ReturnBlock);
}

public IntPtr m_alignmentPad;
#elif TARGET_RISCV64
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
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 @@ -92,6 +92,9 @@
<PropertyGroup Condition="'$(Platform)' == 'loongarch64'">
<DefineConstants>TARGET_64BIT;TARGET_LOONGARCH64;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' == 'riscv64'">
<DefineConstants>TARGET_64BIT;TARGET_RISCV64;$(DefineConstants)</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<DefineConstants Condition="'$(TargetsWindows)'=='true'">TARGET_WINDOWS;$(DefineConstants)</DefineConstants>
Expand Down
7 changes: 5 additions & 2 deletions src/coreclr/nativeaot/Runtime/AsmOffsetsVerify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ class AsmOffsets
static_assert(offsetof(Array, m_Length) == offsetof(String, m_Length), "The length field of String and Array have different offsets");
static_assert(sizeof(((Array*)0)->m_Length) == sizeof(((String*)0)->m_Length), "The length field of String and Array have different sizes");

#define TO_STRING(x) #x
#define OFFSET_STRING(cls, member) TO_STRING(offsetof(cls, member))

// Macro definition
#define PLAT_ASM_OFFSET(offset, cls, member) \
static_assert((offsetof(cls, member) == 0x##offset) || (offsetof(cls, member) > 0x##offset), "Bad asm offset for '" #cls "." #member "', the actual offset is smaller than 0x" #offset "."); \
static_assert((offsetof(cls, member) == 0x##offset) || (offsetof(cls, member) < 0x##offset), "Bad asm offset for '" #cls "." #member "', the actual offset is larger than 0x" #offset ".");
static_assert(offsetof(cls, member) == 0x##offset, "Bad asm offset for '" #cls "." #member "'. Actual offset: " OFFSET_STRING(cls, member));

#define PLAT_ASM_SIZEOF(size, cls ) \
static_assert((sizeof(cls) == 0x##size) || (sizeof(cls) > 0x##size), "Bad asm size for '" #cls "', the actual size is smaller than 0x" #size "."); \
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/nativeaot/Runtime/CommonMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ inline bool IS_ALIGNED(T* val, uintptr_t alignment);
#define LOG2_PTRSIZE 2
#define POINTER_SIZE 4

#elif defined(HOST_LOONGARCH64)
#elif defined(HOST_LOONGARCH64) || defined (HOST_RISCV64)

#define LOG2_PTRSIZE 3
#define POINTER_SIZE 8
Expand Down
24 changes: 21 additions & 3 deletions src/coreclr/nativeaot/Runtime/EHHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,24 @@ FCIMPL3(void, RhpCopyContextFromExInfo, void * pOSContext, int32_t cbOSContext,
pContext->Sp = pPalContext->SP;
pContext->Ra = pPalContext->RA;
pContext->Pc = pPalContext->IP;
#elif defined(HOST_RISCV64)
pContext->A0 = pPalContext->A0;
pContext->A1 = pPalContext->A1;
pContext->S1 = pPalContext->S1;
pContext->S2 = pPalContext->S2;
pContext->S3 = pPalContext->S3;
pContext->S4 = pPalContext->S4;
pContext->S5 = pPalContext->S5;
pContext->S6 = pPalContext->S6;
pContext->S7 = pPalContext->S7;
pContext->S8 = pPalContext->S8;
pContext->S9 = pPalContext->S9;
pContext->S10 = pPalContext->S10;
pContext->S11 = pPalContext->S11;
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 Down Expand Up @@ -295,7 +313,7 @@ EXTERN_C CODE_LOCATION RhpCheckedAssignRefEBPAVLocation;
#endif
EXTERN_C CODE_LOCATION RhpByRefAssignRefAVLocation1;

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

Expand Down Expand Up @@ -328,7 +346,7 @@ static bool InWriteBarrierHelper(uintptr_t faultingIP)
(uintptr_t)&RhpCheckedAssignRefEBPAVLocation,
#endif
(uintptr_t)&RhpByRefAssignRefAVLocation1,
#if !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64)
#if !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64) && !defined(HOST_RISCV64)
(uintptr_t)&RhpByRefAssignRefAVLocation2,
#endif
};
Expand Down Expand Up @@ -410,7 +428,7 @@ 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)
#elif defined(HOST_LOONGARCH64) || defined(HOST_RISCV64)
uintptr_t adjustedFaultingIP = pContext->GetRa();
#else
uintptr_t adjustedFaultingIP = 0; // initializing to make the compiler happy
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 @@ -86,6 +86,27 @@ inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
return returnKind;
}

#elif defined(TARGET_RISCV64)
// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
C_ASSERT(PTFF_A0_IS_GCREF == ((uint64_t)GCRK_Object << 31));
C_ASSERT(PTFF_A0_IS_BYREF == ((uint64_t)GCRK_Byref << 31));
C_ASSERT(PTFF_A1_IS_GCREF == ((uint64_t)GCRK_Scalar_Obj << 31));
C_ASSERT(PTFF_A1_IS_BYREF == ((uint64_t)GCRK_Scalar_Byref << 31));

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 << 31);
}

inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
{
GCRefKind returnKind = (GCRefKind)((transFrameFlags & ( PTFF_A0_IS_GCREF | PTFF_A0_IS_BYREF | PTFF_A1_IS_GCREF | PTFF_A1_IS_BYREF)) >> 31);
ASSERT((returnKind == GCRK_Scalar) || ((transFrameFlags & PTFF_SAVE_A0) && (transFrameFlags & PTFF_SAVE_A1)));
return returnKind;
}

#elif defined(TARGET_AMD64)

// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
Expand Down
41 changes: 41 additions & 0 deletions src/coreclr/nativeaot/Runtime/MiscHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ 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"?
Expand Down Expand Up @@ -370,6 +371,46 @@ FCIMPL1(uint8_t *, RhGetCodeTarget, uint8_t * pCodeOrg)
distToTarget += ((((int64_t)pCode[1] & ~0x3ff) << 38) >> 46);
return (uint8_t *)((int64_t)pCode + distToTarget);
}

#elif TARGET_RISCV64
uint32_t * pCode = (uint32_t *)pCodeOrg;
// is this "addi a0, a0, 8"?
am11 marked this conversation as resolved.
Show resolved Hide resolved
if (pCode[0] == 0x00850513) // Encoding for `addi a0, a0, 8` in 32-bit instruction format
{
// unboxing sequence
unboxingStub = true;
pCode++;
}
// is this an indirect jump?
// lui t0, imm; jalr t0, t0, imm12
if ((pCode[0] & 0x7f) == 0x17 && // auipc
(pCode[1] & 0x707f) == 0x3003 && // ld with funct3=011
(pCode[2] & 0x707f) == 0x0067) // jr (jalr with x0 as rd and funct3=000)
{
// Compute the distance to the IAT cell
int64_t distToIatCell = (((int32_t)pCode[0]) >> 12) << 12; // Extract imm20 from auipc
distToIatCell += ((int32_t)pCode[1]) >> 20; // Add imm12 from ld

uint8_t ** pIatCell = (uint8_t **)(((int64_t)pCode & ~0xfff) + distToIatCell);
return *pIatCell;
}

// Is this an unboxing stub followed by a relative jump?
// auipc t0, imm20; jalr ra, imm12(t0)
else if (unboxingStub &&
(pCode[0] & 0x7f) == 0x17 && // auipc opcode
(pCode[1] & 0x707f) == 0x0067) // jalr opcode with funct3=000
{
// Extract imm20 from auipc
int64_t distToTarget = (((int32_t)pCode[0]) >> 12) << 12; // Extract imm20 (bits 31:12)

// Extract imm12 from jalr
distToTarget += ((int32_t)pCode[1]) >> 20; // Extract imm12 (bits 31:20)

// Calculate the final target address relative to PC
return (uint8_t *)((int64_t)pCode + distToTarget);
}

#else
UNREFERENCED_PARAMETER(unboxingStub);
PORTABILITY_ASSERT("RhGetCodeTarget");
Expand Down
77 changes: 77 additions & 0 deletions src/coreclr/nativeaot/Runtime/PalRedhawk.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,83 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
}
} CONTEXT, *PCONTEXT;

#elif defined(TARGET_RISCV64)

#define CONTEXT_RISCV64 0x01000000L

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

#define RISCV64_MAX_BREAKPOINTS 8
#define RISCV64_MAX_WATCHPOINTS 2

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

//
// Integer registers
//
uint64_t X0;
uint64_t Ra;
uint64_t Sp;
uint64_t Gp;
uint64_t Tp;
uint64_t T0;
uint64_t T1;
uint64_t T2;
uint64_t Fp;
uint64_t S1;
uint64_t A0;
uint64_t A1;
uint64_t A2;
uint64_t A3;
uint64_t A4;
uint64_t A5;
uint64_t A6;
uint64_t A7;
uint64_t S2;
uint64_t S3;
uint64_t S4;
uint64_t S5;
uint64_t S6;
uint64_t S7;
uint64_t S8;
uint64_t S9;
uint64_t S10;
uint64_t S11;
uint64_t T3;
uint64_t T4;
uint64_t T5;
uint64_t T6;
uint64_t Pc;

//
// Floating Point Registers
//
uint64_t F[32];
uint32_t Fcsr;

void SetIp(uintptr_t ip) { Pc = ip; }
void SetArg0Reg(uintptr_t val) { A0 = val; }
void SetArg1Reg(uintptr_t val) { A1 = 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 = &X0; pReg <= &T6; 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