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