1*06c3fb27SDimitry Andric //===-- PPCCallingConv.cpp - ------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "PPCRegisterInfo.h"
100b57cec5SDimitry Andric #include "PPCCallingConv.h"
110b57cec5SDimitry Andric #include "PPCSubtarget.h"
120b57cec5SDimitry Andric #include "PPCCCState.h"
130b57cec5SDimitry Andric using namespace llvm;
140b57cec5SDimitry Andric
CC_PPC_AnyReg_Error(unsigned &,MVT &,MVT &,CCValAssign::LocInfo &,ISD::ArgFlagsTy &,CCState &)150b57cec5SDimitry Andric inline bool CC_PPC_AnyReg_Error(unsigned &, MVT &, MVT &,
160b57cec5SDimitry Andric CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
170b57cec5SDimitry Andric CCState &) {
180b57cec5SDimitry Andric llvm_unreachable("The AnyReg calling convention is only supported by the " \
190b57cec5SDimitry Andric "stackmap and patchpoint intrinsics.");
200b57cec5SDimitry Andric // gracefully fallback to PPC C calling convention on Release builds.
210b57cec5SDimitry Andric return false;
220b57cec5SDimitry Andric }
230b57cec5SDimitry Andric
24*06c3fb27SDimitry Andric // This function handles the shadowing of GPRs for fp and vector types,
25*06c3fb27SDimitry Andric // and is a depiction of the algorithm described in the ELFv2 ABI,
26*06c3fb27SDimitry Andric // Section 2.2.4.1: Parameter Passing Register Selection Algorithm.
CC_PPC64_ELF_Shadow_GPR_Regs(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)27*06c3fb27SDimitry Andric inline bool CC_PPC64_ELF_Shadow_GPR_Regs(unsigned &ValNo, MVT &ValVT,
28*06c3fb27SDimitry Andric MVT &LocVT,
29*06c3fb27SDimitry Andric CCValAssign::LocInfo &LocInfo,
30*06c3fb27SDimitry Andric ISD::ArgFlagsTy &ArgFlags,
31*06c3fb27SDimitry Andric CCState &State) {
32*06c3fb27SDimitry Andric
33*06c3fb27SDimitry Andric // The 64-bit ELFv2 ABI-defined parameter passing general purpose registers.
34*06c3fb27SDimitry Andric static const MCPhysReg ELF64ArgGPRs[] = {PPC::X3, PPC::X4, PPC::X5, PPC::X6,
35*06c3fb27SDimitry Andric PPC::X7, PPC::X8, PPC::X9, PPC::X10};
36*06c3fb27SDimitry Andric const unsigned ELF64NumArgGPRs = std::size(ELF64ArgGPRs);
37*06c3fb27SDimitry Andric
38*06c3fb27SDimitry Andric unsigned FirstUnallocGPR = State.getFirstUnallocated(ELF64ArgGPRs);
39*06c3fb27SDimitry Andric if (FirstUnallocGPR == ELF64NumArgGPRs)
40*06c3fb27SDimitry Andric return false;
41*06c3fb27SDimitry Andric
42*06c3fb27SDimitry Andric // As described in 2.2.4.1 under the "float" section, shadow a single GPR
43*06c3fb27SDimitry Andric // for single/double precision. ppcf128 gets broken up into two doubles
44*06c3fb27SDimitry Andric // and will also shadow GPRs within this section.
45*06c3fb27SDimitry Andric if (LocVT == MVT::f32 || LocVT == MVT::f64)
46*06c3fb27SDimitry Andric State.AllocateReg(ELF64ArgGPRs);
47*06c3fb27SDimitry Andric else if (LocVT.is128BitVector() || (LocVT == MVT::f128)) {
48*06c3fb27SDimitry Andric // For vector and __float128 (which is represents the "vector" section
49*06c3fb27SDimitry Andric // in 2.2.4.1), shadow two even GPRs (skipping the odd one if it is next
50*06c3fb27SDimitry Andric // in the allocation order). To check if the GPR is even, the specific
51*06c3fb27SDimitry Andric // condition checks if the register allocated is odd, because the even
52*06c3fb27SDimitry Andric // physical registers are odd values.
53*06c3fb27SDimitry Andric if ((State.AllocateReg(ELF64ArgGPRs) - PPC::X3) % 2 == 1)
54*06c3fb27SDimitry Andric State.AllocateReg(ELF64ArgGPRs);
55*06c3fb27SDimitry Andric State.AllocateReg(ELF64ArgGPRs);
56*06c3fb27SDimitry Andric }
57*06c3fb27SDimitry Andric return false;
58*06c3fb27SDimitry Andric }
59*06c3fb27SDimitry Andric
CC_PPC32_SVR4_Custom_Dummy(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)600b57cec5SDimitry Andric static bool CC_PPC32_SVR4_Custom_Dummy(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
610b57cec5SDimitry Andric CCValAssign::LocInfo &LocInfo,
620b57cec5SDimitry Andric ISD::ArgFlagsTy &ArgFlags,
630b57cec5SDimitry Andric CCState &State) {
640b57cec5SDimitry Andric return true;
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric
CC_PPC32_SVR4_Custom_AlignArgRegs(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)670b57cec5SDimitry Andric static bool CC_PPC32_SVR4_Custom_AlignArgRegs(unsigned &ValNo, MVT &ValVT,
680b57cec5SDimitry Andric MVT &LocVT,
690b57cec5SDimitry Andric CCValAssign::LocInfo &LocInfo,
700b57cec5SDimitry Andric ISD::ArgFlagsTy &ArgFlags,
710b57cec5SDimitry Andric CCState &State) {
720b57cec5SDimitry Andric static const MCPhysReg ArgRegs[] = {
730b57cec5SDimitry Andric PPC::R3, PPC::R4, PPC::R5, PPC::R6,
740b57cec5SDimitry Andric PPC::R7, PPC::R8, PPC::R9, PPC::R10,
750b57cec5SDimitry Andric };
76bdd1243dSDimitry Andric const unsigned NumArgRegs = std::size(ArgRegs);
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric unsigned RegNum = State.getFirstUnallocated(ArgRegs);
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric // Skip one register if the first unallocated register has an even register
810b57cec5SDimitry Andric // number and there are still argument registers available which have not been
820b57cec5SDimitry Andric // allocated yet. RegNum is actually an index into ArgRegs, which means we
830b57cec5SDimitry Andric // need to skip a register if RegNum is odd.
840b57cec5SDimitry Andric if (RegNum != NumArgRegs && RegNum % 2 == 1) {
850b57cec5SDimitry Andric State.AllocateReg(ArgRegs[RegNum]);
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric // Always return false here, as this function only makes sure that the first
890b57cec5SDimitry Andric // unallocated register has an odd register number and does not actually
900b57cec5SDimitry Andric // allocate a register for the current argument.
910b57cec5SDimitry Andric return false;
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric
CC_PPC32_SVR4_Custom_SkipLastArgRegsPPCF128(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)940b57cec5SDimitry Andric static bool CC_PPC32_SVR4_Custom_SkipLastArgRegsPPCF128(
950b57cec5SDimitry Andric unsigned &ValNo, MVT &ValVT, MVT &LocVT, CCValAssign::LocInfo &LocInfo,
960b57cec5SDimitry Andric ISD::ArgFlagsTy &ArgFlags, CCState &State) {
970b57cec5SDimitry Andric static const MCPhysReg ArgRegs[] = {
980b57cec5SDimitry Andric PPC::R3, PPC::R4, PPC::R5, PPC::R6,
990b57cec5SDimitry Andric PPC::R7, PPC::R8, PPC::R9, PPC::R10,
1000b57cec5SDimitry Andric };
101bdd1243dSDimitry Andric const unsigned NumArgRegs = std::size(ArgRegs);
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric unsigned RegNum = State.getFirstUnallocated(ArgRegs);
1040b57cec5SDimitry Andric int RegsLeft = NumArgRegs - RegNum;
1050b57cec5SDimitry Andric
1060b57cec5SDimitry Andric // Skip if there is not enough registers left for long double type (4 gpr regs
1070b57cec5SDimitry Andric // in soft float mode) and put long double argument on the stack.
1080b57cec5SDimitry Andric if (RegNum != NumArgRegs && RegsLeft < 4) {
1090b57cec5SDimitry Andric for (int i = 0; i < RegsLeft; i++) {
1100b57cec5SDimitry Andric State.AllocateReg(ArgRegs[RegNum + i]);
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric
1140b57cec5SDimitry Andric return false;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
CC_PPC32_SVR4_Custom_AlignFPArgRegs(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)1170b57cec5SDimitry Andric static bool CC_PPC32_SVR4_Custom_AlignFPArgRegs(unsigned &ValNo, MVT &ValVT,
1180b57cec5SDimitry Andric MVT &LocVT,
1190b57cec5SDimitry Andric CCValAssign::LocInfo &LocInfo,
1200b57cec5SDimitry Andric ISD::ArgFlagsTy &ArgFlags,
1210b57cec5SDimitry Andric CCState &State) {
1220b57cec5SDimitry Andric static const MCPhysReg ArgRegs[] = {
1230b57cec5SDimitry Andric PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
1240b57cec5SDimitry Andric PPC::F8
1250b57cec5SDimitry Andric };
1260b57cec5SDimitry Andric
127bdd1243dSDimitry Andric const unsigned NumArgRegs = std::size(ArgRegs);
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric unsigned RegNum = State.getFirstUnallocated(ArgRegs);
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric // If there is only one Floating-point register left we need to put both f64
1320b57cec5SDimitry Andric // values of a split ppc_fp128 value on the stack.
1330b57cec5SDimitry Andric if (RegNum != NumArgRegs && ArgRegs[RegNum] == PPC::F8) {
1340b57cec5SDimitry Andric State.AllocateReg(ArgRegs[RegNum]);
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric
1370b57cec5SDimitry Andric // Always return false here, as this function only makes sure that the two f64
1380b57cec5SDimitry Andric // values a ppc_fp128 value is split into are both passed in registers or both
1390b57cec5SDimitry Andric // passed on the stack and does not actually allocate a register for the
1400b57cec5SDimitry Andric // current argument.
1410b57cec5SDimitry Andric return false;
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric // Split F64 arguments into two 32-bit consecutive registers.
CC_PPC32_SPE_CustomSplitFP64(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)1450b57cec5SDimitry Andric static bool CC_PPC32_SPE_CustomSplitFP64(unsigned &ValNo, MVT &ValVT,
1460b57cec5SDimitry Andric MVT &LocVT,
1470b57cec5SDimitry Andric CCValAssign::LocInfo &LocInfo,
1480b57cec5SDimitry Andric ISD::ArgFlagsTy &ArgFlags,
1490b57cec5SDimitry Andric CCState &State) {
1500b57cec5SDimitry Andric static const MCPhysReg HiRegList[] = { PPC::R3, PPC::R5, PPC::R7, PPC::R9 };
1510b57cec5SDimitry Andric static const MCPhysReg LoRegList[] = { PPC::R4, PPC::R6, PPC::R8, PPC::R10 };
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric // Try to get the first register.
1540b57cec5SDimitry Andric unsigned Reg = State.AllocateReg(HiRegList);
1550b57cec5SDimitry Andric if (!Reg)
1560b57cec5SDimitry Andric return false;
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric unsigned i;
159bdd1243dSDimitry Andric for (i = 0; i < std::size(HiRegList); ++i)
1600b57cec5SDimitry Andric if (HiRegList[i] == Reg)
1610b57cec5SDimitry Andric break;
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric unsigned T = State.AllocateReg(LoRegList[i]);
1640b57cec5SDimitry Andric (void)T;
1650b57cec5SDimitry Andric assert(T == LoRegList[i] && "Could not allocate register");
1660b57cec5SDimitry Andric
1670b57cec5SDimitry Andric State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
1680b57cec5SDimitry Andric State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
1690b57cec5SDimitry Andric LocVT, LocInfo));
1700b57cec5SDimitry Andric return true;
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric // Same as above, but for return values, so only allocate for R3 and R4
CC_PPC32_SPE_RetF64(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)1740b57cec5SDimitry Andric static bool CC_PPC32_SPE_RetF64(unsigned &ValNo, MVT &ValVT,
1750b57cec5SDimitry Andric MVT &LocVT,
1760b57cec5SDimitry Andric CCValAssign::LocInfo &LocInfo,
1770b57cec5SDimitry Andric ISD::ArgFlagsTy &ArgFlags,
1780b57cec5SDimitry Andric CCState &State) {
1790b57cec5SDimitry Andric static const MCPhysReg HiRegList[] = { PPC::R3 };
1800b57cec5SDimitry Andric static const MCPhysReg LoRegList[] = { PPC::R4 };
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric // Try to get the first register.
1830b57cec5SDimitry Andric unsigned Reg = State.AllocateReg(HiRegList, LoRegList);
1840b57cec5SDimitry Andric if (!Reg)
1850b57cec5SDimitry Andric return false;
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric unsigned i;
188bdd1243dSDimitry Andric for (i = 0; i < std::size(HiRegList); ++i)
1890b57cec5SDimitry Andric if (HiRegList[i] == Reg)
1900b57cec5SDimitry Andric break;
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
1930b57cec5SDimitry Andric State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
1940b57cec5SDimitry Andric LocVT, LocInfo));
1950b57cec5SDimitry Andric return true;
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric #include "PPCGenCallingConv.inc"
199