diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 78929397..2b32239d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -100,11 +100,22 @@ jobs: system-processor: riscv64 triple: riscv64-linux-gnu rtld: ld-linux-riscv64-lp64d.so.1 + - name: loongarch64 + system-processor: loongarch64 + triple: loongarch64-linux-gnu + rtld: ld-linux-loongarch-lp64d.so.1 - name: ppc64el system-processor: powerpc64le triple: powerpc64le-linux-gnu rtld: ld64.so.2 exclude: + # lld versions prior to 18 do not support linking LoongArch in the Ubuntu provided packages. + - llvm-version: 16 + arch: + name: loongarch64 + - llvm-version: 17 + arch: + name: loongarch64 # FIXME(hugo): Hangs while executing tests. - llvm-version: 18 arch: @@ -118,7 +129,12 @@ jobs: - name: Install cross-compile toolchain and QEMU run: | sudo apt update - sudo apt install libstdc++-9-dev-${{ matrix.arch.name }}-cross qemu-user ninja-build + if [ "${{ matrix.arch.name }}" = "loongarch64" ]; then + # No libstdc++-9 package exists for LoongArch on Ubuntu, so use version 13. + sudo apt install libstdc++-13-dev-loong64-cross qemu-user ninja-build + else + sudo apt install libstdc++-9-dev-${{ matrix.arch.name }}-cross qemu-user ninja-build + fi - name: Configure CMake run: | export LDFLAGS="-L/usr/lib/llvm-${{ matrix.llvm-version }}/lib/ -fuse-ld=lld-${{ matrix.llvm-version}} -Wl,--dynamic-linker=/usr/${{ matrix.arch.triple }}/lib/${{ matrix.arch.rtld }},-rpath,/usr/${{ matrix.arch.triple }}/lib" diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d915d1f..27c10a55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,7 +213,7 @@ if (WIN32 AND NOT MINGW) COMMAND echo ${ASSEMBLER} ${ASM_TARGET} -c "${CMAKE_SOURCE_DIR}/objc_msgSend.S" -o "${CMAKE_BINARY_DIR}/objc_msgSend.obj" COMMAND ${ASSEMBLER} ${ASM_TARGET} -c "${CMAKE_SOURCE_DIR}/objc_msgSend.S" -o "${CMAKE_BINARY_DIR}/objc_msgSend.obj" MAIN_DEPENDENCY objc_msgSend.S - DEPENDS objc_msgSend.aarch64.S objc_msgSend.arm.S objc_msgSend.mips.S objc_msgSend.x86-32.S objc_msgSend.x86-64.S + DEPENDS objc_msgSend.aarch64.S objc_msgSend.arm.S objc_msgSend.loongarch64.S objc_msgSend.mips.S objc_msgSend.x86-32.S objc_msgSend.x86-64.S ) set(libobjc_ASM_OBJS block_trampolines.obj objc_msgSend.obj) endif() diff --git a/objc/message.h b/objc/message.h index ee4fba1d..7b107844 100644 --- a/objc/message.h +++ b/objc/message.h @@ -9,6 +9,8 @@ #if defined(__x86_64) || defined(__i386) || defined(__arm__) || \ defined(__mips_n64) || defined(__mips_n32) || \ defined(__ARM_ARCH_ISA_A64) || \ + (defined(__loongarch__) && defined(__loongarch_lp64) && \ + defined(__loongarch_double_float)) || \ (defined(__riscv) && __riscv_xlen == 64 && \ defined(__riscv_float_abi_double)) diff --git a/objc_msgSend.S b/objc_msgSend.S index 54275940..c90ceb9b 100644 --- a/objc_msgSend.S +++ b/objc_msgSend.S @@ -10,6 +10,8 @@ #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) +#include "objc_msgSend.loongarch64.S" #elif defined(__mips_n64) || defined(__mips_n32) #include "objc_msgSend.mips.S" #else diff --git a/objc_msgSend.loongarch64.S b/objc_msgSend.loongarch64.S new file mode 100644 index 00000000..129771e0 --- /dev/null +++ b/objc_msgSend.loongarch64.S @@ -0,0 +1,135 @@ +#define ARGUMENT_SPILL_SIZE (10*8 + 8*8) + +.macro MSGSEND receiver, sel + .cfi_startproc + beqz \receiver, 3f // Skip everything if receiver is nil + + andi $t0, \receiver, SMALLOBJ_MASK + bnez $t0, 5f + + ld.d $t0, \receiver, 0 // Load class into t0 +0: + ld.d $t0, $t0, DTABLE_OFFSET // dtable -> t0 + ld.d $t1, \sel, 0 // selector->index -> t1 + ld.w $t2, $t0, SHIFT_OFFSET // dtable->shift -> t2 + + addi.d $t3, $zero, 8 + beq $t2, $t3, 1f + beqz $t2, 2f + + srli.d $t2, $t1, 13 // Extract byte 3 of sel index and multiply by 2^3 + andi $t2, $t2, 0x7f8 + add.d $t2, $t0, $t2 + ld.d $t0, $t2, DATA_OFFSET +1: + srli.d $t2, $t1, 5 // Extract byte 2 of sel index and multiply by 2^3 + andi $t2, $t2, 0x7f8 + add.d $t2, $t0, $t2 + ld.d $t0, $t2, DATA_OFFSET +2: + slli.d $t2, $t1, 3 // Multiply by 2^3 + andi $t2, $t2, 0x7f8 + add.d $t2, $t0, $t2 + ld.d $t0, $t2, DATA_OFFSET // Slot pointer is now in t0 + + beqz $t0, 4f // If the slot is nil, go to the C path + + ld.d $t0, $t0, SLOT_OFFSET // Load the method from the slot + jr $t0 // Tail-call the method + +3: + move \receiver, $zero + move \sel, $zero + movgr2fr.d $fa0, $zero + movgr2fr.d $fa1, $zero + ret + +4: + addi.d $sp, $sp, -ARGUMENT_SPILL_SIZE + + // Spill function arguments. + st.d $a0, $sp, 0 + st.d $a1, $sp, 8 + st.d $a2, $sp, 16 + st.d $a3, $sp, 24 + st.d $a4, $sp, 32 + st.d $a5, $sp, 40 + st.d $a6, $sp, 48 + st.d $a7, $sp, 56 + + // Spill FP arguments. + fst.d $fa0, $sp, 64 + fst.d $fa1, $sp, 72 + fst.d $fa2, $sp, 80 + fst.d $fa3, $sp, 88 + fst.d $fa4, $sp, 96 + fst.d $fa5, $sp, 104 + fst.d $fa6, $sp, 112 + fst.d $fa7, $sp, 120 + + st.d $fp, $sp, 128 + st.d $ra, $sp, 136 + + addi.d $fp, $sp, 128 + addi.d $sp, $sp, -16 + st.d \receiver, $sp, 0 // Keep &self at sp for slowMsgLookup + + // Use explicit DWARF register numbers for compatibility with older Clang IAS. + .cfi_def_cfa 22, 16 + .cfi_offset 22, -16 + .cfi_offset 1, -8 + + move $a0, $sp // &self in first argument + move $a1, \sel + pcaddu18i $ra, %call36(CDECL(slowMsgLookup)) + jirl $ra, $ra, 0 + + move $t0, $a0 // IMP -> t0 + + ld.d $a0, $sp, 16 + ld.d $a1, $sp, 24 + ld.d $a2, $sp, 32 + ld.d $a3, $sp, 40 + ld.d $a4, $sp, 48 + ld.d $a5, $sp, 56 + ld.d $a6, $sp, 64 + ld.d $a7, $sp, 72 + + fld.d $fa0, $sp, 80 + fld.d $fa1, $sp, 88 + fld.d $fa2, $sp, 96 + fld.d $fa3, $sp, 104 + fld.d $fa4, $sp, 112 + fld.d $fa5, $sp, 120 + fld.d $fa6, $sp, 128 + fld.d $fa7, $sp, 136 + + ld.d $fp, $sp, 144 + ld.d $ra, $sp, 152 + ld.d \receiver, $sp, 0 + + addi.d $sp, $sp, ARGUMENT_SPILL_SIZE + addi.d $sp, $sp, 16 + + jr $t0 // Tail-call the method + +5: + pcalau12i $t1, %got_pc_hi20(CDECL(SmallObjectClasses)) + ld.d $t1, $t1, %got_pc_lo12(CDECL(SmallObjectClasses)) + slli.d $t0, $t0, 3 + ldx.d $t0, $t1, $t0 + b 0b + .cfi_endproc +.endm + +.globl CDECL(objc_msgSend_fpret) +TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function) +.globl CDECL(objc_msgSend) +TYPE_DIRECTIVE(CDECL(objc_msgSend), %function) +.globl CDECL(objc_msgSend_stret) +TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function) +CDECL(objc_msgSend): +CDECL(objc_msgSend_fpret): + MSGSEND $a0, $a1 +CDECL(objc_msgSend_stret): + MSGSEND $a1, $a2 // Pointer to stack frame in a0