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

Merged
merged 24 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3fa9946
part1
am11 Aug 10, 2024
429e67c
part2
am11 Aug 10, 2024
e0ef18b
part3
am11 Aug 10, 2024
3900943
Misc. fixes
am11 Aug 11, 2024
4cbecee
Apply fixes from main
am11 Sep 29, 2024
8adbc73
Fix registers/offsets in riscv-nativeaot.
sunlijun-610 Oct 8, 2024
ec0776c
Revert the changes in UnwindCursor.hpp and REGDISPLAY.
sunlijun-610 Nov 14, 2024
6fce606
Fix *.S files in riscv-nativeaot.
sunlijun-610 Nov 29, 2024
8b819a5
Merge dotnet/main into feature/nativeaot/riscv64-port
am11 Dec 13, 2024
4dbe95c
Fix riscv64 nativeaot native build
am11 Dec 13, 2024
e1fbc73
Merge branch 'main' into feature/nativeaot/riscv64-port
am11 Dec 13, 2024
c01dc7b
Managed build fixes
am11 Dec 13, 2024
bd3641b
Address feedback
am11 Dec 16, 2024
ddbb05e
Apply suggestions from code review
am11 Dec 16, 2024
60f3f1d
Update src/coreclr/nativeaot/Runtime/riscv64/UniversalTransition.S
am11 Dec 16, 2024
03e4394
Apply suggestions from code review
am11 Dec 17, 2024
56e5a87
Apply suggestions from code review
am11 Dec 17, 2024
ef6d1d7
Merge branch 'main' into feature/nativeaot/riscv64-port
am11 Dec 17, 2024
d006373
Merge branch 'main' into feature/nativeaot/riscv64-port
am11 Dec 20, 2024
71fb818
Merge branch 'main' into feature/nativeaot/riscv64-port
am11 Jan 9, 2025
b96fc63
Define GetReturnAddressRegisterLocation
am11 Jan 9, 2025
3949dfa
Fix merge conflict
am11 Jan 9, 2025
a33d91c
Update other macros in AsmOffsetsVerify
am11 Jan 9, 2025
c3c07cd
Update src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWrite…
jkotas Jan 9, 2025
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));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, this is producing message like:

static_assert failed: 'Bad asm offset for 'PAL_LIMITED_CONTEXT.Rbp'. Actual offset: offsetof(PAL_LIMITED_CONTEXT, Rbp)'

This is less informative message than the existing one that tries to tell you whether the actual offset is less or more. Why is it an improvement?

Also, if it is an improvement, should the other macros in this file get the same treatment?

Copy link
Member Author

@am11 am11 Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. I just changed the value of ExInfo and ran build.sh -a loongarch64 in the container I was already running, it shows the actual computed value:

  [ 33%] Built target unwinder_wks
  In file included from /runtime/src/coreclr/nativeaot/Runtime/AsmOffsetsVerify.cpp:46:
  In file included from /runtime/src/coreclr/nativeaot/Runtime/AsmOffsets.h:84:
  /runtime/src/coreclr/nativeaot/Runtime/loongarch64/AsmOffsetsCpu.h:11:1: error: static assertion failed due to requirement '__builtin_offsetof(ExInfo, m_pPrevExInfo) == 1': Bad asm offset for 'ExInfo.m_pPrevExInfo'. Actual offset: offsetof(ExInfo, m_pPrevExInfo)
     11 | PLAT_ASM_OFFSET(1, ExInfo, m_pPrevExInfo)
        | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  /runtime/src/coreclr/nativeaot/Runtime/AsmOffsetsVerify.cpp:36:19: note: expanded from macro 'PLAT_ASM_OFFSET'
     36 |     static_assert(offsetof(cls, member) == 0x##offset, "Bad asm offset for '" #cls "." #member "'. Actual offset: " OFFSET_STRING(cls, member));
        |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  /usr/lib/llvm-19/lib/clang/19/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
     16 | #define offsetof(t, d) __builtin_offsetof(t, d)
        |                        ^
  /runtime/src/coreclr/nativeaot/Runtime/loongarch64/AsmOffsetsCpu.h:11:1: note: expression evaluates to '0 == 1'
     11 | PLAT_ASM_OFFSET(1, ExInfo, m_pPrevExInfo)
        | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  /runtime/src/coreclr/nativeaot/Runtime/AsmOffsetsVerify.cpp:36:41: note: expanded from macro 'PLAT_ASM_OFFSET'
     36 |     static_assert(offsetof(cls, member) == 0x##offset, "Bad asm offset for '" #cls "." #member "'. Actual offset: " OFFSET_STRING(cls, member));
        |                   ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~

It helped me figuring out a few issues during the port. I can update other macros as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not show the computed value with Windows compilers:

  C:\runtime\src\coreclr\nativeaot\Runtime\amd64\AsmOffsetsCpu.h(19): error C2338: static_assert failed: 'Bad asmoffset for 'ExInfo.m_notifyDebuggerSP'. Actual offset: offsetof(ExInfo, m_notifyDebuggerSP)'

I am fine with changing it. All macros in the file should be changed the same way.


#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
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
Loading