LLVM 22.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) override {
97 Register ExtReg = extendRegister(ValVReg, VA);
98 MIRBuilder.buildCopy(PhysReg, ExtReg);
99 MIB.addUse(PhysReg, RegState::Implicit);
100 }
101
102 unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
104 std::function<void()> *Thunk) override {
105 const CCValAssign &VA = VAs[0];
106 if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
107 (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
108 Register PhysReg = VA.getLocReg();
109
110 auto assignFunc = [=]() {
111 auto Trunc = MIRBuilder.buildAnyExt(LLT(VA.getLocVT()), Arg.Regs[0]);
112 MIRBuilder.buildCopy(PhysReg, Trunc);
113 MIB.addUse(PhysReg, RegState::Implicit);
114 };
115
116 if (Thunk) {
117 *Thunk = assignFunc;
118 return 1;
119 }
120
121 assignFunc();
122 return 1;
123 }
124
125 assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
126 const CCValAssign &VAHi = VAs[1];
127
128 assert(VAHi.needsCustom() && "Value doesn't need custom handling");
129 assert(VA.getValNo() == VAHi.getValNo() &&
130 "Values belong to different arguments");
131
132 assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
133 VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
134 "unexpected custom value");
135
136 Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
137 MRI.createGenericVirtualRegister(LLT::scalar(32))};
138 MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
139
140 if (VAHi.isMemLoc()) {
141 LLT MemTy(VAHi.getLocVT());
142
143 MachinePointerInfo MPO;
144 Register StackAddr = getStackAddress(
145 MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
146
147 assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
148 const_cast<CCValAssign &>(VAHi));
149 }
150
151 auto assignFunc = [=]() {
152 assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
153 if (VAHi.isRegLoc())
154 assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
155 };
156
157 if (Thunk) {
158 *Thunk = assignFunc;
159 return 2;
160 }
161
162 assignFunc();
163 return 2;
164 }
165
166private:
167 MachineInstrBuilder MIB;
168
169 // Cache the SP register vreg if we need it more than once in this call site.
170 Register SPReg;
171
172 const RISCVSubtarget &Subtarget;
173};
174
175struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
176private:
177 // The function used internally to assign args - we ignore the AssignFn stored
178 // by IncomingValueAssigner since RISC-V implements its CC using a custom
179 // function with a different signature.
180 RISCVCCAssignFn *RISCVAssignFn;
181
182 // Whether this is assigning args from a return.
183 bool IsRet;
184
185public:
186 RISCVIncomingValueAssigner(RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
187 : CallLowering::IncomingValueAssigner(nullptr),
188 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
189
190 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
191 CCValAssign::LocInfo LocInfo,
192 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
193 CCState &State) override {
194 MachineFunction &MF = State.getMachineFunction();
195
196 if (LocVT.isScalableVector())
197 MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall();
198
199 if (RISCVAssignFn(ValNo, ValVT, LocVT, LocInfo, Flags, State, IsRet,
200 Info.Ty))
201 return true;
202
203 StackSize = State.getStackSize();
204 return false;
205 }
206};
207
208struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
209 RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
210 : IncomingValueHandler(B, MRI),
211 Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
212
213 Register getStackAddress(uint64_t MemSize, int64_t Offset,
214 MachinePointerInfo &MPO,
215 ISD::ArgFlagsTy Flags) override {
216 MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
217
218 int FI = MFI.CreateFixedObject(MemSize, Offset, /*Immutable=*/true);
219 MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
220 return MIRBuilder.buildFrameIndex(LLT::pointer(0, Subtarget.getXLen()), FI)
221 .getReg(0);
222 }
223
224 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
225 const MachinePointerInfo &MPO,
226 const CCValAssign &VA) override {
227 MachineFunction &MF = MIRBuilder.getMF();
228 auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
229 inferAlignFromPtrInfo(MF, MPO));
230 MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
231 }
232
233 void assignValueToReg(Register ValVReg, Register PhysReg,
234 const CCValAssign &VA) override {
235 markPhysRegUsed(PhysReg);
236 IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
237 }
238
239 unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
241 std::function<void()> *Thunk) override {
242 const CCValAssign &VA = VAs[0];
243 if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
244 (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
245 Register PhysReg = VA.getLocReg();
246
247 markPhysRegUsed(PhysReg);
248
249 LLT LocTy(VA.getLocVT());
250 auto Copy = MIRBuilder.buildCopy(LocTy, PhysReg);
251
252 MIRBuilder.buildTrunc(Arg.Regs[0], Copy.getReg(0));
253 return 1;
254 }
255
256 assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
257 const CCValAssign &VAHi = VAs[1];
258
259 assert(VAHi.needsCustom() && "Value doesn't need custom handling");
260 assert(VA.getValNo() == VAHi.getValNo() &&
261 "Values belong to different arguments");
262
263 assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
264 VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
265 "unexpected custom value");
266
267 Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
268 MRI.createGenericVirtualRegister(LLT::scalar(32))};
269
270 if (VAHi.isMemLoc()) {
271 LLT MemTy(VAHi.getLocVT());
272
273 MachinePointerInfo MPO;
274 Register StackAddr = getStackAddress(
275 MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
276
277 assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
278 const_cast<CCValAssign &>(VAHi));
279 }
280
281 assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
282 if (VAHi.isRegLoc())
283 assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
284
285 MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
286
287 return 2;
288 }
289
290 /// How the physical register gets marked varies between formal
291 /// parameters (it's a basic-block live-in), and a call instruction
292 /// (it's an implicit-def of the BL).
293 virtual void markPhysRegUsed(MCRegister PhysReg) = 0;
294
295private:
296 const RISCVSubtarget &Subtarget;
297};
298
299struct RISCVFormalArgHandler : public RISCVIncomingValueHandler {
300 RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
301 : RISCVIncomingValueHandler(B, MRI) {}
302
303 void markPhysRegUsed(MCRegister PhysReg) override {
304 MIRBuilder.getMRI()->addLiveIn(PhysReg);
305 MIRBuilder.getMBB().addLiveIn(PhysReg);
306 }
307};
308
309struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
310 RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
311 MachineInstrBuilder &MIB)
312 : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
313
314 void markPhysRegUsed(MCRegister PhysReg) override {
315 MIB.addDef(PhysReg, RegState::Implicit);
316 }
317
318 MachineInstrBuilder MIB;
319};
320
321} // namespace
322
325
326/// Return true if scalable vector with ScalarTy is legal for lowering.
328 const RISCVSubtarget &Subtarget) {
329 if (EltTy->isPointerTy())
330 return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true;
331 if (EltTy->isIntegerTy(1) || EltTy->isIntegerTy(8) ||
332 EltTy->isIntegerTy(16) || EltTy->isIntegerTy(32))
333 return true;
334 if (EltTy->isIntegerTy(64))
335 return Subtarget.hasVInstructionsI64();
336 if (EltTy->isHalfTy())
337 return Subtarget.hasVInstructionsF16();
338 if (EltTy->isBFloatTy())
339 return Subtarget.hasVInstructionsBF16Minimal();
340 if (EltTy->isFloatTy())
341 return Subtarget.hasVInstructionsF32();
342 if (EltTy->isDoubleTy())
343 return Subtarget.hasVInstructionsF64();
344 return false;
345}
346
347// TODO: Support all argument types.
348// TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall.
349static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
350 bool IsLowerArgs = false) {
351 if (T->isIntegerTy())
352 return true;
353 if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy() || T->isFP128Ty())
354 return true;
355 if (T->isPointerTy())
356 return true;
357 if (T->isArrayTy())
358 return isSupportedArgumentType(T->getArrayElementType(), Subtarget,
359 IsLowerArgs);
360 // TODO: Support fixed vector types.
361 if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() &&
362 T->isScalableTy() &&
363 isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
364 return true;
365 return false;
366}
367
368// TODO: Only integer, pointer and aggregate types are supported now.
369// TODO: Remove IsLowerRetVal argument by adding support for vectors in
370// lowerCall.
371static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
372 bool IsLowerRetVal = false) {
373 if (T->isIntegerTy() || T->isFloatingPointTy() || T->isPointerTy())
374 return true;
375
376 if (T->isArrayTy())
377 return isSupportedReturnType(T->getArrayElementType(), Subtarget);
378
379 if (T->isStructTy()) {
380 auto StructT = cast<StructType>(T);
381 for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i)
382 if (!isSupportedReturnType(StructT->getElementType(i), Subtarget))
383 return false;
384 return true;
385 }
386
387 if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() &&
388 T->isScalableTy() &&
389 isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
390 return true;
391
392 return false;
393}
394
396 const Value *Val, ArrayRef<Register> VRegs,
397 FunctionLoweringInfo &FLI) const {
398 assert(!Val == VRegs.empty() && "Return value without a vreg");
399 MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
400
401 if (!FLI.CanLowerReturn) {
402 insertSRetStores(MIRBuilder, Val->getType(), VRegs, FLI.DemoteRegister);
403 } else if (!VRegs.empty()) {
404 const RISCVSubtarget &Subtarget =
405 MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
406 if (!isSupportedReturnType(Val->getType(), Subtarget,
407 /*IsLowerRetVal=*/true))
408 return false;
409
410 MachineFunction &MF = MIRBuilder.getMF();
411 const DataLayout &DL = MF.getDataLayout();
412 const Function &F = MF.getFunction();
413 CallingConv::ID CC = F.getCallingConv();
414
415 ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
416 setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F);
417
418 SmallVector<ArgInfo, 4> SplitRetInfos;
419 splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC);
420
421 RISCVOutgoingValueAssigner Assigner(
423 /*IsRet=*/true);
424 RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
425 if (!determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
426 MIRBuilder, CC, F.isVarArg()))
427 return false;
428 }
429
430 MIRBuilder.insertInstr(Ret);
431 return true;
432}
433
435 CallingConv::ID CallConv,
437 bool IsVarArg) const {
439 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs,
440 MF.getFunction().getContext());
441
442 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
443
444 std::optional<unsigned> FirstMaskArgument = std::nullopt;
445 // Preassign the first mask argument.
446 if (Subtarget.hasVInstructions()) {
447 for (const auto &ArgIdx : enumerate(Outs)) {
448 MVT ArgVT = MVT::getVT(ArgIdx.value().Ty);
449 if (ArgVT.isVector() && ArgVT.getVectorElementType() == MVT::i1)
450 FirstMaskArgument = ArgIdx.index();
451 }
452 }
453
454 for (unsigned I = 0, E = Outs.size(); I < E; ++I) {
455 MVT VT = MVT::getVT(Outs[I].Ty);
456 if (CC_RISCV(I, VT, VT, CCValAssign::Full, Outs[I].Flags[0], CCInfo,
457 /*isRet=*/true, nullptr))
458 return false;
459 }
460 return true;
461}
462
463/// If there are varargs that were passed in a0-a7, the data in those registers
464/// must be copied to the varargs save area on the stack.
465void RISCVCallLowering::saveVarArgRegisters(
467 IncomingValueAssigner &Assigner, CCState &CCInfo) const {
468 MachineFunction &MF = MIRBuilder.getMF();
469 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
470 unsigned XLenInBytes = Subtarget.getXLen() / 8;
473 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
474 MachineFrameInfo &MFI = MF.getFrameInfo();
476
477 // Size of the vararg save area. For now, the varargs save area is either
478 // zero or large enough to hold a0-a7.
479 int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
480 int FI;
481
482 // If all registers are allocated, then all varargs must be passed on the
483 // stack and we don't need to save any argregs.
484 if (VarArgsSaveSize == 0) {
485 int VaArgOffset = Assigner.StackSize;
486 FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
487 } else {
488 int VaArgOffset = -VarArgsSaveSize;
489 FI = MFI.CreateFixedObject(VarArgsSaveSize, VaArgOffset, true);
490
491 // If saving an odd number of registers then create an extra stack slot to
492 // ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
493 // offsets to even-numbered registered remain 2*XLEN-aligned.
494 if (Idx % 2) {
495 MFI.CreateFixedObject(XLenInBytes,
496 VaArgOffset - static_cast<int>(XLenInBytes), true);
497 VarArgsSaveSize += XLenInBytes;
498 }
499
500 const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(),
501 Subtarget.getXLen());
502 const LLT sXLen = LLT::scalar(Subtarget.getXLen());
503
504 auto FIN = MIRBuilder.buildFrameIndex(p0, FI);
505 auto Offset = MIRBuilder.buildConstant(
506 MRI.createGenericVirtualRegister(sXLen), XLenInBytes);
507
508 // Copy the integer registers that may have been used for passing varargs
509 // to the vararg save area.
510 const MVT XLenVT = Subtarget.getXLenVT();
511 for (unsigned I = Idx; I < ArgRegs.size(); ++I) {
512 const Register VReg = MRI.createGenericVirtualRegister(sXLen);
513 Handler.assignValueToReg(
514 VReg, ArgRegs[I],
516 ArgRegs[I], XLenVT, CCValAssign::Full));
517 auto MPO =
518 MachinePointerInfo::getFixedStack(MF, FI, (I - Idx) * XLenInBytes);
519 MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
520 FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
521 FIN.getReg(0), Offset);
522 }
523 }
524
525 // Record the frame index of the first variable argument which is a value
526 // necessary to G_VASTART.
527 RVFI->setVarArgsFrameIndex(FI);
528 RVFI->setVarArgsSaveSize(VarArgsSaveSize);
529}
530
532 const Function &F,
534 FunctionLoweringInfo &FLI) const {
535 MachineFunction &MF = MIRBuilder.getMF();
536
537 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
538 for (auto &Arg : F.args()) {
539 if (!isSupportedArgumentType(Arg.getType(), Subtarget,
540 /*IsLowerArgs=*/true))
541 return false;
542 }
543
545 const DataLayout &DL = MF.getDataLayout();
546 CallingConv::ID CC = F.getCallingConv();
547
548 SmallVector<ArgInfo, 32> SplitArgInfos;
549
550 // Insert the hidden sret parameter if the return value won't fit in the
551 // return registers.
552 if (!FLI.CanLowerReturn)
553 insertSRetIncomingArgument(F, SplitArgInfos, FLI.DemoteRegister, MRI, DL);
554
555 unsigned Index = 0;
556 for (auto &Arg : F.args()) {
557 // Construct the ArgInfo object from destination register and argument type.
558 ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
559 setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F);
560
561 // Handle any required merging from split value types from physical
562 // registers into the desired VReg. ArgInfo objects are constructed
563 // correspondingly and appended to SplitArgInfos.
564 splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
565
566 ++Index;
567 }
568
569 RISCVIncomingValueAssigner Assigner(CC == CallingConv::Fast ? CC_RISCV_FastCC
570 : CC_RISCV,
571 /*IsRet=*/false);
572 RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
573
575 CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
576 if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) ||
577 !handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder))
578 return false;
579
580 if (F.isVarArg())
581 saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
582
583 return true;
584}
585
587 CallLoweringInfo &Info) const {
588 MachineFunction &MF = MIRBuilder.getMF();
589 const DataLayout &DL = MF.getDataLayout();
590 CallingConv::ID CC = Info.CallConv;
591
592 const RISCVSubtarget &Subtarget =
593 MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
594 for (auto &AInfo : Info.OrigArgs) {
595 if (!isSupportedArgumentType(AInfo.Ty, Subtarget))
596 return false;
597 if (AInfo.Flags[0].isByVal())
598 return false;
599 }
600
601 if (!Info.OrigRet.Ty->isVoidTy() &&
602 !isSupportedReturnType(Info.OrigRet.Ty, Subtarget))
603 return false;
604
605 MachineInstrBuilder CallSeqStart =
606 MIRBuilder.buildInstr(RISCV::ADJCALLSTACKDOWN);
607
608 SmallVector<ArgInfo, 32> SplitArgInfos;
609 for (auto &AInfo : Info.OrigArgs) {
610 // Handle any required unmerging of split value types from a given VReg into
611 // physical registers. ArgInfo objects are constructed correspondingly and
612 // appended to SplitArgInfos.
613 splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
614 }
615
616 // TODO: Support tail calls.
617 Info.IsTailCall = false;
618
619 // Select the recommended relocation type R_RISCV_CALL_PLT.
620 if (!Info.Callee.isReg())
621 Info.Callee.setTargetFlags(RISCVII::MO_CALL);
622
624 MIRBuilder
625 .buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
626 : RISCV::PseudoCALL)
627 .add(Info.Callee);
628 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
629 Call.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
630
631 RISCVOutgoingValueAssigner ArgAssigner(
633 /*IsRet=*/false);
634 RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
635 if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
636 MIRBuilder, CC, Info.IsVarArg))
637 return false;
638
639 MIRBuilder.insertInstr(Call);
640
641 CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0);
642 MIRBuilder.buildInstr(RISCV::ADJCALLSTACKUP)
643 .addImm(ArgAssigner.StackSize)
644 .addImm(0);
645
646 // If Callee is a reg, since it is used by a target specific
647 // instruction, it must have a register class matching the
648 // constraint of that instruction.
649 if (Call->getOperand(0).isReg())
651 *Subtarget.getInstrInfo(),
652 *Subtarget.getRegBankInfo(), *Call,
653 Call->getDesc(), Call->getOperand(0), 0);
654
655 if (Info.CanLowerReturn && !Info.OrigRet.Ty->isVoidTy()) {
656 SmallVector<ArgInfo, 4> SplitRetInfos;
657 splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
658
659 RISCVIncomingValueAssigner RetAssigner(
661 /*IsRet=*/true);
662 RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
663 if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
664 MIRBuilder, CC, Info.IsVarArg))
665 return false;
666 }
667
668 if (!Info.CanLowerReturn)
669 insertSRetLoads(MIRBuilder, Info.OrigRet.Ty, Info.OrigRet.Regs,
670 Info.DemoteRegister, Info.DemoteStackIndex);
671
672 return true;
673}
unsigned const MachineRegisterInfo * MRI
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")
Analysis containing CSE Info
Definition CSEInfo.cpp:27
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
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:41
size_t size() const
size - Get the array size.
Definition ArrayRef.h:147
bool empty() const
empty - Check if the array is empty.
Definition ArrayRef.h:142
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 splitToValueTypes(const ArgInfo &OrigArgInfo, SmallVectorImpl< ArgInfo > &SplitArgs, const DataLayout &DL, CallingConv::ID CallConv, SmallVectorImpl< uint64_t > *Offsets=nullptr) const
Break OrigArgInfo into one or more pieces the calling convention can process, returned in SplitArgs.
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.
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:63
unsigned getAllocaAddrSpace() const
Definition DataLayout.h:230
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:359
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 isVector() const
Return true if this is a vector 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.
MVT getVectorElementType() const
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,...
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
unsigned getXLen() const
bool hasVInstructionsF16() 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:254
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)
@ Implicit
Not emitted register (e.g. carry, or temporary result).
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
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
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2452
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:565
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:212
LLVM_ABI Align inferAlignFromPtrInfo(MachineFunction &MF, const MachinePointerInfo &MPO)
Definition Utils.cpp:899
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) 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.