LLVM 23.0.0git
RISCVCallLowering.cpp
Go to the documentation of this file.
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 "RISCVCallingConv.h"
17#include "RISCVISelLowering.h"
19#include "RISCVSubtarget.h"
24
25using namespace llvm;
26
27namespace {
28
29struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
30private:
31 // The function used internally to assign args - we ignore the AssignFn stored
32 // by OutgoingValueAssigner since RISC-V implements its CC using a custom
33 // function with a different signature.
34 RISCVCCAssignFn *RISCVAssignFn;
35
36 // Whether this is assigning args for a return.
37 bool IsRet;
38
39public:
40 RISCVOutgoingValueAssigner(RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
41 : CallLowering::OutgoingValueAssigner(nullptr),
42 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
43
44 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
46 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
47 CCState &State) override {
48 if (RISCVAssignFn(ValNo, ValVT, LocVT, LocInfo, Flags, State, IsRet,
49 Info.Ty))
50 return true;
51
52 StackSize = State.getStackSize();
53 return false;
54 }
55};
56
57struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
58 RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
59 MachineInstrBuilder MIB)
60 : OutgoingValueHandler(B, MRI), MIB(MIB),
61 Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
62 Register getStackAddress(uint64_t MemSize, int64_t Offset,
63 MachinePointerInfo &MPO,
64 ISD::ArgFlagsTy Flags) override {
65 MachineFunction &MF = MIRBuilder.getMF();
66 LLT p0 = LLT::pointer(0, Subtarget.getXLen());
67 LLT sXLen = LLT::scalar(Subtarget.getXLen());
68
69 if (!SPReg)
70 SPReg = MIRBuilder.buildCopy(p0, Register(RISCV::X2)).getReg(0);
71
72 auto OffsetReg = MIRBuilder.buildConstant(sXLen, Offset);
73
74 auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
75
77 return AddrReg.getReg(0);
78 }
79
80 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
81 const MachinePointerInfo &MPO,
82 const CCValAssign &VA) override {
83 MachineFunction &MF = MIRBuilder.getMF();
84 uint64_t LocMemOffset = VA.getLocMemOffset();
85
86 // TODO: Move StackAlignment to subtarget and share with FrameLowering.
87 auto MMO =
89 commonAlignment(Align(16), LocMemOffset));
90
91 Register ExtReg = extendRegister(ValVReg, VA);
92 MIRBuilder.buildStore(ExtReg, Addr, *MMO);
93 }
94
95 void assignValueToReg(Register ValVReg, Register PhysReg,
96 const CCValAssign &VA,
97 ISD::ArgFlagsTy Flags = {}) override {
98 Register ExtReg = extendRegister(ValVReg, VA);
99 MIRBuilder.buildCopy(PhysReg, ExtReg);
100 MIB.addUse(PhysReg, RegState::Implicit);
101 }
102
103 unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
105 std::function<void()> *Thunk) override {
106 const CCValAssign &VA = VAs[0];
107 if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
108 (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
109 Register PhysReg = VA.getLocReg();
110
111 auto assignFunc = [=]() {
112 auto Trunc = MIRBuilder.buildAnyExt(LLT(VA.getLocVT()), Arg.Regs[0]);
113 MIRBuilder.buildCopy(PhysReg, Trunc);
114 MIB.addUse(PhysReg, RegState::Implicit);
115 };
116
117 if (Thunk) {
118 *Thunk = std::move(assignFunc);
119 return 1;
120 }
121
122 assignFunc();
123 return 1;
124 }
125
126 assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
127 const CCValAssign &VAHi = VAs[1];
128
129 assert(VAHi.needsCustom() && "Value doesn't need custom handling");
130 assert(VA.getValNo() == VAHi.getValNo() &&
131 "Values belong to different arguments");
132
133 assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
134 VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
135 "unexpected custom value");
136
137 Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
138 MRI.createGenericVirtualRegister(LLT::scalar(32))};
139 MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
140
141 if (VAHi.isMemLoc()) {
142 LLT MemTy(VAHi.getLocVT());
143
144 MachinePointerInfo MPO;
145 Register StackAddr = getStackAddress(
146 MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
147
148 assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
149 const_cast<CCValAssign &>(VAHi));
150 }
151
152 auto assignFunc = [=]() {
153 assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
154 if (VAHi.isRegLoc())
155 assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
156 };
157
158 if (Thunk) {
159 *Thunk = std::move(assignFunc);
160 return 2;
161 }
162
163 assignFunc();
164 return 2;
165 }
166
167private:
168 MachineInstrBuilder MIB;
169
170 // Cache the SP register vreg if we need it more than once in this call site.
171 Register SPReg;
172
173 const RISCVSubtarget &Subtarget;
174};
175
176struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
177private:
178 // The function used internally to assign args - we ignore the AssignFn stored
179 // by IncomingValueAssigner since RISC-V implements its CC using a custom
180 // function with a different signature.
181 RISCVCCAssignFn *RISCVAssignFn;
182
183 // Whether this is assigning args from a return.
184 bool IsRet;
185
186public:
187 RISCVIncomingValueAssigner(RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
188 : CallLowering::IncomingValueAssigner(nullptr),
189 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
190
191 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
192 CCValAssign::LocInfo LocInfo,
193 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
194 CCState &State) override {
195 MachineFunction &MF = State.getMachineFunction();
196
197 if (LocVT.isScalableVector())
198 MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall();
199
200 if (RISCVAssignFn(ValNo, ValVT, LocVT, LocInfo, Flags, State, IsRet,
201 Info.Ty))
202 return true;
203
204 StackSize = State.getStackSize();
205 return false;
206 }
207};
208
209struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
210 RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
211 : IncomingValueHandler(B, MRI),
212 Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
213
214 Register getStackAddress(uint64_t MemSize, int64_t Offset,
215 MachinePointerInfo &MPO,
216 ISD::ArgFlagsTy Flags) override {
217 MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
218
219 int FI = MFI.CreateFixedObject(MemSize, Offset, /*Immutable=*/true);
220 MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
221 return MIRBuilder.buildFrameIndex(LLT::pointer(0, Subtarget.getXLen()), FI)
222 .getReg(0);
223 }
224
225 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
226 const MachinePointerInfo &MPO,
227 const CCValAssign &VA) override {
228 MachineFunction &MF = MIRBuilder.getMF();
229 auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
230 inferAlignFromPtrInfo(MF, MPO));
231 MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
232 }
233
234 void assignValueToReg(Register ValVReg, Register PhysReg,
235 const CCValAssign &VA,
236 ISD::ArgFlagsTy Flags = {}) override {
237 markPhysRegUsed(PhysReg);
238 IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
239 }
240
241 unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
243 std::function<void()> *Thunk) override {
244 const CCValAssign &VA = VAs[0];
245 if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
246 (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
247 Register PhysReg = VA.getLocReg();
248
249 markPhysRegUsed(PhysReg);
250
251 LLT LocTy(VA.getLocVT());
252 auto Copy = MIRBuilder.buildCopy(LocTy, PhysReg);
253
254 MIRBuilder.buildTrunc(Arg.Regs[0], Copy.getReg(0));
255 return 1;
256 }
257
258 assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
259 const CCValAssign &VAHi = VAs[1];
260
261 assert(VAHi.needsCustom() && "Value doesn't need custom handling");
262 assert(VA.getValNo() == VAHi.getValNo() &&
263 "Values belong to different arguments");
264
265 assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
266 VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
267 "unexpected custom value");
268
269 Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
270 MRI.createGenericVirtualRegister(LLT::scalar(32))};
271
272 if (VAHi.isMemLoc()) {
273 LLT MemTy(VAHi.getLocVT());
274
275 MachinePointerInfo MPO;
276 Register StackAddr = getStackAddress(
277 MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
278
279 assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
280 const_cast<CCValAssign &>(VAHi));
281 }
282
283 assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
284 if (VAHi.isRegLoc())
285 assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
286
287 MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
288
289 return 2;
290 }
291
292 /// How the physical register gets marked varies between formal
293 /// parameters (it's a basic-block live-in), and a call instruction
294 /// (it's an implicit-def of the BL).
295 virtual void markPhysRegUsed(MCRegister PhysReg) = 0;
296
297private:
298 const RISCVSubtarget &Subtarget;
299};
300
301struct RISCVFormalArgHandler : public RISCVIncomingValueHandler {
302 RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
303 : RISCVIncomingValueHandler(B, MRI) {}
304
305 void markPhysRegUsed(MCRegister PhysReg) override {
306 MIRBuilder.getMRI()->addLiveIn(PhysReg);
307 MIRBuilder.getMBB().addLiveIn(PhysReg);
308 }
309};
310
311struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
312 RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
313 MachineInstrBuilder &MIB)
314 : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
315
316 void markPhysRegUsed(MCRegister PhysReg) override {
317 MIB.addDef(PhysReg, RegState::Implicit);
318 }
319
320 MachineInstrBuilder MIB;
321};
322
323} // namespace
324
327
328/// Return true if scalable vector with ScalarTy is legal for lowering.
330 const RISCVSubtarget &Subtarget) {
331 if (EltTy->isPointerTy())
332 return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true;
333 if (EltTy->isIntegerTy(1) || EltTy->isIntegerTy(8) ||
334 EltTy->isIntegerTy(16) || EltTy->isIntegerTy(32))
335 return true;
336 if (EltTy->isIntegerTy(64))
337 return Subtarget.hasVInstructionsI64();
338 if (EltTy->isHalfTy())
339 return Subtarget.hasVInstructionsF16Minimal();
340 if (EltTy->isBFloatTy())
341 return Subtarget.hasVInstructionsBF16Minimal();
342 if (EltTy->isFloatTy())
343 return Subtarget.hasVInstructionsF32();
344 if (EltTy->isDoubleTy())
345 return Subtarget.hasVInstructionsF64();
346 return false;
347}
348
349// TODO: Support all argument types.
350// TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall.
351static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
352 bool IsLowerArgs = false) {
353 if (T->isIntegerTy())
354 return true;
355 if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy() || T->isFP128Ty())
356 return true;
357 if (T->isPointerTy())
358 return true;
359 if (T->isArrayTy())
360 return isSupportedArgumentType(T->getArrayElementType(), Subtarget,
361 IsLowerArgs);
362 // TODO: Support fixed vector types.
363 if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() &&
364 T->isScalableTy() &&
365 isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
366 return true;
367 return false;
368}
369
370// TODO: Only integer, pointer and aggregate types are supported now.
371// TODO: Remove IsLowerRetVal argument by adding support for vectors in
372// lowerCall.
373static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
374 bool IsLowerRetVal = false) {
375 if (T->isIntegerTy() || T->isFloatingPointTy() || T->isPointerTy())
376 return true;
377
378 if (T->isArrayTy())
379 return isSupportedReturnType(T->getArrayElementType(), Subtarget);
380
381 if (T->isStructTy()) {
382 auto StructT = cast<StructType>(T);
383 for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i)
384 if (!isSupportedReturnType(StructT->getElementType(i), Subtarget))
385 return false;
386 return true;
387 }
388
389 if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() &&
390 T->isScalableTy() &&
391 isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
392 return true;
393
394 return false;
395}
396
398 const Value *Val, ArrayRef<Register> VRegs,
399 FunctionLoweringInfo &FLI) const {
400 assert(!Val == VRegs.empty() && "Return value without a vreg");
401 MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
402
403 if (!FLI.CanLowerReturn) {
404 insertSRetStores(MIRBuilder, Val->getType(), VRegs, FLI.DemoteRegister);
405 } else if (!VRegs.empty()) {
406 const RISCVSubtarget &Subtarget =
407 MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
408 if (!isSupportedReturnType(Val->getType(), Subtarget,
409 /*IsLowerRetVal=*/true))
410 return false;
411
412 MachineFunction &MF = MIRBuilder.getMF();
413 const DataLayout &DL = MF.getDataLayout();
414 const Function &F = MF.getFunction();
415 CallingConv::ID CC = F.getCallingConv();
416
417 ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
418 setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F);
419
420 SmallVector<ArgInfo, 4> SplitRetInfos;
421 splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC);
422
423 RISCVOutgoingValueAssigner Assigner(
425 /*IsRet=*/true);
426 RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
427 if (!determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
428 MIRBuilder, CC, F.isVarArg()))
429 return false;
430 }
431
432 MIRBuilder.insertInstr(Ret);
433 return true;
434}
435
437 CallingConv::ID CallConv,
439 bool IsVarArg) const {
441 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs,
442 MF.getFunction().getContext());
443
444 for (unsigned I = 0, E = Outs.size(); I < E; ++I) {
445 MVT VT = MVT::getVT(Outs[I].Ty);
446 if (CC_RISCV(I, VT, VT, CCValAssign::Full, Outs[I].Flags[0], CCInfo,
447 /*isRet=*/true, nullptr))
448 return false;
449 }
450 return true;
451}
452
453/// If there are varargs that were passed in a0-a7, the data in those registers
454/// must be copied to the varargs save area on the stack.
455void RISCVCallLowering::saveVarArgRegisters(
457 IncomingValueAssigner &Assigner, CCState &CCInfo) const {
458 MachineFunction &MF = MIRBuilder.getMF();
459 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
460 unsigned XLenInBytes = Subtarget.getXLen() / 8;
463 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
464 MachineFrameInfo &MFI = MF.getFrameInfo();
466
467 // Size of the vararg save area. For now, the varargs save area is either
468 // zero or large enough to hold a0-a7.
469 int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
470 int FI;
471
472 // If all registers are allocated, then all varargs must be passed on the
473 // stack and we don't need to save any argregs.
474 if (VarArgsSaveSize == 0) {
475 int VaArgOffset = Assigner.StackSize;
476 FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
477 } else {
478 int VaArgOffset = -VarArgsSaveSize;
479 FI = MFI.CreateFixedObject(VarArgsSaveSize, VaArgOffset, true);
480
481 // If saving an odd number of registers then create an extra stack slot to
482 // ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
483 // offsets to even-numbered registered remain 2*XLEN-aligned.
484 if (Idx % 2) {
485 MFI.CreateFixedObject(XLenInBytes,
486 VaArgOffset - static_cast<int>(XLenInBytes), true);
487 VarArgsSaveSize += XLenInBytes;
488 }
489
490 const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(),
491 Subtarget.getXLen());
492 const LLT sXLen = LLT::scalar(Subtarget.getXLen());
493
494 auto FIN = MIRBuilder.buildFrameIndex(p0, FI);
495 auto Offset = MIRBuilder.buildConstant(
496 MRI.createGenericVirtualRegister(sXLen), XLenInBytes);
497
498 // Copy the integer registers that may have been used for passing varargs
499 // to the vararg save area.
500 const MVT XLenVT = Subtarget.getXLenVT();
501 for (unsigned I = Idx; I < ArgRegs.size(); ++I) {
502 const Register VReg = MRI.createGenericVirtualRegister(sXLen);
503 Handler.assignValueToReg(
504 VReg, ArgRegs[I],
506 ArgRegs[I], XLenVT, CCValAssign::Full));
507 auto MPO =
508 MachinePointerInfo::getFixedStack(MF, FI, (I - Idx) * XLenInBytes);
509 MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
510 FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
511 FIN.getReg(0), Offset);
512 }
513 }
514
515 // Record the frame index of the first variable argument which is a value
516 // necessary to G_VASTART.
517 RVFI->setVarArgsFrameIndex(FI);
518 RVFI->setVarArgsSaveSize(VarArgsSaveSize);
519}
520
522 const Function &F,
524 FunctionLoweringInfo &FLI) const {
525 MachineFunction &MF = MIRBuilder.getMF();
526
527 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
528 for (auto &Arg : F.args()) {
529 if (!isSupportedArgumentType(Arg.getType(), Subtarget,
530 /*IsLowerArgs=*/true))
531 return false;
532 }
533
535 const DataLayout &DL = MF.getDataLayout();
536 CallingConv::ID CC = F.getCallingConv();
537
538 SmallVector<ArgInfo, 32> SplitArgInfos;
539
540 // Insert the hidden sret parameter if the return value won't fit in the
541 // return registers.
542 if (!FLI.CanLowerReturn)
543 insertSRetIncomingArgument(F, SplitArgInfos, FLI.DemoteRegister, MRI, DL);
544
545 unsigned Index = 0;
546 for (auto &Arg : F.args()) {
547 // Construct the ArgInfo object from destination register and argument type.
548 ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
549 setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F);
550
551 // Handle any required merging from split value types from physical
552 // registers into the desired VReg. ArgInfo objects are constructed
553 // correspondingly and appended to SplitArgInfos.
554 splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
555
556 ++Index;
557 }
558
559 RISCVIncomingValueAssigner Assigner(CC == CallingConv::Fast ? CC_RISCV_FastCC
560 : CC_RISCV,
561 /*IsRet=*/false);
562 RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
563
565 CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
566 if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) ||
567 !handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder))
568 return false;
569
570 if (F.isVarArg())
571 saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
572
573 return true;
574}
575
577 CallLoweringInfo &Info) const {
578 MachineFunction &MF = MIRBuilder.getMF();
579 const DataLayout &DL = MF.getDataLayout();
580 CallingConv::ID CC = Info.CallConv;
581
582 const RISCVSubtarget &Subtarget =
583 MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
584 for (auto &AInfo : Info.OrigArgs) {
585 if (!isSupportedArgumentType(AInfo.Ty, Subtarget))
586 return false;
587 if (AInfo.Flags[0].isByVal())
588 return false;
589 }
590
591 if (!Info.OrigRet.Ty->isVoidTy() &&
592 !isSupportedReturnType(Info.OrigRet.Ty, Subtarget))
593 return false;
594
595 MachineInstrBuilder CallSeqStart =
596 MIRBuilder.buildInstr(RISCV::ADJCALLSTACKDOWN);
597
598 SmallVector<ArgInfo, 32> SplitArgInfos;
599 for (auto &AInfo : Info.OrigArgs) {
600 // Handle any required unmerging of split value types from a given VReg into
601 // physical registers. ArgInfo objects are constructed correspondingly and
602 // appended to SplitArgInfos.
603 splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
604 }
605
606 // TODO: Support tail calls.
607 Info.IsTailCall = false;
608
609 // Select the recommended relocation type R_RISCV_CALL_PLT.
610 if (!Info.Callee.isReg())
611 Info.Callee.setTargetFlags(RISCVII::MO_CALL);
612
614 MIRBuilder
615 .buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
616 : RISCV::PseudoCALL)
617 .add(Info.Callee);
618 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
619 Call.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
620
621 RISCVOutgoingValueAssigner ArgAssigner(
623 /*IsRet=*/false);
624 RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
625 if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
626 MIRBuilder, CC, Info.IsVarArg))
627 return false;
628
629 MIRBuilder.insertInstr(Call);
630
631 CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0);
632 MIRBuilder.buildInstr(RISCV::ADJCALLSTACKUP)
633 .addImm(ArgAssigner.StackSize)
634 .addImm(0);
635
636 // If Callee is a reg, since it is used by a target specific
637 // instruction, it must have a register class matching the
638 // constraint of that instruction.
639 if (Call->getOperand(0).isReg())
641 *Subtarget.getInstrInfo(),
642 *Subtarget.getRegBankInfo(), *Call,
643 Call->getDesc(), Call->getOperand(0), 0);
644
645 if (Info.CanLowerReturn && !Info.OrigRet.Ty->isVoidTy()) {
646 SmallVector<ArgInfo, 4> SplitRetInfos;
647 splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
648
649 RISCVIncomingValueAssigner RetAssigner(
651 /*IsRet=*/true);
652 RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
653 if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
654 MIRBuilder, CC, Info.IsVarArg))
655 return false;
656 }
657
658 if (!Info.CanLowerReturn)
659 insertSRetLoads(MIRBuilder, Info.OrigRet.Ty, Info.OrigRet.Regs,
660 Info.DemoteRegister, Info.DemoteStackIndex);
661
662 return true;
663}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static bool isSupportedReturnType(Type *T)
static bool isSupportedArgumentType(Type *T)
static bool isLegalElementTypeForRVV(Type *EltTy, const RISCVSubtarget &Subtarget)
Return true if scalable vector with ScalarTy is legal for lowering.
This file describes how to lower LLVM calls to machine code calls.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
bool empty() const
empty - Check if the array is empty.
Definition ArrayRef.h:137
CCState - This class holds information needed while lowering arguments and return values.
MachineFunction & getMachineFunction() const
unsigned getFirstUnallocated(ArrayRef< MCPhysReg > Regs) const
getFirstUnallocated - Return the index of the first unallocated register in the set,...
uint64_t getStackSize() const
Returns the size of the currently allocated portion of the stack.
Register getLocReg() const
static CCValAssign getReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool needsCustom() const
int64_t getLocMemOffset() const
unsigned getValNo() const
void insertSRetLoads(MachineIRBuilder &MIRBuilder, Type *RetTy, ArrayRef< Register > VRegs, Register DemoteReg, int FI) const
Load the returned value from the stack into virtual registers in VRegs.
bool handleAssignments(ValueHandler &Handler, SmallVectorImpl< ArgInfo > &Args, CCState &CCState, SmallVectorImpl< CCValAssign > &ArgLocs, MachineIRBuilder &MIRBuilder, ArrayRef< Register > ThisReturnRegs={}) const
Use Handler to insert code to handle the argument/return values represented by Args.
void insertSRetIncomingArgument(const Function &F, SmallVectorImpl< ArgInfo > &SplitArgs, Register &DemoteReg, MachineRegisterInfo &MRI, const DataLayout &DL) const
Insert the hidden sret ArgInfo to the beginning of SplitArgs.
void splitToValueTypes(const ArgInfo &OrigArgInfo, SmallVectorImpl< ArgInfo > &SplitArgs, const DataLayout &DL, CallingConv::ID CallConv, SmallVectorImpl< TypeSize > *Offsets=nullptr) const
Break OrigArgInfo into one or more pieces the calling convention can process, returned in SplitArgs.
bool determineAndHandleAssignments(ValueHandler &Handler, ValueAssigner &Assigner, SmallVectorImpl< ArgInfo > &Args, MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv, bool IsVarArg, ArrayRef< Register > ThisReturnRegs={}) const
Invoke ValueAssigner::assignArg on each of the given Args and then use Handler to move them to the as...
void insertSRetStores(MachineIRBuilder &MIRBuilder, Type *RetTy, ArrayRef< Register > VRegs, Register DemoteReg) const
Store the return value given by VRegs into stack starting at the offset specified in DemoteReg.
bool determineAssignments(ValueAssigner &Assigner, SmallVectorImpl< ArgInfo > &Args, CCState &CCInfo) const
Analyze the argument list in Args, using Assigner to populate CCInfo.
CallLowering(const TargetLowering *TLI)
void setArgFlags(ArgInfo &Arg, unsigned OpIdx, const DataLayout &DL, const FuncInfoTy &FuncInfo) const
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
unsigned getAllocaAddrSpace() const
Definition DataLayout.h:246
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
Register DemoteRegister
DemoteRegister - if CanLowerReturn is false, DemoteRegister is a vreg allocated to hold a pointer to ...
bool CanLowerReturn
CanLowerReturn - true iff the function's return value can be lowered to registers.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:358
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
Machine Value Type.
bool isInteger() const
Return true if this is an integer or a vector integer type.
bool isScalableVector() const
Return true if this is a vector value type where the runtime length is machine dependent.
static LLVM_ABI MVT getVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Helper class to build MachineInstr.
MachineInstrBuilder insertInstr(MachineInstrBuilder MIB)
Insert an existing instruction at the insertion point.
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildFrameIndex(const DstOp &Res, int Idx)
Build and insert Res = G_FRAME_INDEX Idx.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildInstrNoInsert(unsigned Opcode)
Build but don't insert <empty> = Opcode <empty>.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val, ArrayRef< Register > VRegs, FunctionLoweringInfo &FLI) const override
This hook behaves as the extended lowerReturn function, but for targets that do not support swifterro...
bool canLowerReturn(MachineFunction &MF, CallingConv::ID CallConv, SmallVectorImpl< BaseArgInfo > &Outs, bool IsVarArg) const override
This hook must be implemented to check whether the return values described by Outs can fit into the r...
bool lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const override
This hook must be implemented to lower the given call instruction, including argument and return valu...
bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F, ArrayRef< ArrayRef< Register > > VRegs, FunctionLoweringInfo &FLI) const override
This hook must be implemented to lower the incoming (formal) arguments, described by VRegs,...
RISCVCallLowering(const RISCVTargetLowering &TLI)
RISCVMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private RISCV-...
RISCVABI::ABI getTargetABI() const
bool hasVInstructionsI64() const
bool hasVInstructionsF64() const
bool hasVInstructionsBF16Minimal() const
bool hasVInstructionsF16Minimal() const
unsigned getXLen() const
const RISCVRegisterBankInfo * getRegBankInfo() const override
bool hasVInstructions() const
const RISCVRegisterInfo * getRegisterInfo() const override
const RISCVInstrInfo * getInstrInfo() const override
bool hasVInstructionsF32() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:267
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
Definition Type.h:153
bool isBFloatTy() const
Return true if this is 'bfloat', a 16-bit bfloat type.
Definition Type.h:145
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Definition Type.h:142
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition Type.h:156
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:240
unsigned getNumOperands() const
Definition User.h:229
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
CallInst * Call
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
ArrayRef< MCPhysReg > getArgGPRs(const RISCVABI::ABI ABI)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
bool CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsRet, Type *OrigTy)
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
Definition Utils.cpp:56
bool RISCVCCAssignFn(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsRet, Type *OrigTy)
RISCVCCAssignFn - This target-specific function extends the default CCValAssign with additional infor...
bool CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsRet, Type *OrigTy)
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:201
LLVM_ABI Align inferAlignFromPtrInfo(MachineFunction &MF, const MachinePointerInfo &MPO)
Definition Utils.cpp:900
SmallVector< Register, 4 > Regs
SmallVector< ISD::ArgFlagsTy, 4 > Flags
Base class for ValueHandlers used for arguments coming into the current function, or for return value...
void assignValueToReg(Register ValVReg, Register PhysReg, const CCValAssign &VA, ISD::ArgFlagsTy Flags={}) override
Provides a default implementation for argument handling.
Base class for ValueHandlers used for arguments passed to a function call, or for return values.
static LLVM_ABI MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset, uint8_t ID=0)
Stack pointer relative access.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.