Skip to content

Commit

Permalink
Add linux-riscv64 nativeaot runtime build (dotnet#110688)
Browse files Browse the repository at this point in the history
* Fix registers/offsets in riscv-nativeaot.

* Fix *.S files in riscv-nativeaot.

* Fix riscv64 nativeaot native build

* Managed build fixes

* Apply suggestions from code review

Co-authored-by: Tymoteusz Wenerski <[email protected]>

* Apply suggestions from code review

Co-authored-by: Tomasz Sowiński <[email protected]>

* Update other macros in AsmOffsetsVerify

* Update src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs

Co-authored-by: Adeel Mujahid <[email protected]>

---------

Co-authored-by: sunlijun <[email protected]>
Co-authored-by: Tomek Sowiński <[email protected]>
Co-authored-by: Tymoteusz Wenerski <[email protected]>
Co-authored-by: Jan Kotas <[email protected]>
  • Loading branch information
5 people authored Jan 9, 2025
1 parent eb0490e commit 289aa17
Show file tree
Hide file tree
Showing 47 changed files with 3,882 additions and 39 deletions.
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 @@ -89,6 +89,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
15 changes: 8 additions & 7 deletions src/coreclr/nativeaot/Runtime/AsmOffsetsVerify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ 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 "."); \
static_assert((sizeof(cls) == 0x##size) || (sizeof(cls) < 0x##size), "Bad asm size for '" #cls "', the actual size is larger than 0x" #size ".");
#define PLAT_ASM_SIZEOF(size, cls) \
static_assert(sizeof(cls) == 0x##size, "Bad asm size for '" #cls "'. Actual size: " OFFSET_STRING(cls, 0x##size));

#define PLAT_ASM_CONST(constant, expr) \
static_assert(((expr) == 0x##constant) || ((expr) > 0x##constant), "Bad asm constant for '" #expr "', the actual value is smaller than 0x" #constant "."); \
static_assert(((expr) == 0x##constant) || ((expr) < 0x##constant), "Bad asm constant for '" #expr "', the actual value is larger than 0x" #constant ".");
static_assert((expr) == 0x##constant, "Bad asm constant for '" #expr "'. Actual value: " OFFSET_STRING(expr, 0x##constant));

#include "AsmOffsets.h"

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
40 changes: 40 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,45 @@ 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;
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
33 changes: 33 additions & 0 deletions src/coreclr/nativeaot/Runtime/PalRedhawkCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct PAL_LIMITED_CONTEXT
uintptr_t GetLr() const { return LR; }
void SetIp(uintptr_t ip) { IP = ip; }
void SetSp(uintptr_t sp) { SP = sp; }

#elif defined(TARGET_ARM64)
uintptr_t FP;
uintptr_t LR;
Expand Down Expand Up @@ -91,6 +92,7 @@ struct PAL_LIMITED_CONTEXT
uintptr_t GetLr() const { return LR; }
void SetIp(uintptr_t ip) { IP = ip; }
void SetSp(uintptr_t sp) { SP = sp; }

#elif defined(TARGET_LOONGARCH64)
uintptr_t FP;
uintptr_t RA;
Expand Down Expand Up @@ -121,6 +123,37 @@ struct PAL_LIMITED_CONTEXT
void SetIp(uintptr_t ip) { IP = ip; }
void SetSp(uintptr_t sp) { SP = sp; }

#elif defined(TARGET_RISCV64)

uintptr_t FP;
uintptr_t RA;

uintptr_t A0;
uintptr_t A1;
uintptr_t S1;
uintptr_t S2;
uintptr_t S3;
uintptr_t S4;
uintptr_t S5;
uintptr_t S6;
uintptr_t S7;
uintptr_t S8;
uintptr_t S9;
uintptr_t S10;
uintptr_t S11;

uintptr_t SP;
uintptr_t IP;

uint64_t F[12];

uintptr_t GetIp() const { return IP; }
uintptr_t GetSp() const { return SP; }
uintptr_t GetFp() const { return FP; }
uintptr_t GetRa() const { return RA; }
void SetIp(uintptr_t ip) { IP = ip; }
void SetSp(uintptr_t sp) { SP = sp; }

#elif defined(UNIX_AMD64_ABI)
// Param regs: rdi, rsi, rdx, rcx, r8, r9, scratch: rax, rdx (both return val), preserved: rbp, rbx, r12-r15
uintptr_t IP;
Expand Down
Loading

0 comments on commit 289aa17

Please sign in to comment.