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 31 const unsigned XPLINK64NumArgVRs = 8; 32 extern const MCPhysReg XPLINK64ArgVRs[XPLINK64NumArgVRs]; 33 } // end namespace SystemZ 34 35 class SystemZCCState : public CCState { 36 private: 37 /// Records whether the value was a fixed argument. 38 /// See ISD::OutputArg::IsFixed. 39 SmallVector<bool, 4> ArgIsFixed; 40 41 /// Records whether the value was widened from a short vector type. 42 SmallVector<bool, 4> ArgIsShortVector; 43 44 // Check whether ArgVT is a short vector type. 45 bool IsShortVectorType(EVT ArgVT) { 46 return ArgVT.isVector() && ArgVT.getStoreSize() <= 8; 47 } 48 49 public: 50 SystemZCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, 51 SmallVectorImpl<CCValAssign> &locs, LLVMContext &C) 52 : CCState(CC, isVarArg, MF, locs, C) {} 53 54 void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins, 55 CCAssignFn Fn) { 56 // Formal arguments are always fixed. 57 ArgIsFixed.clear(); 58 for (unsigned i = 0; i < Ins.size(); ++i) 59 ArgIsFixed.push_back(true); 60 // Record whether the call operand was a short vector. 61 ArgIsShortVector.clear(); 62 for (unsigned i = 0; i < Ins.size(); ++i) 63 ArgIsShortVector.push_back(IsShortVectorType(Ins[i].ArgVT)); 64 65 CCState::AnalyzeFormalArguments(Ins, Fn); 66 } 67 68 void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, 69 CCAssignFn Fn) { 70 // Record whether the call operand was a fixed argument. 71 ArgIsFixed.clear(); 72 for (unsigned i = 0; i < Outs.size(); ++i) 73 ArgIsFixed.push_back(Outs[i].IsFixed); 74 // Record whether the call operand was a short vector. 75 ArgIsShortVector.clear(); 76 for (unsigned i = 0; i < Outs.size(); ++i) 77 ArgIsShortVector.push_back(IsShortVectorType(Outs[i].ArgVT)); 78 79 CCState::AnalyzeCallOperands(Outs, Fn); 80 } 81 82 // This version of AnalyzeCallOperands in the base class is not usable 83 // since we must provide a means of accessing ISD::OutputArg::IsFixed. 84 void AnalyzeCallOperands(const SmallVectorImpl<MVT> &Outs, 85 SmallVectorImpl<ISD::ArgFlagsTy> &Flags, 86 CCAssignFn Fn) = delete; 87 88 bool IsFixed(unsigned ValNo) { return ArgIsFixed[ValNo]; } 89 bool IsShortVector(unsigned ValNo) { return ArgIsShortVector[ValNo]; } 90 }; 91 92 // Handle i128 argument types. These need to be passed by implicit 93 // reference. This could be as simple as the following .td line: 94 // CCIfType<[i128], CCPassIndirect<i64>>, 95 // except that i128 is not a legal type, and therefore gets split by 96 // common code into a pair of i64 arguments. 97 inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT, 98 MVT &LocVT, 99 CCValAssign::LocInfo &LocInfo, 100 ISD::ArgFlagsTy &ArgFlags, 101 CCState &State) { 102 SmallVectorImpl<CCValAssign> &PendingMembers = State.getPendingLocs(); 103 104 // ArgFlags.isSplit() is true on the first part of a i128 argument; 105 // PendingMembers.empty() is false on all subsequent parts. 106 if (!ArgFlags.isSplit() && PendingMembers.empty()) 107 return false; 108 109 // Push a pending Indirect value location for each part. 110 LocVT = MVT::i64; 111 LocInfo = CCValAssign::Indirect; 112 PendingMembers.push_back(CCValAssign::getPending(ValNo, ValVT, 113 LocVT, LocInfo)); 114 if (!ArgFlags.isSplitEnd()) 115 return true; 116 117 // OK, we've collected all parts in the pending list. Allocate 118 // the location (register or stack slot) for the indirect pointer. 119 // (This duplicates the usual i64 calling convention rules.) 120 unsigned Reg; 121 const SystemZSubtarget &Subtarget = 122 State.getMachineFunction().getSubtarget<SystemZSubtarget>(); 123 if (Subtarget.isTargetELF()) 124 Reg = State.AllocateReg(SystemZ::ELFArgGPRs); 125 else if (Subtarget.isTargetXPLINK64()) 126 Reg = State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 127 else 128 llvm_unreachable("Unknown Calling Convention!"); 129 130 unsigned Offset = Reg && !Subtarget.isTargetXPLINK64() 131 ? 0 132 : State.AllocateStack(8, Align(8)); 133 134 // Use that same location for all the pending parts. 135 for (auto &It : PendingMembers) { 136 if (Reg) 137 It.convertToReg(Reg); 138 else 139 It.convertToMem(Offset); 140 State.addLoc(It); 141 } 142 143 PendingMembers.clear(); 144 145 return true; 146 } 147 148 inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 149 CCValAssign::LocInfo &LocInfo, 150 ISD::ArgFlagsTy &ArgFlags, CCState &State) { 151 if (LocVT == MVT::f32 || LocVT == MVT::f64) { 152 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 153 } 154 if (LocVT == MVT::f128 || LocVT.is128BitVector()) { 155 // Shadow next two GPRs, if available. 156 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 157 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 158 159 // Quad precision floating point needs to 160 // go inside pre-defined FPR pair. 161 if (LocVT == MVT::f128) { 162 for (unsigned I = 0; I < SystemZ::XPLINK64NumArgFPRs; I += 2) 163 if (State.isAllocated(SystemZ::XPLINK64ArgFPRs[I])) 164 State.AllocateReg(SystemZ::XPLINK64ArgFPRs[I + 1]); 165 } 166 } 167 return false; 168 } 169 170 inline bool CC_XPLINK64_Allocate128BitVararg(unsigned &ValNo, MVT &ValVT, 171 MVT &LocVT, 172 CCValAssign::LocInfo &LocInfo, 173 ISD::ArgFlagsTy &ArgFlags, 174 CCState &State) { 175 // For any C or C++ program, this should always be 176 // false, since it is illegal to have a function 177 // where the first argument is variadic. Therefore 178 // the first fixed argument should already have 179 // allocated GPR1 either through shadowing it or 180 // using it for parameter passing. 181 State.AllocateReg(SystemZ::R1D); 182 183 bool AllocGPR2 = State.AllocateReg(SystemZ::R2D); 184 bool AllocGPR3 = State.AllocateReg(SystemZ::R3D); 185 186 // If GPR2 and GPR3 are available, then we may pass vararg in R2Q. 187 // If only GPR3 is available, we need to set custom handling to copy 188 // hi bits into GPR3. 189 // Either way, we allocate on the stack. 190 if (AllocGPR3) { 191 // For f128 and vector var arg case, set the bitcast flag to bitcast to 192 // i128. 193 LocVT = MVT::i128; 194 LocInfo = CCValAssign::BCvt; 195 auto Offset = State.AllocateStack(16, Align(8)); 196 if (AllocGPR2) 197 State.addLoc( 198 CCValAssign::getReg(ValNo, ValVT, SystemZ::R2Q, LocVT, LocInfo)); 199 else 200 State.addLoc( 201 CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo)); 202 return true; 203 } 204 205 return false; 206 } 207 208 inline bool CC_XPLINK64_Shadow_Stack(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 209 CCValAssign::LocInfo &LocInfo, 210 ISD::ArgFlagsTy &ArgFlags, 211 CCState &State) { 212 ArrayRef<MCPhysReg> RegList; 213 214 switch (LocVT.SimpleTy) { 215 case MVT::i64: 216 RegList = SystemZ::XPLINK64ArgGPRs; 217 break; 218 case MVT::v16i8: 219 case MVT::v8i16: 220 case MVT::v4i32: 221 case MVT::v2i64: 222 case MVT::v4f32: 223 case MVT::v2f64: 224 RegList = SystemZ::XPLINK64ArgVRs; 225 break; 226 case MVT::f32: 227 case MVT::f64: 228 case MVT::f128: 229 RegList = SystemZ::XPLINK64ArgFPRs; 230 break; 231 default: 232 return false; 233 } 234 235 unsigned UnallocatedRegisterIndex = State.getFirstUnallocated(RegList); 236 // Every time we can allocate a register, allocate on the stack. 237 if (UnallocatedRegisterIndex < RegList.size()) 238 State.AllocateStack(LocVT.getSizeInBits() / 8, Align(8)); 239 240 return false; 241 } 242 243 inline bool RetCC_SystemZ_Error(unsigned &, MVT &, MVT &, 244 CCValAssign::LocInfo &, ISD::ArgFlagsTy &, 245 CCState &) { 246 llvm_unreachable("Return value calling convention currently unsupported."); 247 } 248 249 inline bool CC_SystemZ_Error(unsigned &, MVT &, MVT &, CCValAssign::LocInfo &, 250 ISD::ArgFlagsTy &, CCState &) { 251 llvm_unreachable("Argument calling convention currently unsupported."); 252 } 253 254 inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &, 255 CCValAssign::LocInfo &, ISD::ArgFlagsTy &, 256 CCState &) { 257 report_fatal_error("No registers left in GHC calling convention"); 258 return false; 259 } 260 261 } // end namespace llvm 262 263 #endif 264