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 && !Subtarget.isTargetXPLINK64() 128 ? 0 129 : State.AllocateStack(8, Align(8)); 130 131 // Use that same location for all the pending parts. 132 for (auto &It : PendingMembers) { 133 if (Reg) 134 It.convertToReg(Reg); 135 else 136 It.convertToMem(Offset); 137 State.addLoc(It); 138 } 139 140 PendingMembers.clear(); 141 142 return true; 143 } 144 145 // A pointer in 64bit mode is always passed as 64bit. 146 inline bool CC_XPLINK64_Pointer(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 147 CCValAssign::LocInfo &LocInfo, 148 ISD::ArgFlagsTy &ArgFlags, CCState &State) { 149 if (LocVT != MVT::i64) { 150 LocVT = MVT::i64; 151 LocInfo = CCValAssign::ZExt; 152 } 153 return false; 154 } 155 156 inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 157 CCValAssign::LocInfo &LocInfo, 158 ISD::ArgFlagsTy &ArgFlags, CCState &State) { 159 if (LocVT == MVT::f32 || LocVT == MVT::f64) { 160 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 161 } 162 if (LocVT == MVT::f128 || LocVT.is128BitVector()) { 163 // Shadow next two GPRs, if available. 164 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 165 State.AllocateReg(SystemZ::XPLINK64ArgGPRs); 166 167 // Quad precision floating point needs to 168 // go inside pre-defined FPR pair. 169 if (LocVT == MVT::f128) { 170 for (unsigned I = 0; I < SystemZ::XPLINK64NumArgFPRs; I += 2) 171 if (State.isAllocated(SystemZ::XPLINK64ArgFPRs[I])) 172 State.AllocateReg(SystemZ::XPLINK64ArgFPRs[I + 1]); 173 } 174 } 175 return false; 176 } 177 178 inline bool CC_XPLINK64_Allocate128BitVararg(unsigned &ValNo, MVT &ValVT, 179 MVT &LocVT, 180 CCValAssign::LocInfo &LocInfo, 181 ISD::ArgFlagsTy &ArgFlags, 182 CCState &State) { 183 // For any C or C++ program, this should always be 184 // false, since it is illegal to have a function 185 // where the first argument is variadic. Therefore 186 // the first fixed argument should already have 187 // allocated GPR1 either through shadowing it or 188 // using it for parameter passing. 189 State.AllocateReg(SystemZ::R1D); 190 191 bool AllocGPR2 = State.AllocateReg(SystemZ::R2D); 192 bool AllocGPR3 = State.AllocateReg(SystemZ::R3D); 193 194 // If GPR2 and GPR3 are available, then we may pass vararg in R2Q. 195 // If only GPR3 is available, we need to set custom handling to copy 196 // hi bits into GPR3. 197 // Either way, we allocate on the stack. 198 if (AllocGPR3) { 199 // For f128 and vector var arg case, set the bitcast flag to bitcast to 200 // i128. 201 LocVT = MVT::i128; 202 LocInfo = CCValAssign::BCvt; 203 auto Offset = State.AllocateStack(16, Align(8)); 204 if (AllocGPR2) 205 State.addLoc( 206 CCValAssign::getReg(ValNo, ValVT, SystemZ::R2Q, LocVT, LocInfo)); 207 else 208 State.addLoc( 209 CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo)); 210 return true; 211 } 212 213 return false; 214 } 215 216 inline bool RetCC_SystemZ_Error(unsigned &, MVT &, MVT &, 217 CCValAssign::LocInfo &, ISD::ArgFlagsTy &, 218 CCState &) { 219 llvm_unreachable("Return value calling convention currently unsupported."); 220 } 221 222 inline bool CC_SystemZ_Error(unsigned &, MVT &, MVT &, CCValAssign::LocInfo &, 223 ISD::ArgFlagsTy &, CCState &) { 224 llvm_unreachable("Argument calling convention currently unsupported."); 225 } 226 227 inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &, 228 CCValAssign::LocInfo &, ISD::ArgFlagsTy &, 229 CCState &) { 230 report_fatal_error("No registers left in GHC calling convention"); 231 return false; 232 } 233 234 } // end namespace llvm 235 236 #endif 237