[llvm] a8dc211 - [RISCV] Add GHC calling convention
Luís Marques via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 24 14:36:02 PST 2020
Author: Luís Marques
Date: 2020-11-24T22:35:23Z
New Revision: a8dc2110cd4dd69212a204bc1074729f95d5402a
URL: https://github.com/llvm/llvm-project/commit/a8dc2110cd4dd69212a204bc1074729f95d5402a
DIFF: https://github.com/llvm/llvm-project/commit/a8dc2110cd4dd69212a204bc1074729f95d5402a.diff
LOG: [RISCV] Add GHC calling convention
This is a special calling convention to be used by the GHC compiler.
Patch by Andreas Schwab (schwab)
Differential Revision: https://reviews.llvm.org/D89788
Added:
llvm/test/CodeGen/RISCV/ghccc-rv32.ll
llvm/test/CodeGen/RISCV/ghccc-rv64.ll
Modified:
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 439f138defcd..9222146c5909 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -325,6 +325,11 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
// to determine the end of the prologue.
DebugLoc DL;
+ // All calls are tail calls in GHC calling conv, and functions have no
+ // prologue/epilogue.
+ if (MF.getFunction().getCallingConv() == CallingConv::GHC)
+ return;
+
// Emit prologue for shadow call stack.
emitSCSPrologue(MF, MBB, MBBI, DL);
@@ -500,6 +505,11 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
Register FPReg = getFPReg(STI);
Register SPReg = getSPReg(STI);
+ // All calls are tail calls in GHC calling conv, and functions have no
+ // prologue/epilogue.
+ if (MF.getFunction().getCallingConv() == CallingConv::GHC)
+ return;
+
// Get the insert location for the epilogue. If there were no terminators in
// the block, get the last instruction.
MachineBasicBlock::iterator MBBI = MBB.end();
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0eb748b3a3c0..15bd35e72e9a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -665,6 +665,10 @@ SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
TLSModel::Model Model = getTargetMachine().getTLSModel(N->getGlobal());
+ if (DAG.getMachineFunction().getFunction().getCallingConv() ==
+ CallingConv::GHC)
+ report_fatal_error("In GHC calling convention TLS is not supported");
+
SDValue Addr;
switch (Model) {
case TLSModel::LocalExec:
@@ -2240,22 +2244,71 @@ static bool CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT,
return true; // CC didn't match.
}
+static bool CC_RISCV_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
+ CCValAssign::LocInfo LocInfo,
+ ISD::ArgFlagsTy ArgFlags, CCState &State) {
+
+ 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
+ static const MCPhysReg GPRList[] = {
+ RISCV::X9, RISCV::X18, RISCV::X19, RISCV::X20, RISCV::X21, RISCV::X22,
+ RISCV::X23, RISCV::X24, RISCV::X25, RISCV::X26, RISCV::X27};
+ if (unsigned Reg = State.AllocateReg(GPRList)) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
+ if (LocVT == MVT::f32) {
+ // Pass in STG registers: F1, ..., F6
+ // fs0 ... fs5
+ static const MCPhysReg FPR32List[] = {RISCV::F8_F, RISCV::F9_F,
+ RISCV::F18_F, RISCV::F19_F,
+ RISCV::F20_F, RISCV::F21_F};
+ if (unsigned Reg = State.AllocateReg(FPR32List)) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
+ if (LocVT == MVT::f64) {
+ // Pass in STG registers: D1, ..., D6
+ // fs6 ... fs11
+ static const MCPhysReg FPR64List[] = {RISCV::F22_D, RISCV::F23_D,
+ RISCV::F24_D, RISCV::F25_D,
+ RISCV::F26_D, RISCV::F27_D};
+ if (unsigned Reg = State.AllocateReg(FPR64List)) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
+ report_fatal_error("No registers left in GHC calling convention");
+ return true;
+}
+
// Transform physical registers into virtual registers.
SDValue RISCVTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+
switch (CallConv) {
default:
report_fatal_error("Unsupported calling convention");
case CallingConv::C:
case CallingConv::Fast:
break;
+ case CallingConv::GHC:
+ if (!MF.getSubtarget().getFeatureBits()[RISCV::FeatureStdExtF] ||
+ !MF.getSubtarget().getFeatureBits()[RISCV::FeatureStdExtD])
+ report_fatal_error(
+ "GHC calling convention requires the F and D instruction set extensions");
}
- MachineFunction &MF = DAG.getMachineFunction();
-
const Function &Func = MF.getFunction();
if (Func.hasFnAttribute("interrupt")) {
if (!Func.arg_empty())
@@ -2282,6 +2335,8 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
if (CallConv == CallingConv::Fast)
CCInfo.AnalyzeFormalArguments(Ins, CC_RISCV_FastCC);
+ else if (CallConv == CallingConv::GHC)
+ CCInfo.AnalyzeFormalArguments(Ins, CC_RISCV_GHC);
else
analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false);
@@ -2482,6 +2537,8 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI,
if (CallConv == CallingConv::Fast)
ArgCCInfo.AnalyzeCallOperands(Outs, CC_RISCV_FastCC);
+ else if (CallConv == CallingConv::GHC)
+ ArgCCInfo.AnalyzeCallOperands(Outs, CC_RISCV_GHC);
else
analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI);
@@ -2769,6 +2826,9 @@ RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
nullptr);
+ if (CallConv == CallingConv::GHC && !RVLocs.empty())
+ report_fatal_error("GHC functions return void only");
+
SDValue Glue;
SmallVector<SDValue, 4> RetOps(1, Chain);
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 97475e807526..05a2bd3f1feb 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -45,6 +45,8 @@ RISCVRegisterInfo::RISCVRegisterInfo(unsigned HwMode)
const MCPhysReg *
RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
auto &Subtarget = MF->getSubtarget<RISCVSubtarget>();
+ if (MF->getFunction().getCallingConv() == CallingConv::GHC)
+ return CSR_NoRegs_SaveList;
if (MF->getFunction().hasFnAttribute("interrupt")) {
if (Subtarget.hasStdExtD())
return CSR_XLEN_F64_Interrupt_SaveList;
@@ -191,9 +193,11 @@ Register RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
const uint32_t *
RISCVRegisterInfo::getCallPreservedMask(const MachineFunction & MF,
- CallingConv::ID /*CC*/) const {
+ CallingConv::ID CC) const {
auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
+ if (CC == CallingConv::GHC)
+ return CSR_NoRegs_RegMask;
switch (Subtarget.getTargetABI()) {
default:
llvm_unreachable("Unrecognized ABI");
diff --git a/llvm/test/CodeGen/RISCV/ghccc-rv32.ll b/llvm/test/CodeGen/RISCV/ghccc-rv32.ll
new file mode 100644
index 000000000000..1d7b05ba3b9a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/ghccc-rv32.ll
@@ -0,0 +1,114 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+f,+d < %s | FileCheck %s
+
+; Check the GHC call convention works (rv32)
+
+ at base = external global i32 ; assigned to register: s1
+ at sp = external global i32 ; assigned to register: s2
+ at hp = external global i32 ; assigned to register: s3
+ at r1 = external global i32 ; assigned to register: s4
+ at r2 = external global i32 ; assigned to register: s5
+ at r3 = external global i32 ; assigned to register: s6
+ at r4 = external global i32 ; assigned to register: s7
+ at r5 = external global i32 ; assigned to register: s8
+ at r6 = external global i32 ; assigned to register: s9
+ at r7 = external global i32 ; assigned to register: s10
+ at splim = external global i32 ; assigned to register: s11
+
+ at f1 = external global float ; assigned to register: fs0
+ at f2 = external global float ; assigned to register: fs1
+ at f3 = external global float ; assigned to register: fs2
+ at f4 = external global float ; assigned to register: fs3
+ at f5 = external global float ; assigned to register: fs4
+ at f6 = external global float ; assigned to register: fs5
+
+ at d1 = external global double ; assigned to register: fs6
+ at d2 = external global double ; assigned to register: fs7
+ at d3 = external global double ; assigned to register: fs8
+ at d4 = external global double ; assigned to register: fs9
+ at d5 = external global double ; assigned to register: fs10
+ at d6 = external global double ; assigned to register: fs11
+
+define ghccc void @foo() nounwind {
+; CHECK-LABEL: foo:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lui a0, %hi(d6)
+; CHECK-NEXT: fld fs11, %lo(d6)(a0)
+; CHECK-NEXT: lui a0, %hi(d5)
+; CHECK-NEXT: fld fs10, %lo(d5)(a0)
+; CHECK-NEXT: lui a0, %hi(d4)
+; CHECK-NEXT: fld fs9, %lo(d4)(a0)
+; CHECK-NEXT: lui a0, %hi(d3)
+; CHECK-NEXT: fld fs8, %lo(d3)(a0)
+; CHECK-NEXT: lui a0, %hi(d2)
+; CHECK-NEXT: fld fs7, %lo(d2)(a0)
+; CHECK-NEXT: lui a0, %hi(d1)
+; CHECK-NEXT: fld fs6, %lo(d1)(a0)
+; CHECK-NEXT: lui a0, %hi(f6)
+; CHECK-NEXT: flw fs5, %lo(f6)(a0)
+; CHECK-NEXT: lui a0, %hi(f5)
+; CHECK-NEXT: flw fs4, %lo(f5)(a0)
+; CHECK-NEXT: lui a0, %hi(f4)
+; CHECK-NEXT: flw fs3, %lo(f4)(a0)
+; CHECK-NEXT: lui a0, %hi(f3)
+; CHECK-NEXT: flw fs2, %lo(f3)(a0)
+; CHECK-NEXT: lui a0, %hi(f2)
+; CHECK-NEXT: flw fs1, %lo(f2)(a0)
+; CHECK-NEXT: lui a0, %hi(f1)
+; CHECK-NEXT: flw fs0, %lo(f1)(a0)
+; CHECK-NEXT: lui a0, %hi(splim)
+; CHECK-NEXT: lw s11, %lo(splim)(a0)
+; CHECK-NEXT: lui a0, %hi(r7)
+; CHECK-NEXT: lw s10, %lo(r7)(a0)
+; CHECK-NEXT: lui a0, %hi(r6)
+; CHECK-NEXT: lw s9, %lo(r6)(a0)
+; CHECK-NEXT: lui a0, %hi(r5)
+; CHECK-NEXT: lw s8, %lo(r5)(a0)
+; CHECK-NEXT: lui a0, %hi(r4)
+; CHECK-NEXT: lw s7, %lo(r4)(a0)
+; CHECK-NEXT: lui a0, %hi(r3)
+; CHECK-NEXT: lw s6, %lo(r3)(a0)
+; CHECK-NEXT: lui a0, %hi(r2)
+; CHECK-NEXT: lw s5, %lo(r2)(a0)
+; CHECK-NEXT: lui a0, %hi(r1)
+; CHECK-NEXT: lw s4, %lo(r1)(a0)
+; CHECK-NEXT: lui a0, %hi(hp)
+; CHECK-NEXT: lw s3, %lo(hp)(a0)
+; CHECK-NEXT: lui a0, %hi(sp)
+; CHECK-NEXT: lw s2, %lo(sp)(a0)
+; CHECK-NEXT: lui a0, %hi(base)
+; CHECK-NEXT: lw s1, %lo(base)(a0)
+; CHECK-NEXT: tail bar
+entry:
+ %0 = load double, double* @d6
+ %1 = load double, double* @d5
+ %2 = load double, double* @d4
+ %3 = load double, double* @d3
+ %4 = load double, double* @d2
+ %5 = load double, double* @d1
+ %6 = load float, float* @f6
+ %7 = load float, float* @f5
+ %8 = load float, float* @f4
+ %9 = load float, float* @f3
+ %10 = load float, float* @f2
+ %11 = load float, float* @f1
+ %12 = load i32, i32* @splim
+ %13 = load i32, i32* @r7
+ %14 = load i32, i32* @r6
+ %15 = load i32, i32* @r5
+ %16 = load i32, i32* @r4
+ %17 = load i32, i32* @r3
+ %18 = load i32, i32* @r2
+ %19 = load i32, i32* @r1
+ %20 = load i32, i32* @hp
+ %21 = load i32, i32* @sp
+ %22 = load i32, i32* @base
+ tail call ghccc void @bar(i32 %22, i32 %21, i32 %20, i32 %19, i32 %18, i32 %17, i32 %16, i32 %15, i32 %14, i32 %13, i32 %12,
+ float %11, float %10, float %9, float %8, float %7, float %6,
+ double %5, double %4, double %3, double %2, double %1, double %0) nounwind
+ ret void
+}
+
+declare ghccc void @bar(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
+ float, float, float, float, float, float,
+ double, double, double, double, double, double)
diff --git a/llvm/test/CodeGen/RISCV/ghccc-rv64.ll b/llvm/test/CodeGen/RISCV/ghccc-rv64.ll
new file mode 100644
index 000000000000..aaca2e102a79
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/ghccc-rv64.ll
@@ -0,0 +1,114 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+f,+d < %s | FileCheck %s
+
+; Check the GHC call convention works (rv64)
+
+ at base = external global i64 ; assigned to register: s1
+ at sp = external global i64 ; assigned to register: s2
+ at hp = external global i64 ; assigned to register: s3
+ at r1 = external global i64 ; assigned to register: s4
+ at r2 = external global i64 ; assigned to register: s5
+ at r3 = external global i64 ; assigned to register: s6
+ at r4 = external global i64 ; assigned to register: s7
+ at r5 = external global i64 ; assigned to register: s8
+ at r6 = external global i64 ; assigned to register: s9
+ at r7 = external global i64 ; assigned to register: s10
+ at splim = external global i64 ; assigned to register: s11
+
+ at f1 = external global float ; assigned to register: fs0
+ at f2 = external global float ; assigned to register: fs1
+ at f3 = external global float ; assigned to register: fs2
+ at f4 = external global float ; assigned to register: fs3
+ at f5 = external global float ; assigned to register: fs4
+ at f6 = external global float ; assigned to register: fs5
+
+ at d1 = external global double ; assigned to register: fs6
+ at d2 = external global double ; assigned to register: fs7
+ at d3 = external global double ; assigned to register: fs8
+ at d4 = external global double ; assigned to register: fs9
+ at d5 = external global double ; assigned to register: fs10
+ at d6 = external global double ; assigned to register: fs11
+
+define ghccc void @foo() nounwind {
+; CHECK-LABEL: foo:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lui a0, %hi(d6)
+; CHECK-NEXT: fld fs11, %lo(d6)(a0)
+; CHECK-NEXT: lui a0, %hi(d5)
+; CHECK-NEXT: fld fs10, %lo(d5)(a0)
+; CHECK-NEXT: lui a0, %hi(d4)
+; CHECK-NEXT: fld fs9, %lo(d4)(a0)
+; CHECK-NEXT: lui a0, %hi(d3)
+; CHECK-NEXT: fld fs8, %lo(d3)(a0)
+; CHECK-NEXT: lui a0, %hi(d2)
+; CHECK-NEXT: fld fs7, %lo(d2)(a0)
+; CHECK-NEXT: lui a0, %hi(d1)
+; CHECK-NEXT: fld fs6, %lo(d1)(a0)
+; CHECK-NEXT: lui a0, %hi(f6)
+; CHECK-NEXT: flw fs5, %lo(f6)(a0)
+; CHECK-NEXT: lui a0, %hi(f5)
+; CHECK-NEXT: flw fs4, %lo(f5)(a0)
+; CHECK-NEXT: lui a0, %hi(f4)
+; CHECK-NEXT: flw fs3, %lo(f4)(a0)
+; CHECK-NEXT: lui a0, %hi(f3)
+; CHECK-NEXT: flw fs2, %lo(f3)(a0)
+; CHECK-NEXT: lui a0, %hi(f2)
+; CHECK-NEXT: flw fs1, %lo(f2)(a0)
+; CHECK-NEXT: lui a0, %hi(f1)
+; CHECK-NEXT: flw fs0, %lo(f1)(a0)
+; CHECK-NEXT: lui a0, %hi(splim)
+; CHECK-NEXT: ld s11, %lo(splim)(a0)
+; CHECK-NEXT: lui a0, %hi(r7)
+; CHECK-NEXT: ld s10, %lo(r7)(a0)
+; CHECK-NEXT: lui a0, %hi(r6)
+; CHECK-NEXT: ld s9, %lo(r6)(a0)
+; CHECK-NEXT: lui a0, %hi(r5)
+; CHECK-NEXT: ld s8, %lo(r5)(a0)
+; CHECK-NEXT: lui a0, %hi(r4)
+; CHECK-NEXT: ld s7, %lo(r4)(a0)
+; CHECK-NEXT: lui a0, %hi(r3)
+; CHECK-NEXT: ld s6, %lo(r3)(a0)
+; CHECK-NEXT: lui a0, %hi(r2)
+; CHECK-NEXT: ld s5, %lo(r2)(a0)
+; CHECK-NEXT: lui a0, %hi(r1)
+; CHECK-NEXT: ld s4, %lo(r1)(a0)
+; CHECK-NEXT: lui a0, %hi(hp)
+; CHECK-NEXT: ld s3, %lo(hp)(a0)
+; CHECK-NEXT: lui a0, %hi(sp)
+; CHECK-NEXT: ld s2, %lo(sp)(a0)
+; CHECK-NEXT: lui a0, %hi(base)
+; CHECK-NEXT: ld s1, %lo(base)(a0)
+; CHECK-NEXT: tail bar
+entry:
+ %0 = load double, double* @d6
+ %1 = load double, double* @d5
+ %2 = load double, double* @d4
+ %3 = load double, double* @d3
+ %4 = load double, double* @d2
+ %5 = load double, double* @d1
+ %6 = load float, float* @f6
+ %7 = load float, float* @f5
+ %8 = load float, float* @f4
+ %9 = load float, float* @f3
+ %10 = load float, float* @f2
+ %11 = load float, float* @f1
+ %12 = load i64, i64* @splim
+ %13 = load i64, i64* @r7
+ %14 = load i64, i64* @r6
+ %15 = load i64, i64* @r5
+ %16 = load i64, i64* @r4
+ %17 = load i64, i64* @r3
+ %18 = load i64, i64* @r2
+ %19 = load i64, i64* @r1
+ %20 = load i64, i64* @hp
+ %21 = load i64, i64* @sp
+ %22 = load i64, i64* @base
+ tail call ghccc void @bar(i64 %22, i64 %21, i64 %20, i64 %19, i64 %18, i64 %17, i64 %16, i64 %15, i64 %14, i64 %13, i64 %12,
+ float %11, float %10, float %9, float %8, float %7, float %6,
+ double %5, double %4, double %3, double %2, double %1, double %0) nounwind
+ ret void
+}
+
+declare ghccc void @bar(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64,
+ float, float, float, float, float, float,
+ double, double, double, double, double, double)
More information about the llvm-commits
mailing list