[llvm] 389079c - [LoongArch] Add GHC Calling Convention
Weining Lu via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 26 03:37:11 PST 2022
Author: Lin Runze
Date: 2022-12-26T19:36:41+08:00
New Revision: 389079c87c826df9c0a089994d0fea50e6613a9f
URL: https://github.com/llvm/llvm-project/commit/389079c87c826df9c0a089994d0fea50e6613a9f
DIFF: https://github.com/llvm/llvm-project/commit/389079c87c826df9c0a089994d0fea50e6613a9f.diff
LOG: [LoongArch] Add GHC Calling Convention
This is modeled after [[ https://reviews.llvm.org/D89788 | the RISCV GHC calling convention]]
and matches [[ https://gitlab.haskell.org/ghc/ghc/-/merge_requests/9292 | the corresponding GHC change ]].
Reviewed By: xen0n, wangleiat
Differential Revision: https://reviews.llvm.org/D137495
Added:
llvm/test/CodeGen/LoongArch/ghc-cc.ll
Modified:
llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
index ad9196ac8c2f8..3bba2d658ec5e 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
@@ -191,7 +191,10 @@ void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
// Debug location must be unknown since the first debug location is used
// 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;
// Determine the correct frame layout
determineFrameLayout(MF);
@@ -322,7 +325,10 @@ void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
MachineFrameInfo &MFI = MF.getFrameInfo();
auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
Register SPReg = LoongArch::R3;
-
+ // All calls are tail calls in GHC calling conv, and functions have no
+ // prologue/epilogue.
+ if (MF.getFunction().getCallingConv() == CallingConv::GHC)
+ return;
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 2268e5e3f443e..fc06fc9226dee 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -556,6 +556,10 @@ LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
SDValue Addr;
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");
+
switch (Model) {
case TLSModel::GeneralDynamic:
// In this model, application code calls the dynamic linker function
@@ -2043,6 +2047,47 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
return Val;
}
+static bool CC_LoongArch_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, SpLim
+ // s0 s1 s2 s3 s4 s5 s6 s7 s8
+ static const MCPhysReg GPRList[] = {
+ LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26, LoongArch::R27,
+ LoongArch::R28, LoongArch::R29, LoongArch::R30, LoongArch::R31};
+ 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, F2, F3, F4
+ // fs0,fs1,fs2,fs3
+ static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
+ LoongArch::F26, LoongArch::F27};
+ 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, D2, D3, D4
+ // fs4,fs5,fs6,fs7
+ static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
+ LoongArch::F30_64, LoongArch::F31_64};
+ 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 LoongArchTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
@@ -2057,6 +2102,11 @@ SDValue LoongArchTargetLowering::LowerFormalArguments(
case CallingConv::C:
case CallingConv::Fast:
break;
+ case CallingConv::GHC:
+ if (!MF.getSubtarget().getFeatureBits()[LoongArch::FeatureBasicF] ||
+ !MF.getSubtarget().getFeatureBits()[LoongArch::FeatureBasicD])
+ report_fatal_error(
+ "GHC calling convention requires the F and D extensions");
}
EVT PtrVT = getPointerTy(DAG.getDataLayout());
@@ -2069,7 +2119,10 @@ SDValue LoongArchTargetLowering::LowerFormalArguments(
SmallVector<CCValAssign> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
- analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
+ if (CallConv == CallingConv::GHC)
+ CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC);
+ else
+ analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
@@ -2237,7 +2290,10 @@ LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
SmallVector<CCValAssign> ArgLocs;
CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
- analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
+ if (CallConv == CallingConv::GHC)
+ ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
+ else
+ analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
// Check if it's really possible to do a tail call.
if (IsTailCall)
@@ -2480,7 +2536,8 @@ SDValue LoongArchTargetLowering::LowerReturn(
analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
nullptr, CC_LoongArch);
-
+ 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/LoongArch/LoongArchRegisterInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
index f84303232875c..4037c4d370bb8 100644
--- a/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
@@ -38,6 +38,8 @@ const MCPhysReg *
LoongArchRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
auto &Subtarget = MF->getSubtarget<LoongArchSubtarget>();
+ if (MF->getFunction().getCallingConv() == CallingConv::GHC)
+ return CSR_NoRegs_SaveList;
switch (Subtarget.getTargetABI()) {
default:
llvm_unreachable("Unrecognized ABI");
@@ -58,6 +60,8 @@ LoongArchRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
auto &Subtarget = MF.getSubtarget<LoongArchSubtarget>();
+ if (CC == CallingConv::GHC)
+ return CSR_NoRegs_RegMask;
switch (Subtarget.getTargetABI()) {
default:
llvm_unreachable("Unrecognized ABI");
diff --git a/llvm/test/CodeGen/LoongArch/ghc-cc.ll b/llvm/test/CodeGen/LoongArch/ghc-cc.ll
new file mode 100644
index 0000000000000..fb67ea565bfa3
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/ghc-cc.ll
@@ -0,0 +1,108 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch64 --mattr=+f,+d < %s | FileCheck %s --check-prefix=LA64
+
+; Check the GHC call convention works (la64)
+
+ at base = external dso_local global i64 ; assigned to register: s0
+ at sp = external dso_local global i64 ; assigned to register: s1
+ at hp = external dso_local global i64 ; assigned to register: s2
+ at r1 = external dso_local global i64 ; assigned to register: s3
+ at r2 = external dso_local global i64 ; assigned to register: s4
+ at r3 = external dso_local global i64 ; assigned to register: s5
+ at r4 = external dso_local global i64 ; assigned to register: s6
+ at r5 = external dso_local global i64 ; assigned to register: s7
+ at splim = external dso_local global i64 ; assigned to register: s8
+
+ at f1 = external dso_local global float ; assigned to register: fs0
+ at f2 = external dso_local global float ; assigned to register: fs1
+ at f3 = external dso_local global float ; assigned to register: fs2
+ at f4 = external dso_local global float ; assigned to register: fs3
+
+ at d1 = external dso_local global double ; assigned to register: fs4
+ at d2 = external dso_local global double ; assigned to register: fs5
+ at d3 = external dso_local global double ; assigned to register: fs6
+ at d4 = external dso_local global double ; assigned to register: fs7
+
+define ghccc void @foo() nounwind {
+; LA64-LABEL: foo:
+; LA64: # %bb.0: # %entry
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(base)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(base)
+; LA64-NEXT: ld.d $s0, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(sp)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(sp)
+; LA64-NEXT: ld.d $s1, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(hp)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(hp)
+; LA64-NEXT: ld.d $s2, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(r1)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(r1)
+; LA64-NEXT: ld.d $s3, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(r2)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(r2)
+; LA64-NEXT: ld.d $s4, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(r3)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(r3)
+; LA64-NEXT: ld.d $s5, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(r4)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(r4)
+; LA64-NEXT: ld.d $s6, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(r5)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(r5)
+; LA64-NEXT: ld.d $s7, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(splim)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(splim)
+; LA64-NEXT: ld.d $s8, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(f1)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(f1)
+; LA64-NEXT: fld.s $fs0, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(f2)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(f2)
+; LA64-NEXT: fld.s $fs1, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(f3)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(f3)
+; LA64-NEXT: fld.s $fs2, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(f4)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(f4)
+; LA64-NEXT: fld.s $fs3, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(d1)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(d1)
+; LA64-NEXT: fld.d $fs4, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(d2)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(d2)
+; LA64-NEXT: fld.d $fs5, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(d3)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(d3)
+; LA64-NEXT: fld.d $fs6, $a0, 0
+; LA64-NEXT: pcalau12i $a0, %pc_hi20(d4)
+; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(d4)
+; LA64-NEXT: fld.d $fs7, $a0, 0
+; LA64-NEXT: b %plt(bar)
+; LA64-NEXT: ret
+
+entry:
+ %0 = load double, ptr @d4
+ %1 = load double, ptr @d3
+ %2 = load double, ptr @d2
+ %3 = load double, ptr @d1
+ %4 = load float, ptr @f4
+ %5 = load float, ptr @f3
+ %6 = load float, ptr @f2
+ %7 = load float, ptr @f1
+ %8 = load i64, ptr @splim
+ %9 = load i64, ptr @r5
+ %10 = load i64, ptr @r4
+ %11 = load i64, ptr @r3
+ %12 = load i64, ptr @r2
+ %13 = load i64, ptr @r1
+ %14 = load i64, ptr @hp
+ %15 = load i64, ptr @sp
+ %16 = load i64, ptr @base
+ tail call ghccc void @bar(i64 %16, i64 %15, i64 %14, i64 %13, i64 %12,
+ i64 %11, i64 %10, i64 %9, i64 %8, float %7, float %6,
+ float %5, float %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,
+ float, float, float, float,
+ double, double, double, double)
More information about the llvm-commits
mailing list