Skip to content
Draft
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c2b6454
[CLRINTRP] Port to ARM
clamp03 Jul 30, 2025
ad24b45
[CLRINTRP] Make dummy asssembly functions
clamp03 Sep 11, 2025
04b980f
Disable Float
clamp03 Sep 16, 2025
8cd71fa
[INTRP] Print HelloWorld Done
clamp03 Sep 18, 2025
55560c4
[INTRP] HelloWorld Done
clamp03 Sep 18, 2025
7df0312
[INTRP] Update X to R for arm register
clamp03 Sep 22, 2025
5b3ef8e
[INTRP] Call methods with 2 args and return value
clamp03 Sep 23, 2025
02320b0
[INTRP] Implement Args Load and Store Assemblies
clamp03 Sep 23, 2025
cb816e6
[INTRP] Add Load_Ref and Store_Ref
clamp03 Sep 23, 2025
0cc0032
[INTRP] Return I8
clamp03 Sep 23, 2025
a09723d
[INTRP] Update I8 to I4 for ARM32
clamp03 Sep 23, 2025
07d975a
[INTRP] Call to Method with LONG args
clamp03 Sep 24, 2025
9875d8b
[INTRP] Initial Support for Float and Double
clamp03 Sep 25, 2025
4d7d19f
[INTRP] Update for ARM SOFTFP
clamp03 Sep 25, 2025
ab7eca6
[INTRP] Update all assemblies for arm softp
clamp03 Sep 25, 2025
1cf65b7
[INTRP] Can Pass Arguments using Stack
clamp03 Sep 25, 2025
aabd45b
[INTRP] Remove Redundant Codes
clamp03 Sep 26, 2025
e6a79a0
[INTRP] Support Struct
clamp03 Sep 26, 2025
a5e1bd5
[INTRP] Support RetBuff
clamp03 Sep 26, 2025
b3ba6ec
[DO NOT MERGE] For Test
clamp03 Oct 13, 2025
30e25e0
[INTRP] Fix release build errors
clamp03 Oct 14, 2025
82769b4
Revert "[DO NOT MERGE] For Test"
clamp03 Oct 14, 2025
f402453
Workarounds for errors
clamp03 Oct 14, 2025
4d48c03
Revert INTERP_STACK_SLOT_SIZE
clamp03 Oct 14, 2025
1607eb2
Revert "Revert INTERP_STACK_SLOT_SIZE"
clamp03 Oct 15, 2025
8280ee2
Update StackVal for 32 bit target
clamp03 Oct 15, 2025
df468a6
Merge remote-tracking branch 'origin/main' into intrp_arm
clamp03 Oct 15, 2025
b93b7cd
Fix align for 8 bytes and value type
clamp03 Oct 20, 2025
a9c0d6e
8 bytes stack size for WASM
clamp03 Oct 20, 2025
705cf2e
Change interpreter stack size to 8 bytes
clamp03 Oct 22, 2025
fe42ce9
Update ProcessArgument
clamp03 Oct 22, 2025
c69cb0d
Merge remote-tracking branch 'origin/main' into intrp_arm
clamp03 Oct 23, 2025
4e3ac8d
Fix InterpreterStub
clamp03 Oct 23, 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/clr.featuredefines.props
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<FeatureObjCMarshal>true</FeatureObjCMarshal>
</PropertyGroup>

<PropertyGroup Condition="('$(Platform)' == 'x64' OR '$(Platform)' == 'arm64') AND ('$(Configuration)' == 'debug' OR '$(Configuration)' == 'checked') AND '$(TargetsAndroid)' != 'true'">
<PropertyGroup Condition="('$(Platform)' == 'x64' OR '$(Platform)' == 'arm64' OR '$(Platform)' == 'arm') AND ('$(Configuration)' == 'debug' OR '$(Configuration)' == 'checked') AND '$(TargetsAndroid)' != 'true'">
<FeatureInterpreter>true</FeatureInterpreter>
</PropertyGroup>

Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/clrfeatures.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ if(NOT DEFINED FEATURE_INTERPRETER)
set(FEATURE_PORTABLE_ENTRYPOINTS 1)
set(FEATURE_PORTABLE_HELPERS 1)
else()
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_ARM)
set(FEATURE_INTERPRETER $<IF:$<CONFIG:Debug,Checked>,1,0>)
else(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
else(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_ARM)
set(FEATURE_INTERPRETER 0)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_ARM)
endif()
endif(NOT DEFINED FEATURE_INTERPRETER)

Expand Down
17 changes: 17 additions & 0 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,12 @@ void InterpCompiler::PushStackType(StackType stackType, CORINFO_CLASS_HANDLE cls
int size = m_compHnd->getClassSize(clsHnd);
PushTypeExplicit(stackType, clsHnd, size);
}
#ifndef TARGET_64BIT
else if (stackType == StackTypeI8 || stackType == StackTypeR8)
{
PushTypeExplicit(stackType, clsHnd, INTERP_STACK_SLOT_SIZE * 2);
}
#endif // !TARGET_64BIT
else
{
// We don't really care about the exact size for non-valuetypes
Expand Down Expand Up @@ -1771,7 +1777,11 @@ void InterpCompiler::EmitConv(StackInfo *sp, StackType type, InterpOpcode convOp
InterpInst *newInst = AddIns(convOp);

newInst->SetSVar(sp->var);
#ifndef TARGET_64BIT
int32_t var = CreateVarExplicit(g_interpTypeFromStackType[type], NULL, (type == StackTypeI8 || type == StackTypeR8) ? INTERP_STACK_SLOT_SIZE * 2 : INTERP_STACK_SLOT_SIZE);
#else // TARGET_64BIT
int32_t var = CreateVarExplicit(g_interpTypeFromStackType[type], NULL, INTERP_STACK_SLOT_SIZE);
#endif // !TARGET_64BIT
new (sp) StackInfo(type, NULL, var);
newInst->SetDVar(var);

Expand Down Expand Up @@ -1836,6 +1846,13 @@ int32_t InterpCompiler::GetInterpTypeStackSize(CORINFO_CLASS_HANDLE clsHnd, Inte
if (align < INTERP_STACK_SLOT_SIZE)
align = INTERP_STACK_SLOT_SIZE;
}
#ifndef TARGET_64BIT
else if (interpType == InterpTypeI8 || interpType == InterpTypeR8)
{
size = INTERP_STACK_SLOT_SIZE * 2; // not really
align = INTERP_STACK_SLOT_SIZE * 2;
}
#endif // !TARGET_64BIT
else
{
size = INTERP_STACK_SLOT_SIZE; // not really
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/interpreter/inc/interpretershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
#define INTERP_API __attribute__ ((visibility ("default")))
#endif // _MSC_VER

#ifdef TARGET_64BIT
#define INTERP_STACK_SLOT_SIZE 8 // Alignment of each var offset on the interpreter stack
#else // !TARGET_64BIT
#define INTERP_STACK_SLOT_SIZE 4 // Alignment of each var offset on the interpreter stack
Copy link
Member

Choose a reason for hiding this comment

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

This is a bad idea, I think. It will cause all sorts of mayhem. Is there a particular reason why this needs to happen for your PR to work?

Copy link
Member

Choose a reason for hiding this comment

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

Also, if you change this, StackVal in interpexec.h needs to have its 8-byte elements removed, I believe.

Copy link
Member Author

@clamp03 clamp03 Oct 14, 2025

Choose a reason for hiding this comment

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

This is a bad idea, I think. It will cause all sorts of mayhem. Is there a particular reason why this needs to happen for your PR to work?

I thought 4bytes is good for ARM32 architecture to sync register size and interpreter stack size. (+ and reduce memory a little.) For 8-byte elements, I changed it to use two stacks in some places.
If you think it is better to keep stack slot size to 8 bytes for ARM32 too, I will update it.

Also, if you change this, StackVal in interpexec.h needs to have its 8-byte elements removed, I believe.

Thank you. I missed.

+ Do you have any test set for interpreter implementation? If you have, could you share tests and how to test? Thank you.

Copy link
Member

Choose a reason for hiding this comment

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

InterpreterTester and Interpreter.cs were where we started testing before we were able to run the whole test suite.

I'll leave it to one of the interpreter architects to say whether the stack slot size should stay at 8, I just wanted to let you know that it has wide-ranging consequences.

For what it's worth, the mono interpreter has 8-byte stack slots even on arm32.

Copy link
Member Author

Choose a reason for hiding this comment

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

I will check the implementation with InterpreterTester.

Okay. It can make wide-ranging consequences even though I think there are some benefits for ARM32.
I will revert to 8 byte-stack slot.
Thank you.

Copy link
Member Author

Choose a reason for hiding this comment

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

@kg I found a problem when I change it to 8 byte-stack slot. (Actually, I forgot implementation details during my long holidays. 🥲)

If I change it to 8 byte-stack slot, it seems passing args between compiled methods and interpreter is hard. When it passes two 4-bytes args or one 8-bytes arg, it uses 2 registers in ARM32. So if it is one 8-bytes arg, values in two registers are needed to be loaded from or stored to one stack slot. However in case of two 4-bytes args, values in two registers are loaded from or stored to two stack slots. In current implementation, argument passing is handled by Load_* and Store_* routines in assembly code without any type check. However, if stack slot is 8 bytes, I think it needs to do type check for all args (or make routines for all cases.).
How do you solve this in mono interpreter? Could you share any idea about this?
Thank you.

Copy link
Member

Choose a reason for hiding this comment

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

I believe the mono interpreter does transitions using hand-written C helpers in most cases, so the C compiler solves the problem for us. @BrzVlad would probably know better though.

Copy link
Member Author

Choose a reason for hiding this comment

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

@kg Thank you. I think 4-bytes stack slot for arm32 isn't so bad idea to me. And if I isolate ARM32 implementation from the other arch well, I think it doesn't make wide-ranging consequences in other archs. What do you think?

#endif
#define INTERP_STACK_ALIGNMENT 16 // Alignment of interpreter stack at the start of a frame

struct InterpHelperData {
Expand Down
22 changes: 22 additions & 0 deletions src/coreclr/pal/inc/unixasmmacrosarm.inc
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ C_FUNC(\Name):
.endif

__PWTB_StackAlloc = __PWTB_TransitionBlock
__PWTB_ArgumentRegisters = __PWTB_StackAlloc + 36

.ifnc \pushArgRegs, DoNotPushArgRegs
PUSH_ARGUMENT_REGISTERS
Expand Down Expand Up @@ -318,3 +319,24 @@ C_FUNC(\Name):
movw \DestReg, #((\Constant) & 0xFFFF)
movt \DestReg, #((\Constant) >> 16)
.endm


// thumb with PIC version
.macro INLINE_GET_TLS_VAR var
ldr r0, 2f
1:
add r0, pc, r0
bl __tls_get_addr
b 3f

// Inline data
// LLVM assembler has no concept of subsections and this is not expressible as
// cross-section relocation.
.p2align 2
2:
.extern \var
.type \var, tls_object
.long \var(TLSGD) + (2b - 1b - 4)
3:
.endm

31 changes: 31 additions & 0 deletions src/coreclr/vm/arm/asmconstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ ASMCONSTANTS_C_ASSERT(ASM_MIN_OBJECT_SIZE == MIN_OBJECT_SIZE);
#define MethodTable__enum_flag_ContainsGCPointers 0x01000000
ASMCONSTANTS_C_ASSERT(MethodTable__enum_flag_ContainsGCPointers == MethodTable::enum_flag_ContainsGCPointers);

#define METHODDESC_REGISTER r12

#define SIZEOF__MethodTable DBG_FRE(0x2c, 0x28)
ASMCONSTANTS_C_ASSERT(SIZEOF__MethodTable == sizeof(MethodTable));

Expand Down Expand Up @@ -198,6 +200,35 @@ ASMCONSTANTS_C_ASSERT(CallCountingStubData__TargetForMethod == offsetof(CallCoun
ASMCONSTANTS_C_ASSERT(CallCountingStubData__TargetForThresholdReached == offsetof(CallCountingStubData, TargetForThresholdReached))
#endif // FEATURE_TIERED_COMPILATION

#define OFFSETOF__ThreadLocalInfo__m_pThread 0
ASMCONSTANTS_C_ASSERT(OFFSETOF__ThreadLocalInfo__m_pThread == offsetof(ThreadLocalInfo, m_pThread))

#ifdef FEATURE_INTERPRETER
#ifdef _DEBUG
#define OFFSETOF__InterpMethod__pCallStub 0x14
#else
#define OFFSETOF__InterpMethod__pCallStub 0x10
#endif
ASMCONSTANTS_C_ASSERT(OFFSETOF__InterpMethod__pCallStub == offsetof(InterpMethod, pCallStub))

#ifdef TARGET_UNIX
#define OFFSETOF__Thread__m_pInterpThreadContext 0x660
#else // TARGET_UNIX
#define OFFSETOF__Thread__m_pInterpThreadContext 0x0
#endif // TARGET_UNIX
ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_pInterpThreadContext == offsetof(Thread, m_pInterpThreadContext))

#define OFFSETOF__InterpThreadContext__pStackPointer 0x8
ASMCONSTANTS_C_ASSERT(OFFSETOF__InterpThreadContext__pStackPointer == offsetof(InterpThreadContext, pStackPointer))

#define OFFSETOF__CallStubHeader__Routines 0xc
ASMCONSTANTS_C_ASSERT(OFFSETOF__CallStubHeader__Routines == offsetof(CallStubHeader, Routines))

#define SIZEOF__TransitionBlock 0x34
ASMCONSTANTS_C_ASSERT(SIZEOF__TransitionBlock == sizeof(TransitionBlock))

#endif // FEATURE_INTERPRETER

#ifdef PROFILING_SUPPORTED
#define PROFILE_ENTER 0x1
#define PROFILE_LEAVE 0x2
Expand Down
Loading
Loading