Skip to content

Commit

Permalink
Fix riscv register mapping with llvm-libunwind (#111735)
Browse files Browse the repository at this point in the history
* Fix riscv register mapping with llvm-libunwind

* Use tail and cleanup custom regs

* Delete emulated TLS from riscv and loongarch

* Fix UniversalTransition

* Fix emitOutputCall and use ret

Co-authored-by: Filip Navara <filip.navara@gmail.com>

* Use traditional TLS dialect for the time being

---------

Co-authored-by: Filip Navara <filip.navara@gmail.com>
  • Loading branch information
am11 and filipnavara authored Feb 7, 2025
1 parent 15f422d commit 42a58a2
Show file tree
Hide file tree
Showing 19 changed files with 477 additions and 561 deletions.
4 changes: 2 additions & 2 deletions src/coreclr/jit/emitriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1624,8 +1624,8 @@ unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, c

size_t addr = (size_t)(id->idAddr()->iiaAddr); // get addr.

int reg2 = ((int)addr & 1) + 10;
addr = addr ^ 1;
int reg2 = (int)(addr & 1);
addr -= reg2;

if (!emitComp->opts.compReloc)
{
Expand Down
37 changes: 35 additions & 2 deletions src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,39 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PAL_LIMITED_CO
m_RegDisplay.pR4 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, R4);
m_RegDisplay.pR5 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, R5);

#elif defined(TARGET_RISCV64)
//
// preserved regs
//
m_RegDisplay.pS1 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S1);
m_RegDisplay.pS2 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S2);
m_RegDisplay.pS3 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S3);
m_RegDisplay.pS4 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S4);
m_RegDisplay.pS5 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S5);
m_RegDisplay.pS6 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S6);
m_RegDisplay.pS7 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S7);
m_RegDisplay.pS8 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S8);
m_RegDisplay.pS9 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S9);
m_RegDisplay.pS10 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S10);
m_RegDisplay.pS11 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, S11);
m_RegDisplay.pFP = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, FP);
m_RegDisplay.pRA = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, RA);

//
// preserved floating-point registers
//
int32_t preservedFpIndices[] = {8, 9, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};
for (int i = 0; i < sizeof(preservedFpIndices) / sizeof(preservedFpIndices[0]); i++)
{
m_RegDisplay.F[preservedFpIndices[i]] = pCtx->F[preservedFpIndices[i]];
}

//
// scratch regs
//
m_RegDisplay.pA0 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, A0);
m_RegDisplay.pA1 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, A1);

#elif defined(UNIX_AMD64_ABI)
//
// preserved regs
Expand Down Expand Up @@ -776,7 +809,7 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, NATIVE_CONTEXT* pC
m_RegDisplay.pS9 = (PTR_uintptr_t)PTR_TO_REG(pCtx, S9);
m_RegDisplay.pS10 = (PTR_uintptr_t)PTR_TO_REG(pCtx, S10);
m_RegDisplay.pS11 = (PTR_uintptr_t)PTR_TO_REG(pCtx, S11);

//
// scratch regs
//
Expand Down Expand Up @@ -1007,7 +1040,7 @@ void StackFrameIterator::UnwindFuncletInvokeThunk()
#if defined(USE_PORTABLE_HELPERS) // @TODO: Currently no funclet invoke defined in a portable way
return;
#else // defined(USE_PORTABLE_HELPERS)
ASSERT((CategorizeUnadjustedReturnAddress(m_ControlPC) == InFuncletInvokeThunk) ||
ASSERT((CategorizeUnadjustedReturnAddress(m_ControlPC) == InFuncletInvokeThunk) ||
(CategorizeUnadjustedReturnAddress(m_ControlPC) == InFilterFuncletInvokeThunk));

PTR_uintptr_t SP;
Expand Down
8 changes: 0 additions & 8 deletions src/coreclr/nativeaot/Runtime/loongarch64/AllocFast.S
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@
LEAF_ENTRY RhpNewFast, _TEXT

// a1 = GetThread()
#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_1
#else
INLINE_GETTHREAD $a1
#endif

//
// a0 contains MethodTable pointer
Expand Down Expand Up @@ -125,11 +121,7 @@ LOCAL_LABEL(NewOutOfMemory):
// a1 == element count
// a2 == string size

#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_3
#else
INLINE_GETTHREAD $a3
#endif

// Load potential new object address into t3.
ld.d $t3, $a3, OFFSETOF__Thread__m_alloc_context__alloc_ptr
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/nativeaot/Runtime/loongarch64/GcProbe.S
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,7 @@
.macro FixupHijackedCallstack

// a2 <- GetThread()
#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_2
#else
INLINE_GETTHREAD $a2
#endif

//
// Fix the stack by restoring the original return address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,7 @@
// Custom calling convention:
// tp pointer to the current thunk's data block (data contains 2 pointer values: context + target pointers)

#ifdef FEATURE_EMULATED_TLS
// This doesn't save and restore the floating point argument registers. If we encounter a
// target system that uses TLS emulation and modify these registers during this call we
// need to save and restore them, too
GETTHUNKDATA_ETLS_9
#else
INLINE_GET_TLS_VAR $t0, C_FUNC(tls_thunkData)
#endif

// t0 = base address of TLS data
// tp = address of context cell in thunk's data
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/nativeaot/Runtime/loongarch64/PInvoke.S
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ NESTED_ENTRY RhpPInvoke, _TEXT, NoHandler

// get TLS global variable address

#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_1
#else
INLINE_GETTHREAD $a1
#endif

st.d $a1, $a0, OFFSETOF__PInvokeTransitionFrame__m_pThread
st.d $a0, $a1, OFFSETOF__Thread__m_pTransitionFrame
Expand Down
37 changes: 19 additions & 18 deletions src/coreclr/nativeaot/Runtime/riscv64/AllocFast.S
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,17 @@
LEAF_ENTRY RhpNewFast, _TEXT

// a1 = GetThread()
#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_1
#else
// Save MethodTable pointer. INLINE_GETTHREAD will trash a0.
mv t2, a0
INLINE_GETTHREAD a1
#endif

//
// a0 contains MethodTable pointer
// t2 contains MethodTable pointer
//
lw a2, OFFSETOF__MethodTable__m_uBaseSize(a0)
lw a2, OFFSETOF__MethodTable__m_uBaseSize(t2)

//
// a0: MethodTable pointer
// t2: MethodTable pointer
// a1: Thread pointer
// a2: base size
//
Expand All @@ -49,13 +47,14 @@
sd a2, OFFSETOF__Thread__m_alloc_context__alloc_ptr(a1)

// Set the new objects MethodTable pointer
sd a0, OFFSETOF__Object__m_pEEType(t3)
sd t2, OFFSETOF__Object__m_pEEType(t3)

mv a0, t3
ret

LOCAL_LABEL(RhpNewFast_RarePath):
mv a1, zero
mv a0, t2
tail RhpNewObject
LEAF_END RhpNewFast, _TEXT

Expand Down Expand Up @@ -123,11 +122,9 @@ LOCAL_LABEL(NewOutOfMemory):
// a1 == element count
// a2 == string size

#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_3
#else
// Save MethodTable pointer. INLINE_GETTHREAD will trash a0.
mv t2, a0
INLINE_GETTHREAD a3
#endif

// Load potential new object address into t3.
ld t3, OFFSETOF__Thread__m_alloc_context__alloc_ptr(a3)
Expand All @@ -145,7 +142,7 @@ LOCAL_LABEL(NewOutOfMemory):
sd a2, OFFSETOF__Thread__m_alloc_context__alloc_ptr(a3)

// Set the new object's MethodTable pointer and element count.
sd a0, OFFSETOF__Object__m_pEEType(t3)
sd t2, OFFSETOF__Object__m_pEEType(t3)
sd a1, OFFSETOF__Array__m_Length(t3)

// Return the object allocated in a0.
Expand All @@ -158,11 +155,12 @@ LOCAL_LABEL(StringSizeOverflow):
// 32-bit value. We are going to tail-call to a managed helper that will throw
// an OOM exception that the caller of this allocator understands.

// a0 holds MethodTable pointer already
mv a0, t2
li a1, 1 // Indicate that we should throw OverflowException
tail C_FUNC(RhExceptionHandling_FailedAllocation)

LOCAL_LABEL(RhNewString_Rare):
mv a0, t2
tail C_FUNC(RhpNewArrayRare)
LEAF_END RhNewString, _TEXT

Expand All @@ -178,9 +176,9 @@ LOCAL_LABEL(RhNewString_Rare):
li a2, 0x7fffffff
bltu a2, a1, LOCAL_LABEL(ArraySizeOverflow) // Branch if a2 < a1 (check for overflow)

ld a2, OFFSETOF__MethodTable__m_usComponentSize(a0) // Load component size
lhu a2, OFFSETOF__MethodTable__m_usComponentSize(a0) // Load component size
mul a2, a1, a2 // a2 = a1 * component size
ld a3, OFFSETOF__MethodTable__m_uBaseSize(a0) // Load base size
lw a3, OFFSETOF__MethodTable__m_uBaseSize(a0) // Load base size
add a2, a2, a3 // a2 = a2 + base size
addi a2, a2, 7 // a2 = a2 + 7
andi a2, a2, ~0x7 // Clear the bits[2:0] of a2 (align to 8 bytes)
Expand All @@ -189,6 +187,8 @@ LOCAL_LABEL(RhNewString_Rare):
// a1 == element count
// a2 == array size

// Save MethodTable pointer. INLINE_GETTHREAD will trash a0.
mv t2, a0
INLINE_GETTHREAD a3

// Load potential new object address into t3.
Expand All @@ -207,7 +207,7 @@ LOCAL_LABEL(RhNewString_Rare):
sd a2, OFFSETOF__Thread__m_alloc_context__alloc_ptr(a3)

// Set the new object's MethodTable pointer and element count.
sd a0, OFFSETOF__Object__m_pEEType(t3)
sd t2, OFFSETOF__Object__m_pEEType(t3)
sd a1, OFFSETOF__Array__m_Length(t3)

// Return the object allocated in a0.
Expand All @@ -220,11 +220,12 @@ LOCAL_LABEL(ArraySizeOverflow):
// 32-bit value. We are going to tail-call to a managed helper that will throw
// an overflow exception that the caller of this allocator understands.

// a0 holds MethodTable pointer already
mv a0, t2
li a1, 1 // Indicate that we should throw OverflowException
tail C_FUNC(RhExceptionHandling_FailedAllocation)

LOCAL_LABEL(RhpNewArray_Rare):
mv a0, t2
tail C_FUNC(RhpNewArrayRare)
LEAF_END RhpNewArray, _TEXT

Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/nativeaot/Runtime/riscv64/ExceptionHandling.S
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ LOCAL_LABEL(NoAbort):

// Allocate space for the call funclet frame
ALLOC_CALL_FUNCLET_FRAME 0x80

// Save floating-point registers
fsd fs0, 0x00(sp)
fsd fs1, 0x08(sp)
Expand All @@ -605,7 +605,7 @@ LOCAL_LABEL(NoAbort):
fsd fs9, 0x48(sp)
fsd fs10, 0x50(sp)
fsd fs11, 0x58(sp)

// Save integer registers
sd a0, 0x60(sp) // Save a0 to 0x60
sd a1, 0x68(sp) // Save a1 to 0x68
Expand Down Expand Up @@ -664,7 +664,7 @@ LOCAL_LABEL(NoAbort):

// Free call funclet frame
FREE_CALL_FUNCLET_FRAME 0x80

// Return
EPILOG_RETURN

Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/nativeaot/Runtime/riscv64/GcProbe.S
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,7 @@
.macro FixupHijackedCallstack

// a2 <- GetThread()
#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_2
#else
INLINE_GETTHREAD a2
#endif

// Fix the stack by restoring the original return address
ld ra, OFFSETOF__Thread__m_pvHijackedReturnAddress(a2)
Expand Down
6 changes: 0 additions & 6 deletions src/coreclr/nativeaot/Runtime/riscv64/InteropThunksHelpers.S
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@
// Custom calling convention:
// tp pointer to the current thunk's data block (data contains 2 pointer values: context + target pointers)

#ifdef FEATURE_EMULATED_TLS
// If using TLS emulation, fetch the TLS data block address
GETTHUNKDATA_ETLS_9
#else
// Inline function to get TLS variable
INLINE_GET_TLS_VAR t0, C_FUNC(tls_thunkData)
#endif

// t0 = base address of TLS data
// tp = address of context cell in thunk's data
Expand Down
31 changes: 16 additions & 15 deletions src/coreclr/nativeaot/Runtime/riscv64/PInvoke.S
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,32 @@
NESTED_ENTRY RhpPInvoke, _TEXT, NoHandler
sd fp, OFFSETOF__PInvokeTransitionFrame__m_FramePointer(a0)
sd ra, OFFSETOF__PInvokeTransitionFrame__m_RIP(a0)
sd sp, OFFSETOF__PInvokeTransitionFrame__m_PreservedRegs(a0)
sd t0, OFFSETOF__PInvokeTransitionFrame__m_PreservedRegs(a0)
li t0, PTFF_SAVE_SP
sd t0, OFFSETOF__PInvokeTransitionFrame__m_Flags(a0)

// get TLS global variable address
#ifdef FEATURE_EMULATED_TLS
GETTHREAD_ETLS_1
#else
// Save MethodTable pointer. INLINE_GETTHREAD will trash a0.
mv t2, a0
INLINE_GETTHREAD a1
#endif

sd a1, OFFSETOF__PInvokeTransitionFrame__m_pThread(a0)
sd a0, OFFSETOF__Thread__m_pTransitionFrame(a1)
jr ra
sd a1, OFFSETOF__PInvokeTransitionFrame__m_pThread(t2)
sd t2, OFFSETOF__Thread__m_pTransitionFrame(a1)
ret
NESTED_END RhpPInvoke, _TEXT

LEAF_ENTRY RhpPInvokeReturn, _TEXT
ld t0, OFFSETOF__PInvokeTransitionFrame__m_pThread(a0)
sd zero, OFFSETOF__Thread__m_pTransitionFrame(t0)
mv t1, zero
sd t1, OFFSETOF__Thread__m_pTransitionFrame(t0)

PREPARE_EXTERNAL_VAR_INDIRECT_W RhpTrapThreads, a5
PREPARE_EXTERNAL_VAR_INDIRECT_W RhpTrapThreads, t0

bnez t1, 0f // If TrapThreadsFlags_None is non-zero, branch
ret

0:
// Passing transition frame pointer in a0
tail RhpWaitForGC2

bne t0, zero, 1f // TrapThreadsFlags_None = 0
jr ra
1:
// passing transition frame pointer in a0
tail C_FUNC(RhpWaitForGC2)
LEAF_END RhpPInvokeReturn, _TEXT
Loading

0 comments on commit 42a58a2

Please sign in to comment.