Skip to content

Commit

Permalink
Initial RISC-V 64-bit Support (#261)
Browse files Browse the repository at this point in the history
* RISC-V objc_msgSend implementation

* Use objc_msgSend.riscv64.S if requirements are met

* RISC-V 64-bit block trampoline

* Fix formatting

* Add riscv64 crossbuild in CI

* Exclude llvm 13 and 14 for riscv64 in CI

* Add RISC-V and Windows on ARM to ANNOUNCE

* Add comment to why we exclude architectures in qemu-crossbuild

* Remove duplicated entry in ANNOUNCE
  • Loading branch information
hmelder committed Jan 1, 2024
1 parent 0771ddf commit adedd68
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 5 deletions.
14 changes: 13 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
strategy:
matrix:
build-type: [ Release, Debug ]
llvm-version: [13, 14]
llvm-version: [13, 14, 15]
arch:
- name: armhf
system-processor: arm
Expand All @@ -84,6 +84,18 @@ jobs:
system-processor: aarch64
triple: aarch64-linux-gnu
rtld: ld-linux-aarch64.so.1
- name: riscv64
system-processor: riscv64
triple: riscv64-linux-gnu
rtld: ld-linux-riscv64-lp64d.so.1
# lld versions prior to 15 do not support R_RISCV_ALIGN relocations
exclude:
- llvm-version: 13
arch:
name: riscv64
- llvm-version: 14
arch:
name: riscv64
# Don't abort runners if a single one fails
fail-fast: false
runs-on: ubuntu-latest
Expand Down
6 changes: 5 additions & 1 deletion ANNOUNCE
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ programs.

Highlights of this release include:

- Initial support for RISC-V 64-bit (rv64) including an architecture-specific
objc_msgSend, and block trampoline implementation. Please note that
double-precision floating-point support (rv64d) is required for the
objc_msgSend implementation.
- Initial support for Windows on ARM64 with fast-path objc_msgSend.
- Numerous improvements to the Objective-C++ exception interoperation code.
The runtime now dynamically detects whether the libcxxrt, libsupc++, or
libc++abi variant of the Itanium C++ Exception ABI is being used. This is
Expand All @@ -18,7 +23,6 @@ Highlights of this release include:
- The minimum CMake version has been bumped to 3.16, which supports
Objective-C. This support is now used, simplifying the build.
- Support for GC mode is gone. Apple dropped support for this a long time ago.
- Support for Windows on Arm has been added.
- `objc_setUncaughtExceptionHandler` is added, which avoids consuming code
needing to access a library-owned global.
- The selector-table code has been rewritten in C++, improving performance of
Expand Down
18 changes: 18 additions & 0 deletions block_trampolines.S
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@
#define ARG1 $a1
#define ARG2 $a2

#elif defined(__riscv) && (__riscv_xlen == 64)
////////////////////////////////////////////////////////////////////////////////
// RISC-V trampoline
////////////////////////////////////////////////////////////////////////////////
.macro trampoline arg0, arg1
auipc t6, 0xFFFFF // pc + -0x1000
mv \arg1, \arg0
ld \arg0, 0(t6)
ld t6, 8(t6)
jr t6
.endm

#define ARG0 a0
#define ARG1 a1
#define ARG2 a2
#define SARG0 ARG1
#define SARG1 ARG2

#elif defined(__ARM_ARCH_ISA_A64)
////////////////////////////////////////////////////////////////////////////////
// AArch64 (ARM64) trampoline
Expand Down
9 changes: 6 additions & 3 deletions objc/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
#ifndef _OBJC_MESSAGE_H_
#define _OBJC_MESSAGE_H_

#if defined(__x86_64) || defined(__i386) || defined(__arm__) || \
defined(__mips_n64) || defined(__mips_n32) || defined(__ARM_ARCH_ISA_A64)
#if defined(__x86_64) || defined(__i386) || defined(__arm__) || \
defined(__mips_n64) || defined(__mips_n32) || \
defined(__ARM_ARCH_ISA_A64) || \
(defined(__riscv) && __riscv_xlen == 64 && \
defined(__riscv_float_abi_double))
/**
* Standard message sending function. This function must be cast to the
* correct types for the function before use. The first argument is the
Expand Down Expand Up @@ -41,7 +44,7 @@ id objc_msgSend(id self, SEL _cmd, ...);
* integer) structures.
*/
OBJC_PUBLIC
#ifdef __cplusplus
#ifdef __cplusplus
id objc_msgSend_stret(id self, SEL _cmd, ...);
#else
void objc_msgSend_stret(id self, SEL _cmd, ...);
Expand Down
2 changes: 2 additions & 0 deletions objc_msgSend.S
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "objc_msgSend.arm.S"
#elif defined(__ARM_ARCH_ISA_A64)
#include "objc_msgSend.aarch64.S"
#elif defined(__riscv) && (__riscv_xlen == 64) && defined(__riscv_float_abi_double)
#include "objc_msgSend.riscv64.S"
#elif defined(__mips_n64) || defined(__mips_n32)
#include "objc_msgSend.mips.S"
#else
Expand Down
141 changes: 141 additions & 0 deletions objc_msgSend.riscv64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#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 t0, 0(\receiver) // Load class into t0
0:
ld t0, DTABLE_OFFSET(t0) // dtable -> t0
ld t1, 0(\sel) // selector->index -> t1
ld t2, SHIFT_OFFSET(t0) // dtable->shift -> t2

li t3, 8
beq t2, t3, 1f
beqz t2, 2f

srli t2, t1, 16-3 // Extract byte 3 of sel index and multiply by 2^3
and t2, t2, 0x7F8 // Mask target byte
// Example: ((0xCAFEBA >> 13) & 0x7f8) == (0xCA << 3)
add t2, t0, t2 // t2 = dtable address + offset
ld t0, DATA_OFFSET(t2) // Load, adding in the data offset
1:
srli t2, t1, 8-3 // Extract byte 2 of sel index and multiply by 2^3
and t2, t2, 0x7F8 // Mask target byte
add t2, t0, t2 // t2 = dtable address + offset
ld t0, DATA_OFFSET(t2) // Load, adding in the data offset
2:
slli t2, t1, 3 // Multiply by 2^3
and t2, t2, 0x7F8 // Mask target byte
add t2, t0, t2 // t2 = dtable address + offset
ld t0, DATA_OFFSET(t2) // Load, adding in the data offset
// Slot pointer is now in t0

beqz t0, 4f // If the slot is nil, go to the C path

ld t0, SLOT_OFFSET(t0) // Load the method from the slot
jalr zero, t0, 0 // Tail-call the method

3:
li \receiver, 0
li \sel, 0
fmv.d.x fa0, zero
fmv.d.x fa1, zero
jalr zero, ra, 0

4:
add sp, sp, -(ARGUMENT_SPILL_SIZE)

// Spill function arguments
sd a0, 0(sp)
sd a1, 8(sp)
sd a2, 16(sp)
sd a3, 24(sp)
sd a4, 32(sp)
sd a5, 40(sp)
sd a6, 48(sp)
sd a7, 56(sp)

// Spill FP arguments
fsd fa0, 64(sp)
fsd fa1, 72(sp)
fsd fa2, 80(sp)
fsd fa3, 88(sp)
fsd fa4, 96(sp)
fsd fa5, 104(sp)
fsd fa6, 112(sp)
fsd fa7, 120(sp)

sd fp, 128(sp)
sd ra, 136(sp)

add fp, sp, 128
add sp, sp, -16

sd \receiver, 0(sp) // it is convenient if \receiver is spilled at sp

.cfi_def_cfa fp, 16
.cfi_offset fp, -16
.cfi_offset ra, -8

add a0, sp, zero // &self in first argument
call CDECL(slowMsgLookup)

add t0, a0, zero // IMP -> t0

ld a0, 16(sp)
ld a1, 24(sp)
ld a2, 32(sp)
ld a3, 40(sp)
ld a4, 48(sp)
ld a5, 56(sp)
ld a6, 64(sp)
ld a7, 72(sp)

fld fa0, 80(sp)
fld fa1, 88(sp)
fld fa2, 96(sp)
fld fa3, 104(sp)
fld fa4, 112(sp)
fld fa5, 120(sp)
fld fa6, 128(sp)
fld fa7, 136(sp)

ld fp, 144(sp)
ld ra, 152(sp)

ld \receiver, 0(sp)

add sp, sp, ARGUMENT_SPILL_SIZE
add sp, sp, 16

jalr zero, t0, 0 // Tail-call the method

5:
// Load address of SmallObjectClasses
auipc t1, %pcrel_hi(CDECL(SmallObjectClasses))
addi t1, t1, %pcrel_lo(5b)

// Calculate array offset (INDEX * 2^3)
slli t0, t0, 3
add t0, t1, t0

ld t0, 0(t0)

j 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)
CDECL(objc_msgSend):
CDECL(objc_msgSend_fpret):
MSGSEND a0, a1
CDECL(objc_msgSend_stret):
MSGSEND a1, a2 // Pointer to stack frame in a0

0 comments on commit adedd68

Please sign in to comment.