xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZCallingConv.h (revision fcaf7f8644a9988098ac6be2165bce3ea4786e91)
10b57cec5SDimitry Andric //===-- SystemZCallingConv.h - Calling conventions for SystemZ --*- 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 #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
100b57cec5SDimitry Andric #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
110b57cec5SDimitry Andric 
12fe6060f1SDimitry Andric #include "SystemZSubtarget.h"
130b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
140b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric namespace llvm {
180b57cec5SDimitry Andric namespace SystemZ {
19fe6060f1SDimitry Andric   const unsigned ELFNumArgGPRs = 5;
20fe6060f1SDimitry Andric   extern const MCPhysReg ELFArgGPRs[ELFNumArgGPRs];
210b57cec5SDimitry Andric 
22fe6060f1SDimitry Andric   const unsigned ELFNumArgFPRs = 4;
23fe6060f1SDimitry Andric   extern const MCPhysReg ELFArgFPRs[ELFNumArgFPRs];
24fe6060f1SDimitry Andric 
25fe6060f1SDimitry Andric   const unsigned XPLINK64NumArgGPRs = 3;
26fe6060f1SDimitry Andric   extern const MCPhysReg XPLINK64ArgGPRs[XPLINK64NumArgGPRs];
27fe6060f1SDimitry Andric 
28fe6060f1SDimitry Andric   const unsigned XPLINK64NumArgFPRs = 4;
29fe6060f1SDimitry Andric   extern const MCPhysReg XPLINK64ArgFPRs[XPLINK64NumArgFPRs];
300b57cec5SDimitry Andric } // end namespace SystemZ
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric class SystemZCCState : public CCState {
330b57cec5SDimitry Andric private:
340b57cec5SDimitry Andric   /// Records whether the value was a fixed argument.
350b57cec5SDimitry Andric   /// See ISD::OutputArg::IsFixed.
360b57cec5SDimitry Andric   SmallVector<bool, 4> ArgIsFixed;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   /// Records whether the value was widened from a short vector type.
390b57cec5SDimitry Andric   SmallVector<bool, 4> ArgIsShortVector;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   // Check whether ArgVT is a short vector type.
IsShortVectorType(EVT ArgVT)420b57cec5SDimitry Andric   bool IsShortVectorType(EVT ArgVT) {
430b57cec5SDimitry Andric     return ArgVT.isVector() && ArgVT.getStoreSize() <= 8;
440b57cec5SDimitry Andric   }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric public:
SystemZCCState(CallingConv::ID CC,bool isVarArg,MachineFunction & MF,SmallVectorImpl<CCValAssign> & locs,LLVMContext & C)470b57cec5SDimitry Andric   SystemZCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
480b57cec5SDimitry Andric                  SmallVectorImpl<CCValAssign> &locs, LLVMContext &C)
490b57cec5SDimitry Andric       : CCState(CC, isVarArg, MF, locs, C) {}
500b57cec5SDimitry Andric 
AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> & Ins,CCAssignFn Fn)510b57cec5SDimitry Andric   void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins,
520b57cec5SDimitry Andric                               CCAssignFn Fn) {
530b57cec5SDimitry Andric     // Formal arguments are always fixed.
540b57cec5SDimitry Andric     ArgIsFixed.clear();
550b57cec5SDimitry Andric     for (unsigned i = 0; i < Ins.size(); ++i)
560b57cec5SDimitry Andric       ArgIsFixed.push_back(true);
570b57cec5SDimitry Andric     // Record whether the call operand was a short vector.
580b57cec5SDimitry Andric     ArgIsShortVector.clear();
590b57cec5SDimitry Andric     for (unsigned i = 0; i < Ins.size(); ++i)
600b57cec5SDimitry Andric       ArgIsShortVector.push_back(IsShortVectorType(Ins[i].ArgVT));
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric     CCState::AnalyzeFormalArguments(Ins, Fn);
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric 
AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> & Outs,CCAssignFn Fn)650b57cec5SDimitry Andric   void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs,
660b57cec5SDimitry Andric                            CCAssignFn Fn) {
670b57cec5SDimitry Andric     // Record whether the call operand was a fixed argument.
680b57cec5SDimitry Andric     ArgIsFixed.clear();
690b57cec5SDimitry Andric     for (unsigned i = 0; i < Outs.size(); ++i)
700b57cec5SDimitry Andric       ArgIsFixed.push_back(Outs[i].IsFixed);
710b57cec5SDimitry Andric     // Record whether the call operand was a short vector.
720b57cec5SDimitry Andric     ArgIsShortVector.clear();
730b57cec5SDimitry Andric     for (unsigned i = 0; i < Outs.size(); ++i)
740b57cec5SDimitry Andric       ArgIsShortVector.push_back(IsShortVectorType(Outs[i].ArgVT));
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric     CCState::AnalyzeCallOperands(Outs, Fn);
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   // This version of AnalyzeCallOperands in the base class is not usable
800b57cec5SDimitry Andric   // since we must provide a means of accessing ISD::OutputArg::IsFixed.
810b57cec5SDimitry Andric   void AnalyzeCallOperands(const SmallVectorImpl<MVT> &Outs,
820b57cec5SDimitry Andric                            SmallVectorImpl<ISD::ArgFlagsTy> &Flags,
830b57cec5SDimitry Andric                            CCAssignFn Fn) = delete;
840b57cec5SDimitry Andric 
IsFixed(unsigned ValNo)850b57cec5SDimitry Andric   bool IsFixed(unsigned ValNo) { return ArgIsFixed[ValNo]; }
IsShortVector(unsigned ValNo)860b57cec5SDimitry Andric   bool IsShortVector(unsigned ValNo) { return ArgIsShortVector[ValNo]; }
870b57cec5SDimitry Andric };
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric // Handle i128 argument types.  These need to be passed by implicit
900b57cec5SDimitry Andric // reference.  This could be as simple as the following .td line:
910b57cec5SDimitry Andric //    CCIfType<[i128], CCPassIndirect<i64>>,
920b57cec5SDimitry Andric // except that i128 is not a legal type, and therefore gets split by
930b57cec5SDimitry Andric // common code into a pair of i64 arguments.
CC_SystemZ_I128Indirect(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)940b57cec5SDimitry Andric inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT,
950b57cec5SDimitry Andric                                     MVT &LocVT,
960b57cec5SDimitry Andric                                     CCValAssign::LocInfo &LocInfo,
970b57cec5SDimitry Andric                                     ISD::ArgFlagsTy &ArgFlags,
980b57cec5SDimitry Andric                                     CCState &State) {
990b57cec5SDimitry Andric   SmallVectorImpl<CCValAssign> &PendingMembers = State.getPendingLocs();
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   // ArgFlags.isSplit() is true on the first part of a i128 argument;
1020b57cec5SDimitry Andric   // PendingMembers.empty() is false on all subsequent parts.
1030b57cec5SDimitry Andric   if (!ArgFlags.isSplit() && PendingMembers.empty())
1040b57cec5SDimitry Andric     return false;
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   // Push a pending Indirect value location for each part.
1070b57cec5SDimitry Andric   LocVT = MVT::i64;
1080b57cec5SDimitry Andric   LocInfo = CCValAssign::Indirect;
1090b57cec5SDimitry Andric   PendingMembers.push_back(CCValAssign::getPending(ValNo, ValVT,
1100b57cec5SDimitry Andric                                                    LocVT, LocInfo));
1110b57cec5SDimitry Andric   if (!ArgFlags.isSplitEnd())
1120b57cec5SDimitry Andric     return true;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   // OK, we've collected all parts in the pending list.  Allocate
1150b57cec5SDimitry Andric   // the location (register or stack slot) for the indirect pointer.
1160b57cec5SDimitry Andric   // (This duplicates the usual i64 calling convention rules.)
117fe6060f1SDimitry Andric   unsigned Reg;
118fe6060f1SDimitry Andric   const SystemZSubtarget &Subtarget =
119fe6060f1SDimitry Andric       State.getMachineFunction().getSubtarget<SystemZSubtarget>();
120fe6060f1SDimitry Andric   if (Subtarget.isTargetELF())
121fe6060f1SDimitry Andric     Reg = State.AllocateReg(SystemZ::ELFArgGPRs);
122fe6060f1SDimitry Andric   else if (Subtarget.isTargetXPLINK64())
123fe6060f1SDimitry Andric     Reg = State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
124fe6060f1SDimitry Andric   else
125fe6060f1SDimitry Andric     llvm_unreachable("Unknown Calling Convention!");
126fe6060f1SDimitry Andric 
127*349cc55cSDimitry Andric   unsigned Offset = Reg && !Subtarget.isTargetXPLINK64()
128*349cc55cSDimitry Andric                         ? 0
129*349cc55cSDimitry Andric                         : State.AllocateStack(8, Align(8));
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   // Use that same location for all the pending parts.
1320b57cec5SDimitry Andric   for (auto &It : PendingMembers) {
1330b57cec5SDimitry Andric     if (Reg)
1340b57cec5SDimitry Andric       It.convertToReg(Reg);
1350b57cec5SDimitry Andric     else
1360b57cec5SDimitry Andric       It.convertToMem(Offset);
1370b57cec5SDimitry Andric     State.addLoc(It);
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   PendingMembers.clear();
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   return true;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
CC_XPLINK64_Shadow_Reg(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)145fe6060f1SDimitry Andric inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
146fe6060f1SDimitry Andric                                    CCValAssign::LocInfo &LocInfo,
147fe6060f1SDimitry Andric                                    ISD::ArgFlagsTy &ArgFlags, CCState &State) {
148fe6060f1SDimitry Andric   if (LocVT == MVT::f32 || LocVT == MVT::f64) {
149fe6060f1SDimitry Andric     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
150fe6060f1SDimitry Andric   }
151fe6060f1SDimitry Andric   if (LocVT == MVT::f128 || LocVT.is128BitVector()) {
152fe6060f1SDimitry Andric     // Shadow next two GPRs, if available.
153fe6060f1SDimitry Andric     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
154fe6060f1SDimitry Andric     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
155fe6060f1SDimitry Andric 
156fe6060f1SDimitry Andric     // Quad precision floating point needs to
157fe6060f1SDimitry Andric     // go inside pre-defined FPR pair.
158fe6060f1SDimitry Andric     if (LocVT == MVT::f128) {
159fe6060f1SDimitry Andric       for (unsigned I = 0; I < SystemZ::XPLINK64NumArgFPRs; I += 2)
160fe6060f1SDimitry Andric         if (State.isAllocated(SystemZ::XPLINK64ArgFPRs[I]))
161fe6060f1SDimitry Andric           State.AllocateReg(SystemZ::XPLINK64ArgFPRs[I + 1]);
162fe6060f1SDimitry Andric     }
163fe6060f1SDimitry Andric   }
164fe6060f1SDimitry Andric   return false;
165fe6060f1SDimitry Andric }
166fe6060f1SDimitry Andric 
CC_XPLINK64_Allocate128BitVararg(unsigned & ValNo,MVT & ValVT,MVT & LocVT,CCValAssign::LocInfo & LocInfo,ISD::ArgFlagsTy & ArgFlags,CCState & State)167fe6060f1SDimitry Andric inline bool CC_XPLINK64_Allocate128BitVararg(unsigned &ValNo, MVT &ValVT,
168fe6060f1SDimitry Andric                                              MVT &LocVT,
169fe6060f1SDimitry Andric                                              CCValAssign::LocInfo &LocInfo,
170fe6060f1SDimitry Andric                                              ISD::ArgFlagsTy &ArgFlags,
171fe6060f1SDimitry Andric                                              CCState &State) {
172fe6060f1SDimitry Andric   // For any C or C++ program, this should always be
173fe6060f1SDimitry Andric   // false, since it is illegal to have a function
174fe6060f1SDimitry Andric   // where the first argument is variadic. Therefore
175fe6060f1SDimitry Andric   // the first fixed argument should already have
176fe6060f1SDimitry Andric   // allocated GPR1 either through shadowing it or
177fe6060f1SDimitry Andric   // using it for parameter passing.
178fe6060f1SDimitry Andric   State.AllocateReg(SystemZ::R1D);
179fe6060f1SDimitry Andric 
180fe6060f1SDimitry Andric   bool AllocGPR2 = State.AllocateReg(SystemZ::R2D);
181fe6060f1SDimitry Andric   bool AllocGPR3 = State.AllocateReg(SystemZ::R3D);
182fe6060f1SDimitry Andric 
183fe6060f1SDimitry Andric   // If GPR2 and GPR3 are available, then we may pass vararg in R2Q.
184*349cc55cSDimitry Andric   // If only GPR3 is available, we need to set custom handling to copy
185*349cc55cSDimitry Andric   // hi bits into GPR3.
186*349cc55cSDimitry Andric   // Either way, we allocate on the stack.
187*349cc55cSDimitry Andric   if (AllocGPR3) {
188*349cc55cSDimitry Andric     // For f128 and vector var arg case, set the bitcast flag to bitcast to
189*349cc55cSDimitry Andric     // i128.
190*349cc55cSDimitry Andric     LocVT = MVT::i128;
191*349cc55cSDimitry Andric     LocInfo = CCValAssign::BCvt;
192*349cc55cSDimitry Andric     auto Offset = State.AllocateStack(16, Align(8));
193*349cc55cSDimitry Andric     if (AllocGPR2)
194fe6060f1SDimitry Andric       State.addLoc(
195fe6060f1SDimitry Andric           CCValAssign::getReg(ValNo, ValVT, SystemZ::R2Q, LocVT, LocInfo));
196*349cc55cSDimitry Andric     else
197fe6060f1SDimitry Andric       State.addLoc(
198fe6060f1SDimitry Andric           CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo));
199fe6060f1SDimitry Andric     return true;
200fe6060f1SDimitry Andric   }
201fe6060f1SDimitry Andric 
202fe6060f1SDimitry Andric   return false;
203fe6060f1SDimitry Andric }
204fe6060f1SDimitry Andric 
RetCC_SystemZ_Error(unsigned &,MVT &,MVT &,CCValAssign::LocInfo &,ISD::ArgFlagsTy &,CCState &)205fe6060f1SDimitry Andric inline bool RetCC_SystemZ_Error(unsigned &, MVT &, MVT &,
206fe6060f1SDimitry Andric                                 CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
207fe6060f1SDimitry Andric                                 CCState &) {
208fe6060f1SDimitry Andric   llvm_unreachable("Return value calling convention currently unsupported.");
209fe6060f1SDimitry Andric }
210fe6060f1SDimitry Andric 
CC_SystemZ_Error(unsigned &,MVT &,MVT &,CCValAssign::LocInfo &,ISD::ArgFlagsTy &,CCState &)211fe6060f1SDimitry Andric inline bool CC_SystemZ_Error(unsigned &, MVT &, MVT &, CCValAssign::LocInfo &,
212fe6060f1SDimitry Andric                              ISD::ArgFlagsTy &, CCState &) {
213fe6060f1SDimitry Andric   llvm_unreachable("Argument calling convention currently unsupported.");
214fe6060f1SDimitry Andric }
215fe6060f1SDimitry Andric 
CC_SystemZ_GHC_Error(unsigned &,MVT &,MVT &,CCValAssign::LocInfo &,ISD::ArgFlagsTy &,CCState &)216480093f4SDimitry Andric inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &,
217480093f4SDimitry Andric                                  CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
218480093f4SDimitry Andric                                  CCState &) {
219480093f4SDimitry Andric   report_fatal_error("No registers left in GHC calling convention");
220480093f4SDimitry Andric   return false;
221480093f4SDimitry Andric }
222480093f4SDimitry Andric 
2230b57cec5SDimitry Andric } // end namespace llvm
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric #endif
226