Skip to content

Commit

Permalink
[RISCV] Add support for static chain
Browse files Browse the repository at this point in the history
The static chain parameter is a special parameter that is not passed in the usual argument registers or stack space. For example, in x64 System V ABI it is always passed in R10. Although the ABI of RISCV does not assign a register for this purpose, GCC had support for it on RISC-V a long time ago, and it is exposed via `__builtin_call_with_static_chain` intrinsic, and assign t2 for static chain parameters. This patch also chose t2 for compatibility.

In LLVM, static chain parameters are handled by the `nest` attribute of an argument to a function ([D6332](https://reviews.llvm.org/D6332)), so tests are added to ensure `nest` arguments are handled correctly.

Reviewed By: kito-cheng, MaskRay

Differential Revision: https://reviews.llvm.org/D129106
  • Loading branch information
melonedo committed Nov 9, 2022
1 parent 000588d commit f4f6c63
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
14 changes: 14 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Expand Up @@ -11078,6 +11078,15 @@ static bool CC_RISCV(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo,
assert(XLen == 32 || XLen == 64);
MVT XLenVT = XLen == 32 ? MVT::i32 : MVT::i64;

// Static chain parameter must not be passed in normal argument registers,
// so we assign t2 for it as done in GCC's __builtin_call_with_static_chain
if (ArgFlags.isNest()) {
if (unsigned Reg = State.AllocateReg(RISCV::X7)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}

// Any return value split in to more than two values can't be returned
// directly. Vectors are returned via the available vector registers.
if (!LocVT.isVector() && IsRet && ValNo > 1)
Expand Down Expand Up @@ -11618,6 +11627,11 @@ static bool CC_RISCV_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {

if (ArgFlags.isNest()) {
report_fatal_error(
"Attribute 'nest' is not supported in GHC calling convention");
}

if (LocVT == MVT::i32 || LocVT == MVT::i64) {
// Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, R6, R7, SpLim
// s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
Expand Down
13 changes: 13 additions & 0 deletions llvm/test/CodeGen/RISCV/ghccc-nest.ll
@@ -0,0 +1,13 @@
; RUN: not --crash llc -mtriple=riscv64 -mattr=+f,+d -verify-machineinstrs -filetype=null < %s 2>&1 | FileCheck %s
; RUN: not --crash llc -mtriple=riscv32 -mattr=+f,+d -verify-machineinstrs -filetype=null < %s 2>&1 | FileCheck %s

define ghccc ptr @nest_receiver(ptr nest %arg) nounwind {
ret ptr %arg
}

define ghccc ptr @nest_caller(ptr %arg) nounwind {
%result = call ghccc ptr @nest_receiver(ptr nest %arg)
ret ptr %result
}

; CHECK: LLVM ERROR: Attribute 'nest' is not supported in GHC calling convention
47 changes: 47 additions & 0 deletions llvm/test/CodeGen/RISCV/nest-register.ll
@@ -0,0 +1,47 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32I %s
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV64I %s

; Tests that the 'nest' parameter attribute causes the relevant parameter to be
; passed in the right register.

define ptr @nest_receiver(ptr nest %arg) nounwind {
; RV32I-LABEL: nest_receiver:
; RV32I: # %bb.0:
; RV32I-NEXT: mv a0, t2
; RV32I-NEXT: ret
;
; RV64I-LABEL: nest_receiver:
; RV64I: # %bb.0:
; RV64I-NEXT: mv a0, t2
; RV64I-NEXT: ret
;
ret ptr %arg
}

define ptr @nest_caller(ptr %arg) nounwind {
; RV32I-LABEL: nest_caller:
; RV32I: # %bb.0:
; RV32I-NEXT: addi sp, sp, -16
; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32I-NEXT: mv t2, a0
; RV32I-NEXT: call nest_receiver@plt
; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32I-NEXT: addi sp, sp, 16
; RV32I-NEXT: ret
;
; RV64I-LABEL: nest_caller:
; RV64I: # %bb.0:
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
; RV64I-NEXT: mv t2, a0
; RV64I-NEXT: call nest_receiver@plt
; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
;
%result = call ptr @nest_receiver(ptr nest %arg)
ret ptr %result
}

0 comments on commit f4f6c63

Please sign in to comment.