Implement full support for the LoongArch CPU architecture#377
Implement full support for the LoongArch CPU architecture#377basilisk-dev wants to merge 6 commits intognustep:masterfrom
Conversation
|
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. |
6a5a9b5 to
f45f097
Compare
|
@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. A few of the tests fail because there is no LoongArch64 implementation in
Makes sense, I'm not familiar with Clang/LLVM internals so I didn't realize this wasn't already the case. |
f45f097 to
20ff36f
Compare
davidchisnall
left a comment
There was a problem hiding this comment.
Thanks. Looks like it would be quite easy to tweak to support 32-bit of desirable.
|
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. |
|
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 |
|
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. |
| triple: powerpc64le-linux-gnu | ||
| rtld: ld64.so.2 | ||
| exclude: | ||
| # lld versions prior to 18 do not support linking LoongArch in the Ubuntu provided packages. |
There was a problem hiding this comment.
Linker relaxation related? Might be good to clarify for the record.
| #if defined(__x86_64) || defined(__i386) || defined(__arm__) || \ | ||
| defined(__mips_n64) || defined(__mips_n32) || \ | ||
| defined(__ARM_ARCH_ISA_A64) || \ | ||
| (defined(__loongarch__) && defined(__loongarch_lp64) && \ |
There was a problem hiding this comment.
__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.
| #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)) |
| 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) |
| 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) |
| #define SARG0 ARG1 | ||
| #define SARG1 ARG2 | ||
|
|
||
| #elif defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float) |
|
|
||
| // 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)) |
| #endif | ||
|
|
||
| // Trampoline for 64 KiB page sizes | ||
| #if defined(__loongarch__) && defined(__loongarch_lp64) && defined(__loongarch_double_float) |
| #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) |
| // LoongArch64 trampoline | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| .macro trampoline arg0, arg1 | ||
| pcaddi $t0, -1024 |
There was a problem hiding this comment.
The LoongArch ABI doesn’t do the MIPS trick of requiring a specific register for jalr so you know the PC on entry?
There was a problem hiding this comment.
No it doesn't, the MIPS way is mostly a hack for lacking the instructions like pcaddi.
| ld.d $t0, $t0, 8 | ||
| jr $t0 | ||
| .endm | ||
| .macro trampoline_64 arg0, arg1 |
There was a problem hiding this comment.
These trampolines appear to differ only by the displacement from the start, can’t that be just another macro argument?
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.