Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
35294 views
1
//===-- RISCVCallLowering.cpp - Call lowering -------------------*- 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
/// \file
10
/// This file implements the lowering of LLVM calls to machine code calls for
11
/// GlobalISel.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#include "RISCVCallLowering.h"
16
#include "RISCVISelLowering.h"
17
#include "RISCVMachineFunctionInfo.h"
18
#include "RISCVSubtarget.h"
19
#include "llvm/CodeGen/Analysis.h"
20
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
21
#include "llvm/CodeGen/MachineFrameInfo.h"
22
23
using namespace llvm;
24
25
namespace {
26
27
struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
28
private:
29
// The function used internally to assign args - we ignore the AssignFn stored
30
// by OutgoingValueAssigner since RISC-V implements its CC using a custom
31
// function with a different signature.
32
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn;
33
34
// Whether this is assigning args for a return.
35
bool IsRet;
36
37
RVVArgDispatcher &RVVDispatcher;
38
39
public:
40
RISCVOutgoingValueAssigner(
41
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet,
42
RVVArgDispatcher &RVVDispatcher)
43
: CallLowering::OutgoingValueAssigner(nullptr),
44
RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet),
45
RVVDispatcher(RVVDispatcher) {}
46
47
bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
48
CCValAssign::LocInfo LocInfo,
49
const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
50
CCState &State) override {
51
MachineFunction &MF = State.getMachineFunction();
52
const DataLayout &DL = MF.getDataLayout();
53
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
54
55
if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
56
LocInfo, Flags, State, Info.IsFixed, IsRet, Info.Ty,
57
*Subtarget.getTargetLowering(), RVVDispatcher))
58
return true;
59
60
StackSize = State.getStackSize();
61
return false;
62
}
63
};
64
65
struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
66
RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
67
MachineInstrBuilder MIB)
68
: OutgoingValueHandler(B, MRI), MIB(MIB),
69
Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
70
Register getStackAddress(uint64_t MemSize, int64_t Offset,
71
MachinePointerInfo &MPO,
72
ISD::ArgFlagsTy Flags) override {
73
MachineFunction &MF = MIRBuilder.getMF();
74
LLT p0 = LLT::pointer(0, Subtarget.getXLen());
75
LLT sXLen = LLT::scalar(Subtarget.getXLen());
76
77
if (!SPReg)
78
SPReg = MIRBuilder.buildCopy(p0, Register(RISCV::X2)).getReg(0);
79
80
auto OffsetReg = MIRBuilder.buildConstant(sXLen, Offset);
81
82
auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
83
84
MPO = MachinePointerInfo::getStack(MF, Offset);
85
return AddrReg.getReg(0);
86
}
87
88
void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
89
const MachinePointerInfo &MPO,
90
const CCValAssign &VA) override {
91
MachineFunction &MF = MIRBuilder.getMF();
92
uint64_t LocMemOffset = VA.getLocMemOffset();
93
94
// TODO: Move StackAlignment to subtarget and share with FrameLowering.
95
auto MMO =
96
MF.getMachineMemOperand(MPO, MachineMemOperand::MOStore, MemTy,
97
commonAlignment(Align(16), LocMemOffset));
98
99
Register ExtReg = extendRegister(ValVReg, VA);
100
MIRBuilder.buildStore(ExtReg, Addr, *MMO);
101
}
102
103
void assignValueToReg(Register ValVReg, Register PhysReg,
104
const CCValAssign &VA) override {
105
// If we're passing a smaller fp value into a larger integer register,
106
// anyextend before copying.
107
if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
108
((VA.getLocVT() == MVT::i32 || VA.getLocVT() == MVT::i64) &&
109
VA.getValVT() == MVT::f16)) {
110
LLT DstTy = LLT::scalar(VA.getLocVT().getSizeInBits());
111
ValVReg = MIRBuilder.buildAnyExt(DstTy, ValVReg).getReg(0);
112
}
113
114
Register ExtReg = extendRegister(ValVReg, VA);
115
MIRBuilder.buildCopy(PhysReg, ExtReg);
116
MIB.addUse(PhysReg, RegState::Implicit);
117
}
118
119
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
120
ArrayRef<CCValAssign> VAs,
121
std::function<void()> *Thunk) override {
122
assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
123
const CCValAssign &VALo = VAs[0];
124
const CCValAssign &VAHi = VAs[1];
125
126
assert(VAHi.needsCustom() && "Value doesn't need custom handling");
127
assert(VALo.getValNo() == VAHi.getValNo() &&
128
"Values belong to different arguments");
129
130
assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
131
VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
132
"unexpected custom value");
133
134
Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
135
MRI.createGenericVirtualRegister(LLT::scalar(32))};
136
MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
137
138
if (VAHi.isMemLoc()) {
139
LLT MemTy(VAHi.getLocVT());
140
141
MachinePointerInfo MPO;
142
Register StackAddr = getStackAddress(
143
MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
144
145
assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
146
const_cast<CCValAssign &>(VAHi));
147
}
148
149
auto assignFunc = [=]() {
150
assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
151
if (VAHi.isRegLoc())
152
assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
153
};
154
155
if (Thunk) {
156
*Thunk = assignFunc;
157
return 2;
158
}
159
160
assignFunc();
161
return 2;
162
}
163
164
private:
165
MachineInstrBuilder MIB;
166
167
// Cache the SP register vreg if we need it more than once in this call site.
168
Register SPReg;
169
170
const RISCVSubtarget &Subtarget;
171
};
172
173
struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
174
private:
175
// The function used internally to assign args - we ignore the AssignFn stored
176
// by IncomingValueAssigner since RISC-V implements its CC using a custom
177
// function with a different signature.
178
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn;
179
180
// Whether this is assigning args from a return.
181
bool IsRet;
182
183
RVVArgDispatcher &RVVDispatcher;
184
185
public:
186
RISCVIncomingValueAssigner(
187
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet,
188
RVVArgDispatcher &RVVDispatcher)
189
: CallLowering::IncomingValueAssigner(nullptr),
190
RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet),
191
RVVDispatcher(RVVDispatcher) {}
192
193
bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
194
CCValAssign::LocInfo LocInfo,
195
const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
196
CCState &State) override {
197
MachineFunction &MF = State.getMachineFunction();
198
const DataLayout &DL = MF.getDataLayout();
199
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
200
201
if (LocVT.isScalableVector())
202
MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall();
203
204
if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
205
LocInfo, Flags, State, /*IsFixed=*/true, IsRet, Info.Ty,
206
*Subtarget.getTargetLowering(), RVVDispatcher))
207
return true;
208
209
StackSize = State.getStackSize();
210
return false;
211
}
212
};
213
214
struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
215
RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
216
: IncomingValueHandler(B, MRI),
217
Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
218
219
Register getStackAddress(uint64_t MemSize, int64_t Offset,
220
MachinePointerInfo &MPO,
221
ISD::ArgFlagsTy Flags) override {
222
MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
223
224
int FI = MFI.CreateFixedObject(MemSize, Offset, /*Immutable=*/true);
225
MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
226
return MIRBuilder.buildFrameIndex(LLT::pointer(0, Subtarget.getXLen()), FI)
227
.getReg(0);
228
}
229
230
void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
231
const MachinePointerInfo &MPO,
232
const CCValAssign &VA) override {
233
MachineFunction &MF = MIRBuilder.getMF();
234
auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
235
inferAlignFromPtrInfo(MF, MPO));
236
MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
237
}
238
239
void assignValueToReg(Register ValVReg, Register PhysReg,
240
const CCValAssign &VA) override {
241
markPhysRegUsed(PhysReg);
242
IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
243
}
244
245
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
246
ArrayRef<CCValAssign> VAs,
247
std::function<void()> *Thunk) override {
248
assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
249
const CCValAssign &VALo = VAs[0];
250
const CCValAssign &VAHi = VAs[1];
251
252
assert(VAHi.needsCustom() && "Value doesn't need custom handling");
253
assert(VALo.getValNo() == VAHi.getValNo() &&
254
"Values belong to different arguments");
255
256
assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
257
VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
258
"unexpected custom value");
259
260
Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
261
MRI.createGenericVirtualRegister(LLT::scalar(32))};
262
263
if (VAHi.isMemLoc()) {
264
LLT MemTy(VAHi.getLocVT());
265
266
MachinePointerInfo MPO;
267
Register StackAddr = getStackAddress(
268
MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
269
270
assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
271
const_cast<CCValAssign &>(VAHi));
272
}
273
274
assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
275
if (VAHi.isRegLoc())
276
assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
277
278
MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
279
280
return 2;
281
}
282
283
/// How the physical register gets marked varies between formal
284
/// parameters (it's a basic-block live-in), and a call instruction
285
/// (it's an implicit-def of the BL).
286
virtual void markPhysRegUsed(MCRegister PhysReg) = 0;
287
288
private:
289
const RISCVSubtarget &Subtarget;
290
};
291
292
struct RISCVFormalArgHandler : public RISCVIncomingValueHandler {
293
RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
294
: RISCVIncomingValueHandler(B, MRI) {}
295
296
void markPhysRegUsed(MCRegister PhysReg) override {
297
MIRBuilder.getMRI()->addLiveIn(PhysReg);
298
MIRBuilder.getMBB().addLiveIn(PhysReg);
299
}
300
};
301
302
struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
303
RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
304
MachineInstrBuilder &MIB)
305
: RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
306
307
void markPhysRegUsed(MCRegister PhysReg) override {
308
MIB.addDef(PhysReg, RegState::Implicit);
309
}
310
311
MachineInstrBuilder MIB;
312
};
313
314
} // namespace
315
316
RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI)
317
: CallLowering(&TLI) {}
318
319
/// Return true if scalable vector with ScalarTy is legal for lowering.
320
static bool isLegalElementTypeForRVV(Type *EltTy,
321
const RISCVSubtarget &Subtarget) {
322
if (EltTy->isPointerTy())
323
return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true;
324
if (EltTy->isIntegerTy(1) || EltTy->isIntegerTy(8) ||
325
EltTy->isIntegerTy(16) || EltTy->isIntegerTy(32))
326
return true;
327
if (EltTy->isIntegerTy(64))
328
return Subtarget.hasVInstructionsI64();
329
if (EltTy->isHalfTy())
330
return Subtarget.hasVInstructionsF16();
331
if (EltTy->isBFloatTy())
332
return Subtarget.hasVInstructionsBF16();
333
if (EltTy->isFloatTy())
334
return Subtarget.hasVInstructionsF32();
335
if (EltTy->isDoubleTy())
336
return Subtarget.hasVInstructionsF64();
337
return false;
338
}
339
340
// TODO: Support all argument types.
341
// TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall.
342
static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
343
bool IsLowerArgs = false) {
344
if (T->isIntegerTy())
345
return true;
346
if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy())
347
return true;
348
if (T->isPointerTy())
349
return true;
350
// TODO: Support fixed vector types.
351
if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() &&
352
T->isScalableTy() &&
353
isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
354
return true;
355
return false;
356
}
357
358
// TODO: Only integer, pointer and aggregate types are supported now.
359
// TODO: Remove IsLowerRetVal argument by adding support for vectors in
360
// lowerCall.
361
static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
362
bool IsLowerRetVal = false) {
363
// TODO: Integers larger than 2*XLen are passed indirectly which is not
364
// supported yet.
365
if (T->isIntegerTy())
366
return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
367
if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy())
368
return true;
369
if (T->isPointerTy())
370
return true;
371
372
if (T->isArrayTy())
373
return isSupportedReturnType(T->getArrayElementType(), Subtarget);
374
375
if (T->isStructTy()) {
376
auto StructT = cast<StructType>(T);
377
for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i)
378
if (!isSupportedReturnType(StructT->getElementType(i), Subtarget))
379
return false;
380
return true;
381
}
382
383
if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() &&
384
T->isScalableTy() &&
385
isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
386
return true;
387
388
return false;
389
}
390
391
bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
392
const Value *Val,
393
ArrayRef<Register> VRegs,
394
MachineInstrBuilder &Ret) const {
395
if (!Val)
396
return true;
397
398
const RISCVSubtarget &Subtarget =
399
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
400
if (!isSupportedReturnType(Val->getType(), Subtarget, /*IsLowerRetVal=*/true))
401
return false;
402
403
MachineFunction &MF = MIRBuilder.getMF();
404
const DataLayout &DL = MF.getDataLayout();
405
const Function &F = MF.getFunction();
406
CallingConv::ID CC = F.getCallingConv();
407
408
ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
409
setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F);
410
411
SmallVector<ArgInfo, 4> SplitRetInfos;
412
splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC);
413
414
RVVArgDispatcher Dispatcher{&MF, getTLI<RISCVTargetLowering>(),
415
ArrayRef(F.getReturnType())};
416
RISCVOutgoingValueAssigner Assigner(
417
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
418
/*IsRet=*/true, Dispatcher);
419
RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
420
return determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
421
MIRBuilder, CC, F.isVarArg());
422
}
423
424
bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
425
const Value *Val, ArrayRef<Register> VRegs,
426
FunctionLoweringInfo &FLI) const {
427
assert(!Val == VRegs.empty() && "Return value without a vreg");
428
MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
429
430
if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret))
431
return false;
432
433
MIRBuilder.insertInstr(Ret);
434
return true;
435
}
436
437
/// If there are varargs that were passed in a0-a7, the data in those registers
438
/// must be copied to the varargs save area on the stack.
439
void RISCVCallLowering::saveVarArgRegisters(
440
MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler,
441
IncomingValueAssigner &Assigner, CCState &CCInfo) const {
442
MachineFunction &MF = MIRBuilder.getMF();
443
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
444
unsigned XLenInBytes = Subtarget.getXLen() / 8;
445
ArrayRef<MCPhysReg> ArgRegs = RISCV::getArgGPRs(Subtarget.getTargetABI());
446
MachineRegisterInfo &MRI = MF.getRegInfo();
447
unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
448
MachineFrameInfo &MFI = MF.getFrameInfo();
449
RISCVMachineFunctionInfo *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
450
451
// Size of the vararg save area. For now, the varargs save area is either
452
// zero or large enough to hold a0-a7.
453
int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
454
int FI;
455
456
// If all registers are allocated, then all varargs must be passed on the
457
// stack and we don't need to save any argregs.
458
if (VarArgsSaveSize == 0) {
459
int VaArgOffset = Assigner.StackSize;
460
FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
461
} else {
462
int VaArgOffset = -VarArgsSaveSize;
463
FI = MFI.CreateFixedObject(VarArgsSaveSize, VaArgOffset, true);
464
465
// If saving an odd number of registers then create an extra stack slot to
466
// ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
467
// offsets to even-numbered registered remain 2*XLEN-aligned.
468
if (Idx % 2) {
469
MFI.CreateFixedObject(XLenInBytes,
470
VaArgOffset - static_cast<int>(XLenInBytes), true);
471
VarArgsSaveSize += XLenInBytes;
472
}
473
474
const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(),
475
Subtarget.getXLen());
476
const LLT sXLen = LLT::scalar(Subtarget.getXLen());
477
478
auto FIN = MIRBuilder.buildFrameIndex(p0, FI);
479
auto Offset = MIRBuilder.buildConstant(
480
MRI.createGenericVirtualRegister(sXLen), XLenInBytes);
481
482
// Copy the integer registers that may have been used for passing varargs
483
// to the vararg save area.
484
const MVT XLenVT = Subtarget.getXLenVT();
485
for (unsigned I = Idx; I < ArgRegs.size(); ++I) {
486
const Register VReg = MRI.createGenericVirtualRegister(sXLen);
487
Handler.assignValueToReg(
488
VReg, ArgRegs[I],
489
CCValAssign::getReg(I + MF.getFunction().getNumOperands(), XLenVT,
490
ArgRegs[I], XLenVT, CCValAssign::Full));
491
auto MPO =
492
MachinePointerInfo::getFixedStack(MF, FI, (I - Idx) * XLenInBytes);
493
MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
494
FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
495
FIN.getReg(0), Offset);
496
}
497
}
498
499
// Record the frame index of the first variable argument which is a value
500
// necessary to G_VASTART.
501
RVFI->setVarArgsFrameIndex(FI);
502
RVFI->setVarArgsSaveSize(VarArgsSaveSize);
503
}
504
505
bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
506
const Function &F,
507
ArrayRef<ArrayRef<Register>> VRegs,
508
FunctionLoweringInfo &FLI) const {
509
// Early exit if there are no arguments. varargs are not part of F.args() but
510
// must be lowered.
511
if (F.arg_empty() && !F.isVarArg())
512
return true;
513
514
const RISCVSubtarget &Subtarget =
515
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
516
for (auto &Arg : F.args()) {
517
if (!isSupportedArgumentType(Arg.getType(), Subtarget,
518
/*IsLowerArgs=*/true))
519
return false;
520
}
521
522
MachineFunction &MF = MIRBuilder.getMF();
523
const DataLayout &DL = MF.getDataLayout();
524
CallingConv::ID CC = F.getCallingConv();
525
526
SmallVector<ArgInfo, 32> SplitArgInfos;
527
SmallVector<Type *, 4> TypeList;
528
unsigned Index = 0;
529
for (auto &Arg : F.args()) {
530
// Construct the ArgInfo object from destination register and argument type.
531
ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
532
setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F);
533
534
// Handle any required merging from split value types from physical
535
// registers into the desired VReg. ArgInfo objects are constructed
536
// correspondingly and appended to SplitArgInfos.
537
splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
538
539
TypeList.push_back(Arg.getType());
540
541
++Index;
542
}
543
544
RVVArgDispatcher Dispatcher{&MF, getTLI<RISCVTargetLowering>(),
545
ArrayRef(TypeList)};
546
RISCVIncomingValueAssigner Assigner(
547
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
548
/*IsRet=*/false, Dispatcher);
549
RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
550
551
SmallVector<CCValAssign, 16> ArgLocs;
552
CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
553
if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) ||
554
!handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder))
555
return false;
556
557
if (F.isVarArg())
558
saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
559
560
return true;
561
}
562
563
bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
564
CallLoweringInfo &Info) const {
565
MachineFunction &MF = MIRBuilder.getMF();
566
const DataLayout &DL = MF.getDataLayout();
567
const Function &F = MF.getFunction();
568
CallingConv::ID CC = F.getCallingConv();
569
570
const RISCVSubtarget &Subtarget =
571
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
572
for (auto &AInfo : Info.OrigArgs) {
573
if (!isSupportedArgumentType(AInfo.Ty, Subtarget))
574
return false;
575
}
576
577
if (!Info.OrigRet.Ty->isVoidTy() &&
578
!isSupportedReturnType(Info.OrigRet.Ty, Subtarget))
579
return false;
580
581
MachineInstrBuilder CallSeqStart =
582
MIRBuilder.buildInstr(RISCV::ADJCALLSTACKDOWN);
583
584
SmallVector<ArgInfo, 32> SplitArgInfos;
585
SmallVector<ISD::OutputArg, 8> Outs;
586
SmallVector<Type *, 4> TypeList;
587
for (auto &AInfo : Info.OrigArgs) {
588
// Handle any required unmerging of split value types from a given VReg into
589
// physical registers. ArgInfo objects are constructed correspondingly and
590
// appended to SplitArgInfos.
591
splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
592
TypeList.push_back(AInfo.Ty);
593
}
594
595
// TODO: Support tail calls.
596
Info.IsTailCall = false;
597
598
// Select the recommended relocation type R_RISCV_CALL_PLT.
599
if (!Info.Callee.isReg())
600
Info.Callee.setTargetFlags(RISCVII::MO_CALL);
601
602
MachineInstrBuilder Call =
603
MIRBuilder
604
.buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
605
: RISCV::PseudoCALL)
606
.add(Info.Callee);
607
const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
608
Call.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
609
610
RVVArgDispatcher ArgDispatcher{&MF, getTLI<RISCVTargetLowering>(),
611
ArrayRef(TypeList)};
612
RISCVOutgoingValueAssigner ArgAssigner(
613
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
614
/*IsRet=*/false, ArgDispatcher);
615
RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
616
if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
617
MIRBuilder, CC, Info.IsVarArg))
618
return false;
619
620
MIRBuilder.insertInstr(Call);
621
622
CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0);
623
MIRBuilder.buildInstr(RISCV::ADJCALLSTACKUP)
624
.addImm(ArgAssigner.StackSize)
625
.addImm(0);
626
627
// If Callee is a reg, since it is used by a target specific
628
// instruction, it must have a register class matching the
629
// constraint of that instruction.
630
if (Call->getOperand(0).isReg())
631
constrainOperandRegClass(MF, *TRI, MF.getRegInfo(),
632
*Subtarget.getInstrInfo(),
633
*Subtarget.getRegBankInfo(), *Call,
634
Call->getDesc(), Call->getOperand(0), 0);
635
636
if (Info.OrigRet.Ty->isVoidTy())
637
return true;
638
639
SmallVector<ArgInfo, 4> SplitRetInfos;
640
splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
641
642
RVVArgDispatcher RetDispatcher{&MF, getTLI<RISCVTargetLowering>(),
643
ArrayRef(F.getReturnType())};
644
RISCVIncomingValueAssigner RetAssigner(
645
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
646
/*IsRet=*/true, RetDispatcher);
647
RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
648
if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
649
MIRBuilder, CC, Info.IsVarArg))
650
return false;
651
652
return true;
653
}
654
655