1 //===-- SystemZCallingConv.h - Calling conventions for SystemZ --*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
10 #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
12 #include "SystemZSubtarget.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/CodeGen/CallingConvLower.h"
15 #include "llvm/MC/MCRegisterInfo.h"
19 const unsigned ELFNumArgGPRs
= 5;
20 extern const MCPhysReg ELFArgGPRs
[ELFNumArgGPRs
];
22 const unsigned ELFNumArgFPRs
= 4;
23 extern const MCPhysReg ELFArgFPRs
[ELFNumArgFPRs
];
25 const unsigned XPLINK64NumArgGPRs
= 3;
26 extern const MCPhysReg XPLINK64ArgGPRs
[XPLINK64NumArgGPRs
];
28 const unsigned XPLINK64NumArgFPRs
= 4;
29 extern const MCPhysReg XPLINK64ArgFPRs
[XPLINK64NumArgFPRs
];
30 } // end namespace SystemZ
32 class SystemZCCState
: public CCState
{
34 /// Records whether the value was a fixed argument.
35 /// See ISD::OutputArg::IsFixed.
36 SmallVector
<bool, 4> ArgIsFixed
;
38 /// Records whether the value was widened from a short vector type.
39 SmallVector
<bool, 4> ArgIsShortVector
;
41 // Check whether ArgVT is a short vector type.
42 bool IsShortVectorType(EVT ArgVT
) {
43 return ArgVT
.isVector() && ArgVT
.getStoreSize() <= 8;
47 SystemZCCState(CallingConv::ID CC
, bool isVarArg
, MachineFunction
&MF
,
48 SmallVectorImpl
<CCValAssign
> &locs
, LLVMContext
&C
)
49 : CCState(CC
, isVarArg
, MF
, locs
, C
) {}
51 void AnalyzeFormalArguments(const SmallVectorImpl
<ISD::InputArg
> &Ins
,
53 // Formal arguments are always fixed.
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
));
62 CCState::AnalyzeFormalArguments(Ins
, Fn
);
65 void AnalyzeCallOperands(const SmallVectorImpl
<ISD::OutputArg
> &Outs
,
67 // Record whether the call operand was a fixed argument.
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
));
76 CCState::AnalyzeCallOperands(Outs
, Fn
);
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;
85 bool IsFixed(unsigned ValNo
) { return ArgIsFixed
[ValNo
]; }
86 bool IsShortVector(unsigned ValNo
) { return ArgIsShortVector
[ValNo
]; }
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
,
96 CCValAssign::LocInfo
&LocInfo
,
97 ISD::ArgFlagsTy
&ArgFlags
,
99 SmallVectorImpl
<CCValAssign
> &PendingMembers
= State
.getPendingLocs();
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())
106 // Push a pending Indirect value location for each part.
108 LocInfo
= CCValAssign::Indirect
;
109 PendingMembers
.push_back(CCValAssign::getPending(ValNo
, ValVT
,
111 if (!ArgFlags
.isSplitEnd())
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.)
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
);
125 llvm_unreachable("Unknown Calling Convention!");
127 unsigned Offset
= Reg
? 0 : State
.AllocateStack(8, Align(8));
129 // Use that same location for all the pending parts.
130 for (auto &It
: PendingMembers
) {
132 It
.convertToReg(Reg
);
134 It
.convertToMem(Offset
);
138 PendingMembers
.clear();
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
);
149 if (LocVT
== MVT::f128
|| LocVT
.is128BitVector()) {
150 // Shadow next two GPRs, if available.
151 State
.AllocateReg(SystemZ::XPLINK64ArgGPRs
);
152 State
.AllocateReg(SystemZ::XPLINK64ArgGPRs
);
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]);
165 inline bool CC_XPLINK64_Allocate128BitVararg(unsigned &ValNo
, MVT
&ValVT
,
167 CCValAssign::LocInfo
&LocInfo
,
168 ISD::ArgFlagsTy
&ArgFlags
,
170 if (LocVT
.getSizeInBits() < 128)
173 if (static_cast<SystemZCCState
*>(&State
)->IsFixed(ValNo
))
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
);
184 bool AllocGPR2
= State
.AllocateReg(SystemZ::R2D
);
185 bool AllocGPR3
= State
.AllocateReg(SystemZ::R3D
);
187 // If GPR2 and GPR3 are available, then we may pass vararg in R2Q.
188 if (AllocGPR2
&& AllocGPR3
) {
190 CCValAssign::getReg(ValNo
, ValVT
, SystemZ::R2Q
, LocVT
, LocInfo
));
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));
199 CCValAssign::getCustomMem(ValNo
, ValVT
, Offset
, LocVT
, LocInfo
));
206 inline bool RetCC_SystemZ_Error(unsigned &, MVT
&, MVT
&,
207 CCValAssign::LocInfo
&, ISD::ArgFlagsTy
&,
209 llvm_unreachable("Return value calling convention currently unsupported.");
212 inline bool CC_SystemZ_Error(unsigned &, MVT
&, MVT
&, CCValAssign::LocInfo
&,
213 ISD::ArgFlagsTy
&, CCState
&) {
214 llvm_unreachable("Argument calling convention currently unsupported.");
217 inline bool CC_SystemZ_GHC_Error(unsigned &, MVT
&, MVT
&,
218 CCValAssign::LocInfo
&, ISD::ArgFlagsTy
&,
220 report_fatal_error("No registers left in GHC calling convention");
224 } // end namespace llvm