1 //===-- SystemZCallingConv.h - Calling conventions for SystemZ --*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H 10 #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H 11 12 #include "SystemZSubtarget.h" 13 #include "llvm/ADT/SmallVector.h" 14 #include "llvm/CodeGen/CallingConvLower.h" 15 #include "llvm/MC/MCRegisterInfo.h" 16 17 namespace llvm { 18 namespace SystemZ { 19 const unsigned ELFNumArgGPRs = 5; 20 extern const MCPhysReg ELFArgGPRs[ELFNumArgGPRs]; 21 22 const unsigned ELFNumArgFPRs = 4; 23 extern const MCPhysReg ELFArgFPRs[ELFNumArgFPRs]; 24 25 const unsigned XPLINK64NumArgGPRs = 3; 26 extern const MCPhysReg XPLINK64ArgGPRs[XPLINK64NumArgGPRs]; 27 28 const unsigned XPLINK64NumArgFPRs = 4; 29 extern const MCPhysReg XPLINK64ArgFPRs[XPLINK64NumArgFPRs]; 30 } // end namespace SystemZ 31 32 class SystemZCCState : public CCState { 33 private: 34 /// Records whether the value was a fixed argument. 35 /// See ISD::OutputArg::IsFixed. 36 SmallVector<bool, 4> ArgIsFixed; 37 38 /// Records whether the value was widened from a short vector type. 39 SmallVector<bool, 4> ArgIsShortVector; 40 41 // Check whether ArgVT is a short vector type. 42 bool IsShortVectorType(EVT ArgVT) { 43 return ArgVT.isVector() && ArgVT.getStoreSize() <= 8; 44 } 45 46 public: 47 SystemZCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, 48 SmallVectorImpl<CCValAssign> &locs, LLVMContext &C) 49 : CCState(CC, isVarArg, MF, locs, C) {} 50 51 void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins, 52 CCAssignFn Fn) { 53 // Formal arguments are always fixed. 54 ArgIsFixed.clear(); 55 for (unsigned i = 0; i < Ins.size(); ++i) 56 ArgIsFixed.push_back(true); 57 // Record whether the call operand was a short vector. 58 ArgIsShortVector.clear(); 59 for (unsigned i = 0; i < Ins.size(); ++i) 60 ArgIsShortVector.push_back(IsShortVectorType(Ins[i].ArgVT)); 61 62 CCState::AnalyzeFormalArguments(Ins, Fn); 63 } 64 65 void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, 66 CCAssignFn Fn) { 67 // Record whether the call operand was a fixed argument. 68 ArgIsFixed.clear(); 69 for (unsigned i = 0; i < Outs.size(); ++i) 70 ArgIsFixed.push_back(Outs[i].IsFixed); 71 // Record whether the call operand was a short vector. 72 ArgIsShortVector.clear(); 73 for (unsigned i = 0; i < Outs.size(); ++i) 74 ArgIsShortVector.push_back(IsShortVectorType(Outs[i].ArgVT)); 75 76 CCState::AnalyzeCallOperands(Outs, Fn); 77 } 78 79 // This version of AnalyzeCallOperands in the base class is not usable 80 // since we must provide a means of accessing ISD::OutputArg::IsFixed. 81 void AnalyzeCallOperands(const SmallVectorImpl<MVT> &Outs, 82 SmallVectorImpl<ISD::ArgFlagsTy> &Flags, 83 CCAssignFn Fn) = delete; 84 85 bool IsFixed(unsigned ValNo) { return ArgIsFixed[ValNo]; } 86 bool IsShortVector(unsigned ValNo) { return ArgIsShortVector[ValNo]; } 87 }; 88 89 // Handle i128 argument types. These need to be passed by implicit 90 // reference. This could be as simple as the following .td line: 91 // CCIfType<[i128], CCPassIndirect<i64>>, 92 // except that i128 is not a legal type, and therefore gets split by 93 // common code into a pair of i64 arguments. 94 inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT, 95 MVT &LocVT, 96 CCValAssign::LocInfo &LocInfo, 97 ISD::ArgFlagsTy &ArgFlags, 98 CCState &State) { 99 SmallVectorImpl<CCValAssign> &PendingMembers = State.getPendingLocs(); 100 101 // ArgFlags.isSplit() is true on the first part of a i128 argument; 102 // PendingMembers.empty() is false on all subsequent parts. 103 if (!ArgFlags.isSplit() && PendingMembers.empty()) 104 return false; 105 106 // Push a pending Indirect value location for each part. 107 LocVT = MVT::i64; 108 LocInfo = CCValAssign::Indirect; 109 PendingMembers.push_back(CCValAssign::getPending(ValNo, ValVT, 110 LocVT, LocInfo)); 111 if (!ArgFlags.isSplitEnd()) 112 return true; 113 114 // OK, we've collected all parts in the pending list. Allocate 115 // the location (register or stack slot) for the indirect pointer. 116 // (This duplicates the usual i64 calling convention rules.) 117 unsigned Reg; 118 const SystemZSubtarget &Subtarget = 119 State.getMachineFunction().getSubtarget<SystemZSubtarget>(); 120 if (Subtarget.isTargetELF()) 121 Reg = State.AllocateReg(SystemZ::ELFArgGPRs); 122 else if (Subtarget.isTargetXPLINK64()) 123 Reg = State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 124 else 125 llvm_unreachable("Unknown Calling Convention!"); 126 127 unsigned Offset = Reg ? 0 : State.AllocateStack(8, Align(8)); 128 129 // Use that same location for all the pending parts. 130 for (auto &It : PendingMembers) { 131 if (Reg) 132 It.convertToReg(Reg); 133 else 134 It.convertToMem(Offset); 135 State.addLoc(It); 136 } 137 138 PendingMembers.clear(); 139 140 return true; 141 } 142 143 inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 144 CCValAssign::LocInfo &LocInfo, 145 ISD::ArgFlagsTy &ArgFlags, CCState &State) { 146 if (LocVT == MVT::f32 || LocVT == MVT::f64) { 147 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 148 } 149 if (LocVT == MVT::f128 || LocVT.is128BitVector()) { 150 // Shadow next two GPRs, if available. 151 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 152 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 153 154 // Quad precision floating point needs to 155 // go inside pre-defined FPR pair. 156 if (LocVT == MVT::f128) { 157 for (unsigned I = 0; I < SystemZ::XPLINK64NumArgFPRs; I += 2) 158 if (State.isAllocated(SystemZ::XPLINK64ArgFPRs[I])) 159 State.AllocateReg(SystemZ::XPLINK64ArgFPRs[I + 1]); 160 } 161 } 162 return false; 163 } 164 165 inline bool CC_XPLINK64_Allocate128BitVararg(unsigned &ValNo, MVT &ValVT, 166 MVT &LocVT, 167 CCValAssign::LocInfo &LocInfo, 168 ISD::ArgFlagsTy &ArgFlags, 169 CCState &State) { 170 if (LocVT.getSizeInBits() < 128) 171 return false; 172 173 if (static_cast<SystemZCCState *>(&State)->IsFixed(ValNo)) 174 return false; 175 176 // For any C or C++ program, this should always be 177 // false, since it is illegal to have a function 178 // where the first argument is variadic. Therefore 179 // the first fixed argument should already have 180 // allocated GPR1 either through shadowing it or 181 // using it for parameter passing. 182 State.AllocateReg(SystemZ::R1D); 183 184 bool AllocGPR2 = State.AllocateReg(SystemZ::R2D); 185 bool AllocGPR3 = State.AllocateReg(SystemZ::R3D); 186 187 // If GPR2 and GPR3 are available, then we may pass vararg in R2Q. 188 if (AllocGPR2 && AllocGPR3) { 189 State.addLoc( 190 CCValAssign::getReg(ValNo, ValVT, SystemZ::R2Q, LocVT, LocInfo)); 191 return true; 192 } 193 194 // If only GPR3 is available, we allocate on stack but need to 195 // set custom handling to copy hi bits into GPR3. 196 if (!AllocGPR2 && AllocGPR3) { 197 auto Offset = State.AllocateStack(16, Align(8)); 198 State.addLoc( 199 CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo)); 200 return true; 201 } 202 203 return false; 204 } 205 206 inline bool RetCC_SystemZ_Error(unsigned &, MVT &, MVT &, 207 CCValAssign::LocInfo &, ISD::ArgFlagsTy &, 208 CCState &) { 209 llvm_unreachable("Return value calling convention currently unsupported."); 210 } 211 212 inline bool CC_SystemZ_Error(unsigned &, MVT &, MVT &, CCValAssign::LocInfo &, 213 ISD::ArgFlagsTy &, CCState &) { 214 llvm_unreachable("Argument calling convention currently unsupported."); 215 } 216 217 inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &, 218 CCValAssign::LocInfo &, ISD::ArgFlagsTy &, 219 CCState &) { 220 report_fatal_error("No registers left in GHC calling convention"); 221 return false; 222 } 223 224 } // end namespace llvm 225 226 #endif 227