Skip to content

Implement full support for the LoongArch CPU architecture#377

Open
basilisk-dev wants to merge 6 commits intognustep:masterfrom
basilisk-dev:loongarch64-obj_msgSend
Open

Implement full support for the LoongArch CPU architecture#377
basilisk-dev wants to merge 6 commits intognustep:masterfrom
basilisk-dev:loongarch64-obj_msgSend

Conversation

@basilisk-dev
Copy link
Copy Markdown

Ported objc_msgSend to the LoongArch64 architecture by adding a native assembly implementation. I basically ported the RISC-V implementation to LoongArch64 assembly. You can read more about the LoongArch architecture here if interested.

I ran the relevant tests and they all passed, and I also tested the implementation manually on LoongArch64 to verify it behaves correctly.

Please let me know if you need any additional info.

@davidchisnall
Copy link
Copy Markdown
Member

Thanks, this looks correct but I’d like to see it running in CI. I believe there is QEMU user mode support for Loongarch, can you add it to the workflow runner?

For this to be useful, we will also need a clang patch that enables the assembly message-dispatch function for message sends.

@basilisk-dev basilisk-dev force-pushed the loongarch64-obj_msgSend branch 3 times, most recently from 6a5a9b5 to f45f097 Compare March 26, 2026 16:28
@basilisk-dev
Copy link
Copy Markdown
Author

@davidchisnall I had to make a slight change to allow the implementation to compile on Clang 18 (I used Clang 22 during initial development).

I've added logic to the GitHub Actions workflow to allow the tests to run against LoongArch64 as well. Here is a test run I did: https://github.com/basilisk-dev/libobjc2/actions/runs/23605441514/job/68746795969

I had to exclude LLVM 16 and LLVM 17 on LoongArch64. ld.lld in the Ubuntu LLVM 16 and LLVM 17 packages do not support linking on LoongArch64.

A few of the tests fail because there is no LoongArch64 implementation in block_trampolines.S but I intend to fix that in a separate PR.

For this to be useful, we will also need a clang patch that enables the assembly message-dispatch function for message sends

Makes sense, I'm not familiar with Clang/LLVM internals so I didn't realize this wasn't already the case.

@davidchisnall davidchisnall force-pushed the loongarch64-obj_msgSend branch from f45f097 to 20ff36f Compare April 18, 2026 09:23
Copy link
Copy Markdown
Member

@davidchisnall davidchisnall left a comment

Choose a reason for hiding this comment

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

Thanks. Looks like it would be quite easy to tweak to support 32-bit of desirable.

@davidchisnall
Copy link
Copy Markdown
Member

CI is failing because of the missing block-to-IMP logic. This is pretty small, but we need to either skip that test on LoongArch or implement it.

@davidchisnall
Copy link
Copy Markdown
Member

Assuming the immediate operand on ld.d is large enough on LoongArch, I think you should be able to simply copy the MIPS code paths here and replace ld with ld.d and jr with jirl (with a 0 immediate), and define ARG0 to ARG2 in exactly the same way.

@basilisk-dev basilisk-dev changed the title Implement objc_msgSend function for the LoongArch CPU architecture Implement full support for the LoongArch CPU architecture May 2, 2026
@basilisk-dev
Copy link
Copy Markdown
Author

Hey @davidchisnall, I went through and fixed the remaining feature gaps on LoongArch64. All CICD tests now pass on Loongarch64. The change was pretty minimal, Loongarch supports multiple page sizes like aarch64 so I added some code to account for that. Basically just the same as the MIPS and RISC-V implementations ported to Loongarch assembly.

Copy link
Copy Markdown

@MingcongBai MingcongBai left a comment

Choose a reason for hiding this comment

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

Preliminary review from me, I might have missed/misinterpreted something.

@xen0n @xry111 @ziyao233, etc. Would really appreciate your input.

triple: powerpc64le-linux-gnu
rtld: ld64.so.2
exclude:
# lld versions prior to 18 do not support linking LoongArch in the Ubuntu provided packages.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Linker relaxation related? Might be good to clarify for the record.

Comment thread objc/message.h
#if defined(__x86_64) || defined(__i386) || defined(__arm__) || \
defined(__mips_n64) || defined(__mips_n32) || \
defined(__ARM_ARCH_ISA_A64) || \
(defined(__loongarch__) && defined(__loongarch_lp64) && \
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

__loongarch_lp64 should suffice on its own, cc @xen0n @xry111 right?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

__loongarch__ should be redundant, but I think we should guard against __loongarch_double_float since floating registers are spilled/restored in the code as well.

Comment thread block_to_imp.c
#if defined(__i386__) || (defined(__mips__) && !defined(__mips_n64)) || (defined(__powerpc__) && !defined(__powerpc64__))
uint64_t padding[3];
#elif defined(__mips__) || defined(__ARM_ARCH_ISA_A64) || defined(__powerpc64__)
#elif defined(__mips__) || defined(__ARM_ARCH_ISA_A64) || defined(__powerpc64__) || (defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto above regarding arch macro.

Comment thread block_to_imp.c
Comment thread block_to_imp.c
extern char __objc_block_trampoline_end_16;
extern char __objc_block_trampoline_sret_16;
extern char __objc_block_trampoline_end_sret_16;
#elif defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto regarding arch macro.

Comment thread block_to_imp.c
trampoline_start_sret = &__objc_block_trampoline_sret_16;
trampoline_end_sret = &__objc_block_trampoline_end_sret_16;
} else {
#elif defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto.

Comment thread block_trampolines.S
#define SARG0 ARG1
#define SARG1 ARG2

#elif defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto.

Comment thread block_trampolines.S

// Trampoline for 16 KiB page sizes
#if defined(__ARM_ARCH_ISA_A64)
#if defined(__ARM_ARCH_ISA_A64) || (defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto.

Comment thread block_trampolines.S
#endif

// Trampoline for 64 KiB page sizes
#if defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto.

Comment thread objc_msgSend.S
#include "objc_msgSend.aarch64.S"
#elif defined(__riscv) && (__riscv_xlen == 64) && defined(__riscv_float_abi_double)
#include "objc_msgSend.riscv64.S"
#elif defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto.

Comment thread block_trampolines.S
// LoongArch64 trampoline
////////////////////////////////////////////////////////////////////////////////
.macro trampoline arg0, arg1
pcaddi $t0, -1024
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The LoongArch ABI doesn’t do the MIPS trick of requiring a specific register for jalr so you know the PC on entry?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No it doesn't, the MIPS way is mostly a hack for lacking the instructions like pcaddi.

Comment thread block_trampolines.S
ld.d $t0, $t0, 8
jr $t0
.endm
.macro trampoline_64 arg0, arg1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These trampolines appear to differ only by the displacement from the start, can’t that be just another macro argument?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

5 participants