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